diff --git a/changelogs/fragments/fix-sa-key-create.yml b/changelogs/fragments/fix-sa-key-create.yml new file mode 100644 index 0000000..8f80405 --- /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 a34718d..11359b4 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) 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 aa65c31..ba66644 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 0000000..f7d2482 --- /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 0000000..6712476 --- /dev/null +++ b/tests/integration/targets/gcp_iam_service_account_key/tasks/service-account-keys.yml @@ -0,0 +1,140 @@ +--- + +# 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 + +- 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