From 56833b4be4214537139626967de9b8e814be6875 Mon Sep 17 00:00:00 2001 From: Benjamin Gandon Date: Tue, 9 Jan 2024 16:35:11 +0100 Subject: [PATCH 1/3] Fix 404 errors when creating key with misspelled service account --- changelogs/fragments/fix-sa-key-create.yml | 4 ++++ plugins/modules/gcp_iam_service_account_key.py | 6 +++++- 2 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 changelogs/fragments/fix-sa-key-create.yml diff --git a/changelogs/fragments/fix-sa-key-create.yml b/changelogs/fragments/fix-sa-key-create.yml new file mode 100644 index 000000000..8f80405b5 --- /dev/null +++ b/changelogs/fragments/fix-sa-key-create.yml @@ -0,0 +1,4 @@ +bugfixes: + - gcp_iam_service_account_key - properly raise an error with context when no + service account of the specified name exists, instead of failing with a + stacktrace. diff --git a/plugins/modules/gcp_iam_service_account_key.py b/plugins/modules/gcp_iam_service_account_key.py index a34718d71..11359b43b 100644 --- a/plugins/modules/gcp_iam_service_account_key.py +++ b/plugins/modules/gcp_iam_service_account_key.py @@ -255,7 +255,11 @@ def main(): def create(module): auth = GcpSession(module, 'iam') - json_content = return_if_object(module, auth.post(self_link(module), resource_to_request(module))) + response = auth.post(self_link(module), resource_to_request(module)) + if response.status_code == 404: + name = replace_resource_dict(module.params['service_account'], 'name') + module.fail_json(msg="No such Service Account: %s" % name) + json_content = return_if_object(module, response) with open(module.params['path'], 'w') as f: private_key_contents = to_native(base64.b64decode(json_content['privateKeyData'])) f.write(private_key_contents) From f404ab3a0067607a1bcaa1c6dfc9fd2e8666da30 Mon Sep 17 00:00:00 2001 From: Benjamin Gandon Date: Mon, 22 Jan 2024 17:43:31 +0100 Subject: [PATCH 2/3] Add basic test case for service account keys --- .../defaults/main.yml | 1 - .../tasks/main.yml | 3 + .../tasks/service-account-keys.yml | 102 ++++++++++++++++++ 3 files changed, 105 insertions(+), 1 deletion(-) create mode 100644 tests/integration/targets/gcp_iam_service_account_key/tasks/main.yml create mode 100644 tests/integration/targets/gcp_iam_service_account_key/tasks/service-account-keys.yml diff --git a/tests/integration/targets/gcp_iam_service_account_key/defaults/main.yml b/tests/integration/targets/gcp_iam_service_account_key/defaults/main.yml index aa65c31f5..ba66644fc 100644 --- a/tests/integration/targets/gcp_iam_service_account_key/defaults/main.yml +++ b/tests/integration/targets/gcp_iam_service_account_key/defaults/main.yml @@ -1,3 +1,2 @@ --- -# defaults file resource_name: "{{ resource_prefix }}" diff --git a/tests/integration/targets/gcp_iam_service_account_key/tasks/main.yml b/tests/integration/targets/gcp_iam_service_account_key/tasks/main.yml new file mode 100644 index 000000000..f7d24820d --- /dev/null +++ b/tests/integration/targets/gcp_iam_service_account_key/tasks/main.yml @@ -0,0 +1,3 @@ +--- +- name: Service Account Keys tests + ansible.builtin.include_tasks: service-account-keys.yml diff --git a/tests/integration/targets/gcp_iam_service_account_key/tasks/service-account-keys.yml b/tests/integration/targets/gcp_iam_service_account_key/tasks/service-account-keys.yml new file mode 100644 index 000000000..8f37ca79f --- /dev/null +++ b/tests/integration/targets/gcp_iam_service_account_key/tasks/service-account-keys.yml @@ -0,0 +1,102 @@ +--- + +# Pre-test setup +- name: Delete a service account + google.cloud.gcp_iam_service_account: + name: service-{{ resource_name.split("-")[-1] }}@{{ gcp_project }}.iam.gserviceaccount.com + display_name: Service Account used for Ansible integration tests + project: "{{ gcp_project }}" + auth_kind: "{{ gcp_cred_kind }}" + service_account_file: "{{ gcp_cred_file | default(omit) }}" + state: absent + +- name: Delete a service account key file + connection: local + ansible.builtin.file: + path: "{{ gcp_cred_file }}-temporary-service-account-key" + state: absent + +- name: Verify that service_account_key was deleted + connection: local + ansible.builtin.stat: + path: "{{ gcp_cred_file }}-temporary-service-account-key" + register: key_file + +- name: Verify that command succeeded + ansible.builtin.assert: + that: + - key_file.stat.exists == false + +- name: Create a service account + google.cloud.gcp_iam_service_account: + name: service-{{ resource_name.split("-")[-1] }}@{{ gcp_project }}.iam.gserviceaccount.com + display_name: Service Account used for Ansible integration tests + project: "{{ gcp_project }}" + auth_kind: "{{ gcp_cred_kind }}" + service_account_file: "{{ gcp_cred_file | default(omit) }}" + state: present + +#---------------------------------------------------------- + +- name: Create a service account key + google.cloud.gcp_iam_service_account_key: + service_account: + name: service-{{ resource_name.split("-")[-1] }}@{{ gcp_project }}.iam.gserviceaccount.com + private_key_type: TYPE_GOOGLE_CREDENTIALS_FILE + path: "{{ gcp_cred_file }}-temporary-service-account-key" + + project: "{{ gcp_project }}" + auth_kind: "{{ gcp_cred_kind }}" + service_account_file: "{{ gcp_cred_file | default(omit) }}" + state: present + register: result + +- name: Assert changed is true + ansible.builtin.assert: + that: + - result.changed == true + +- name: Verify that service_account_key was created + connection: local + ansible.builtin.stat: + path: "{{ gcp_cred_file }}-temporary-service-account-key" + register: key_file + +- name: Verify that command succeeded + ansible.builtin.assert: + that: + - key_file.stat.exists == true + - key_file.stat.isdir == false + - key_file.stat.size > 0 + +# ---------------------------------------------------------------------------- + +- name: Delete a service account key + google.cloud.gcp_iam_service_account_key: + service_account: + name: service-{{ resource_name.split("-")[-1] }}@{{ gcp_project }}.iam.gserviceaccount.com + private_key_type: TYPE_GOOGLE_CREDENTIALS_FILE + path: "{{ gcp_cred_file }}-temporary-service-account-key" + + project: "{{ gcp_project }}" + auth_kind: "{{ gcp_cred_kind }}" + service_account_file: "{{ gcp_cred_file | default(omit) }}" + state: absent + register: result + +- name: Assert changed is true + ansible.builtin.assert: + that: + - result.changed == true + +# ---------------------------------------------------------------------------- + +# Pre-test tear down +- name: Delete a service account + google.cloud.gcp_iam_service_account: + name: service-{{ resource_name.split("-")[-1] }}@{{ gcp_project }}.iam.gserviceaccount.com + display_name: Service Account used for Ansible integration tests + project: "{{ gcp_project }}" + auth_kind: "{{ gcp_cred_kind }}" + service_account_file: "{{ gcp_cred_file | default(omit) }}" + state: absent From 6d61b6699b21fedb92e614b6fc46ca24c59d0c00 Mon Sep 17 00:00:00 2001 From: Benjamin Gandon Date: Mon, 22 Jan 2024 17:44:42 +0100 Subject: [PATCH 3/3] Add test case when specified service account does not exist --- .../tasks/service-account-keys.yml | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/tests/integration/targets/gcp_iam_service_account_key/tasks/service-account-keys.yml b/tests/integration/targets/gcp_iam_service_account_key/tasks/service-account-keys.yml index 8f37ca79f..671247639 100644 --- a/tests/integration/targets/gcp_iam_service_account_key/tasks/service-account-keys.yml +++ b/tests/integration/targets/gcp_iam_service_account_key/tasks/service-account-keys.yml @@ -100,3 +100,41 @@ auth_kind: "{{ gcp_cred_kind }}" service_account_file: "{{ gcp_cred_file | default(omit) }}" state: absent + +- name: Delete a service account key file + connection: local + ansible.builtin.file: + path: "{{ gcp_cred_file }}-temporary-service-account-key" + state: absent + +#---------------------------------------------------------- + +- name: Create a service account key with icorrect service account name + google.cloud.gcp_iam_service_account_key: + service_account: + name: service-{{ resource_name.split("-")[-1] }} + private_key_type: TYPE_GOOGLE_CREDENTIALS_FILE + path: "{{ gcp_cred_file }}-temporary-service-account-key" + + project: "{{ gcp_project }}" + auth_kind: "{{ gcp_cred_kind }}" + service_account_file: "{{ gcp_cred_file | default(omit) }}" + state: present + register: result + failed_when: result.failed == false + +- name: Assert changed is true + ansible.builtin.assert: + that: + - result.msg is match('No such Service Account') + +- name: Verify that service_account_key was not created + connection: local + ansible.builtin.stat: + path: "{{ gcp_cred_file }}-temporary-service-account-key" + register: key_file + +- name: Verify that command succeeded + ansible.builtin.assert: + that: + - key_file.stat.exists == false