From 50d5d0a8d0d4b6254f4deabdb07ae064d12337b6 Mon Sep 17 00:00:00 2001 From: koralowiec Date: Tue, 27 Jun 2023 11:19:07 +0200 Subject: [PATCH 1/6] feat: add options for UID and GID --- README.md | 2 ++ defaults/main.yml | 3 +++ library/check_user.py | 44 +++++++++++++++++++++++++++++++++++ tasks/main.yml | 12 ++++++++++ tasks/user.yml | 26 +++++++++++++++++++++ tests/tasks/verify-common.yml | 6 +++++ vars/main.yml | 1 + 7 files changed, 94 insertions(+) create mode 100755 library/check_user.py create mode 100644 tasks/user.yml diff --git a/README.md b/README.md index 3765a4f..0b22b45 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,8 @@ Set up (the latest version of) [RStudio Connect](https://www.rstudio.com/product * `rstudio_connect_config`: A map of maps containing RStudio Connect configuration. Gets converted into Golang's configuration file (GCFG) and is writted on down to `rstudio-connect.gcfg`. See [default](./defaults/main.yml) for an example. * `rstudio_connect_config_override` [default: `""`]: If you know what you're doing, you can override whole `rstudio-connect.gcfg` config. * `rstudio_connect_license`: If specified, RStudio Connect will attempt to activate the supplied license key. +* `rstudio_connect_user_id` [default: `-1`]: Set user id of `rstudio-connect` user to the provided value after Connect installation. Helps with keeping a consistent UID. +* `rstudio_connect_group_id` [default: `-1`]: Set group id of `rstudio-connect` user to the provided value after Connect installation. Helps with keeping a consistent GID. * `rstudio_connect_python_executables` [default: `[]`]: List of paths to Python executables (e.g. `[/opt/python/3.10.6/bin/python3]`). * `python_versions` [default: `[]`]: List of Python versions, which were installed with [ansible-python-install role](https://github.com/Appsilon/ansible-python-install) (e.g. `[3.10.6, 3.7.8]`). Role will append Python executables information to the RStudio Connect configuration (using pattern: `/opt/python/x.x.x/bin/python3`). diff --git a/defaults/main.yml b/defaults/main.yml index e9c5705..32b7016 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -14,6 +14,9 @@ rstudio_connect_sso_saml_metadata_content_b64_encoded: "" rstudio_encryption_key: "" rstudio_connect_encryption_key_location: "/var/lib/rstudio-connect/db/secret.key" +rstudio_connect_user_id: -1 +rstudio_connect_group_id: -1 + rstudio_connect_config: HTTP: Listen: :{{ rstudio_connect_www_port }} diff --git a/library/check_user.py b/library/check_user.py new file mode 100755 index 0000000..7ed9597 --- /dev/null +++ b/library/check_user.py @@ -0,0 +1,44 @@ +#!/usr/bin/python + +from ansible.module_utils.basic import AnsibleModule +import subprocess + + +def main(): + module_args = dict( + name=dict(type='str', required=True), + uid=dict(type='int', required=True), + gid=dict(type='int', required=True), + ) + + module = AnsibleModule(argument_spec=module_args) + + name = module.params['name'] + uid = module.params['uid'] + gid = module.params['gid'] + + try: + command = ["getent", "passwd", name] + result = subprocess.run(command, capture_output=True, text=True) + stdout = result.stdout.strip() + + if result.returncode != 0: + module.fail_json(msg="User not found") + + uid_from_passwd = int(stdout.split(":")[2]) + gid_from_passwd = int(stdout.split(":")[3]) + + if uid_from_passwd != uid and gid_from_passwd != gid: + module.fail_json(msg="UID and GID don't match") + elif uid_from_passwd != uid: + module.fail_json(msg="UID doesn't match") + elif gid_from_passwd != gid: + module.fail_json(msg="GID doesn't match") + + module.exit_json(msg="UID is valid") + except Exception as e: + module.fail_json(msg=str(e)) + + +if __name__ == '__main__': + main() diff --git a/tasks/main.yml b/tasks/main.yml index a49d85b..26bea6f 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -37,6 +37,18 @@ tags: - rstudio-connect-configure-environment-file +- name: Include user tasks + ansible.builtin.include_tasks: user.yml + tags: + - configuration + - rstudio-connect + - rstudio-connect-configure + when: + - rstudio_connect_user_id is defined or rstudio_connect_group_id is defined + - rstudio_connect_user_id > 0 or rstudio_connect_group_id > 0 + tags: + - rstudio-connect-configure-user + - name: Include license tasks ansible.builtin.include_tasks: license.yml tags: diff --git a/tasks/user.yml b/tasks/user.yml new file mode 100644 index 0000000..17f743b --- /dev/null +++ b/tasks/user.yml @@ -0,0 +1,26 @@ +--- +- name: User | Stop rstudio-connect + ansible.builtin.service: + name: rstudio-connect + state: stopped + +- name: User | Change UID + ansible.builtin.user: + name: "{{ rstudio_connect_user }}" + uid: "{{ rstudio_connect_user_id }}" + when: + - rstudio_connect_user_id is defined + - rstudio_connect_user_id > 0 + +- name: User | Change GID + ansible.builtin.group: + name: "{{ rstudio_connect_user }}" + gid: "{{ rstudio_connect_group_id }}" + when: + - rstudio_connect_group_id is defined + - rstudio_connect_group_id > 0 + +- name: User | Start rstudio-connect + ansible.builtin.service: + name: rstudio-connect + state: started diff --git a/tests/tasks/verify-common.yml b/tests/tasks/verify-common.yml index 71dacef..8925741 100644 --- a/tests/tasks/verify-common.yml +++ b/tests/tasks/verify-common.yml @@ -6,3 +6,9 @@ status_code: - 200 - 402 + +- name: Verify (Common) | rstudio-connect uid and gid + check_user: + name: "rstudio-connect" + uid: 933 + gid: 944 diff --git a/vars/main.yml b/vars/main.yml index eb3f8f9..1ed0f8d 100644 --- a/vars/main.yml +++ b/vars/main.yml @@ -8,3 +8,4 @@ rstudio_connect_machine_map: i386: i386 x86_64: amd64 amd64: amd64 +rstudio_connect_user: "rstudio-connect" From 06e9688101c5eab70ed9c2a9ea437cd2c0a67bb4 Mon Sep 17 00:00:00 2001 From: koralowiec Date: Tue, 27 Jun 2023 11:44:03 +0200 Subject: [PATCH 2/6] chore: replace custom module with getent and assert --- library/check_user.py | 44 ----------------------------------- tests/tasks/verify-common.yml | 26 +++++++++++++++++---- 2 files changed, 21 insertions(+), 49 deletions(-) delete mode 100755 library/check_user.py diff --git a/library/check_user.py b/library/check_user.py deleted file mode 100755 index 7ed9597..0000000 --- a/library/check_user.py +++ /dev/null @@ -1,44 +0,0 @@ -#!/usr/bin/python - -from ansible.module_utils.basic import AnsibleModule -import subprocess - - -def main(): - module_args = dict( - name=dict(type='str', required=True), - uid=dict(type='int', required=True), - gid=dict(type='int', required=True), - ) - - module = AnsibleModule(argument_spec=module_args) - - name = module.params['name'] - uid = module.params['uid'] - gid = module.params['gid'] - - try: - command = ["getent", "passwd", name] - result = subprocess.run(command, capture_output=True, text=True) - stdout = result.stdout.strip() - - if result.returncode != 0: - module.fail_json(msg="User not found") - - uid_from_passwd = int(stdout.split(":")[2]) - gid_from_passwd = int(stdout.split(":")[3]) - - if uid_from_passwd != uid and gid_from_passwd != gid: - module.fail_json(msg="UID and GID don't match") - elif uid_from_passwd != uid: - module.fail_json(msg="UID doesn't match") - elif gid_from_passwd != gid: - module.fail_json(msg="GID doesn't match") - - module.exit_json(msg="UID is valid") - except Exception as e: - module.fail_json(msg=str(e)) - - -if __name__ == '__main__': - main() diff --git a/tests/tasks/verify-common.yml b/tests/tasks/verify-common.yml index 8925741..5000091 100644 --- a/tests/tasks/verify-common.yml +++ b/tests/tasks/verify-common.yml @@ -7,8 +7,24 @@ - 200 - 402 -- name: Verify (Common) | rstudio-connect uid and gid - check_user: - name: "rstudio-connect" - uid: 933 - gid: 944 +- name: Verify (Common) | Get rstudio-connect user info + ansible.builtin.getent: + database: passwd + key: "rstudio-connect" + +- name: Verify (Common) | Extract UID and GID + ansible.builtin.set_fact: + connect_uid: "{{ getent_passwd['rstudio-connect'][1] }}" + connect_gid: "{{ getent_passwd['rstudio-connect'][2] }}" + +- name: Verify (Common) | Check UID + ansible.builtin.assert: + that: + - (connect_uid | int) == 933 + fail_msg: "UID is not valid. UID from passwd {{ connect_uid }}" + +- name: Verify (Common) | Check GID + ansible.builtin.assert: + that: + - (connect_gid | int) == 944 + fail_msg: "GID is not valid. GID from passwd {{ connect_gid }}" From dbb69f7773636201706defd5b4a46cd57126aba0 Mon Sep 17 00:00:00 2001 From: koralowiec Date: Tue, 27 Jun 2023 11:53:55 +0200 Subject: [PATCH 3/6] fix: add steps to fix idempotence --- tasks/main.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tasks/main.yml b/tasks/main.yml index 26bea6f..a77fe5a 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -37,6 +37,16 @@ tags: - rstudio-connect-configure-environment-file +- name: Get rstudio-connect user info + ansible.builtin.getent: + database: passwd + key: "rstudio-connect" + +- name: Extract UID and GID + ansible.builtin.set_fact: + connect_uid: "{{ getent_passwd['rstudio-connect'][1] }}" + connect_gid: "{{ getent_passwd['rstudio-connect'][2] }}" + - name: Include user tasks ansible.builtin.include_tasks: user.yml tags: @@ -46,6 +56,7 @@ when: - rstudio_connect_user_id is defined or rstudio_connect_group_id is defined - rstudio_connect_user_id > 0 or rstudio_connect_group_id > 0 + - rstudio_connect_user_id != (connect_uid | int) or rstudio_connect_group_id != (connect_gid | int) tags: - rstudio-connect-configure-user From c44034fc9fae727fe73cfa0f1e13c8cdc60bcee6 Mon Sep 17 00:00:00 2001 From: koralowiec Date: Tue, 27 Jun 2023 12:27:50 +0200 Subject: [PATCH 4/6] chore: fix lint errors --- tasks/main.yml | 4 ---- tasks/user.yml | 8 ++++---- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/tasks/main.yml b/tasks/main.yml index a77fe5a..eec0076 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -49,10 +49,6 @@ - name: Include user tasks ansible.builtin.include_tasks: user.yml - tags: - - configuration - - rstudio-connect - - rstudio-connect-configure when: - rstudio_connect_user_id is defined or rstudio_connect_group_id is defined - rstudio_connect_user_id > 0 or rstudio_connect_group_id > 0 diff --git a/tasks/user.yml b/tasks/user.yml index 17f743b..3ca648a 100644 --- a/tasks/user.yml +++ b/tasks/user.yml @@ -7,16 +7,16 @@ - name: User | Change UID ansible.builtin.user: name: "{{ rstudio_connect_user }}" - uid: "{{ rstudio_connect_user_id }}" - when: + uid: "{{ rstudio_connect_user_id }}" + when: - rstudio_connect_user_id is defined - rstudio_connect_user_id > 0 - name: User | Change GID ansible.builtin.group: name: "{{ rstudio_connect_user }}" - gid: "{{ rstudio_connect_group_id }}" - when: + gid: "{{ rstudio_connect_group_id }}" + when: - rstudio_connect_group_id is defined - rstudio_connect_group_id > 0 From 63870d0def3bf8a83303ba0377382f29b70d5dc3 Mon Sep 17 00:00:00 2001 From: koralowiec Date: Wed, 28 Jun 2023 15:16:24 +0200 Subject: [PATCH 5/6] feat: remove redundant default UID, GID variables --- defaults/main.yml | 4 ++-- tasks/main.yml | 7 +++---- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/defaults/main.yml b/defaults/main.yml index 32b7016..d8c5690 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -14,8 +14,8 @@ rstudio_connect_sso_saml_metadata_content_b64_encoded: "" rstudio_encryption_key: "" rstudio_connect_encryption_key_location: "/var/lib/rstudio-connect/db/secret.key" -rstudio_connect_user_id: -1 -rstudio_connect_group_id: -1 +# rstudio_connect_user_id: 933 +# rstudio_connect_group_id: 933 rstudio_connect_config: HTTP: diff --git a/tasks/main.yml b/tasks/main.yml index eec0076..6f55f9f 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -49,10 +49,9 @@ - name: Include user tasks ansible.builtin.include_tasks: user.yml - when: - - rstudio_connect_user_id is defined or rstudio_connect_group_id is defined - - rstudio_connect_user_id > 0 or rstudio_connect_group_id > 0 - - rstudio_connect_user_id != (connect_uid | int) or rstudio_connect_group_id != (connect_gid | int) + when: > + (rstudio_connect_user_id is defined and rstudio_connect_user_id != (connect_uid | int)) + or (rstudio_connect_group_id is defined and rstudio_connect_group_id != (connect_gid | int)) tags: - rstudio-connect-configure-user From daac9113528e7d61e2a168abadff26b7149734e0 Mon Sep 17 00:00:00 2001 From: koralowiec Date: Tue, 18 Jul 2023 14:51:52 +0200 Subject: [PATCH 6/6] chore: update README --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 0b22b45..11ae99a 100644 --- a/README.md +++ b/README.md @@ -18,8 +18,8 @@ Set up (the latest version of) [RStudio Connect](https://www.rstudio.com/product * `rstudio_connect_config`: A map of maps containing RStudio Connect configuration. Gets converted into Golang's configuration file (GCFG) and is writted on down to `rstudio-connect.gcfg`. See [default](./defaults/main.yml) for an example. * `rstudio_connect_config_override` [default: `""`]: If you know what you're doing, you can override whole `rstudio-connect.gcfg` config. * `rstudio_connect_license`: If specified, RStudio Connect will attempt to activate the supplied license key. -* `rstudio_connect_user_id` [default: `-1`]: Set user id of `rstudio-connect` user to the provided value after Connect installation. Helps with keeping a consistent UID. -* `rstudio_connect_group_id` [default: `-1`]: Set group id of `rstudio-connect` user to the provided value after Connect installation. Helps with keeping a consistent GID. +* `rstudio_connect_user_id` [default: undefined]: Set user id of `rstudio-connect` user to the provided value after Connect installation. Helps with keeping a consistent UID. +* `rstudio_connect_group_id` [default: undefined]: Set group id of `rstudio-connect` user to the provided value after Connect installation. Helps with keeping a consistent GID. * `rstudio_connect_python_executables` [default: `[]`]: List of paths to Python executables (e.g. `[/opt/python/3.10.6/bin/python3]`). * `python_versions` [default: `[]`]: List of Python versions, which were installed with [ansible-python-install role](https://github.com/Appsilon/ansible-python-install) (e.g. `[3.10.6, 3.7.8]`). Role will append Python executables information to the RStudio Connect configuration (using pattern: `/opt/python/x.x.x/bin/python3`).