diff --git a/README.md b/README.md index 39c586b..598d9b4 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # Equinix Ansible Collection -[![Ansible Galaxy](https://img.shields.io/badge/galaxy-equinix.cloud-660198.svg?style=flat)](https://galaxy.ansible.com/equinix/cloud/) +[![Ansible Galaxy](https://img.shields.io/badge/galaxy-equinix.cloud-660198.svg?style=flat)](https://galaxy.ansible.com/equinix/cloud/) ![Tests](https://img.shields.io/github/actions/workflow/status/equinix-labs/ansible-collection-equinix/integration-tests.yml?branch=main) The Ansible Collection Equinix contains various plugins for managing Equinix services. @@ -26,11 +26,14 @@ Name | Description | [equinix.cloud.metal_ip_assignment](./docs/modules/metal_ip_assignment.md)|Manage Equinix Metal IP assignments| [equinix.cloud.metal_organization](./docs/modules/metal_organization.md)|Lookup a single organization by ID in Equinix Metal| [equinix.cloud.metal_project](./docs/modules/metal_project.md)|Manage Projects in Equinix Metal| +[equinix.cloud.metal_project_ssh_key](./docs/modules/metal_project_ssh_key.md)|Manage a project ssh key in Equinix Metal| [equinix.cloud.metal_reserved_ip_block](./docs/modules/metal_reserved_ip_block.md)|Create/delete blocks of reserved IP addresses in a project.| [equinix.cloud.metal_ssh_key](./docs/modules/metal_ssh_key.md)|Manage personal SSH keys in Equinix Metal| +[equinix.cloud.metal_project_ssh_key](./docs/modules/metal_project_ssh_key.md)|Manage project SSH keys in Equinix Metal| [equinix.cloud.metal_vlan](./docs/modules/metal_vlan.md)|Manage a VLAN resource in Equinix Metal| + ### Info Modules Modules for retrieving information about existing Equinix infrastructure. @@ -45,7 +48,10 @@ Name | Description | [equinix.cloud.metal_operating_system_info](./docs/modules/metal_operating_system_info.md)|Gather information about Operating Systems available for devices in Equinix Metal| [equinix.cloud.metal_organization_info](./docs/modules/metal_organization_info.md)|Gather information about Equinix Metal organizations| [equinix.cloud.metal_project_info](./docs/modules/metal_project_info.md)|Gather information about Equinix Metal projects| +[equinix.cloud.metal_project_ssh_key_info](./docs/modules/metal_project_ssh_key_info.md)|Gather project SSH keys.| [equinix.cloud.metal_reserved_ip_block_info](./docs/modules/metal_reserved_ip_block_info.md)|Gather list of reserved IP blocks| +[equinix.cloud.metal_ssh_key_info](./docs/modules/metal_ssh_key_info.md)|Gather personal SSH keys|list project SSH keys +[equinix.cloud.metal_project_ssh_key_info](./docs/modules/metal_project_ssh_key_info.md)|Gather project SSH keys| [equinix.cloud.metal_ssh_key_info](./docs/modules/metal_ssh_key_info.md)|Gather personal SSH keys| [equinix.cloud.metal_vlan_info](./docs/modules/metal_vlan_info.md)|Gather VLANs.| diff --git a/docs/modules/metal_project_ssh_key.md b/docs/modules/metal_project_ssh_key.md new file mode 100644 index 0000000..ed47b60 --- /dev/null +++ b/docs/modules/metal_project_ssh_key.md @@ -0,0 +1,73 @@ +# metal_project_ssh_key + +Manage project ssh key in Equinix Metal. Read more about personal and project SSH keys in [Equinix Metal documentation](https://deploy.equinix.com/developers/docs/metal/accounts/ssh-keys/#personal-keys-vs-project-keys). You can use *id* or *label* to lookup a project SSH key. If you want to create new resource, you must provide *name*, *public_key* and *project_id*. + + +- [Examples](#examples) +- [Parameters](#parameters) +- [Return Values](#return-values) + +## Examples + +```yaml +- name: Create new project project ssh_key + hosts: localhost + tasks: + - equinix.cloud.metal_project_ssh_key: + name: "test_key" + public_key: "ssh-dss AAAAB3NzaC1kc3MAAACBAPLEVntPO3L7VUbEwWZ2ErkQJ3KJ8o9kFXJrPcpvVfdNag4jIhQDqbtAUgUy6BclhhbfH9l5nlGTprrpEFkxm/GL91qJUX6xrPkDMjMqx2wSKa4YraReOrCOfkqqEkC3o3G/gYSuvTzLgp2rmPiflypftZyzNM4JZT8jDwFGotJhAAAAFQDPk43bayONtUxjkAcOf+6zP1qb6QAAAIBZHHH0tIlth5ot+Xa/EYuB/M4qh77EkrWUbER0Kki7suskw/ffdKQ0y/v+ZhoAHtBU7BeE3HmP98Vrha1i4cOU+A7DCqV+lK/a+5LoEpua0M2M+VzNSGluYuV4qGpAOxNh3mxUi2R7yXxheN1oks1ROJ/bqkF4BJQXU9Nv49GkZgAAAIByWcsFeOitvzyDaNJOZzEHv9fqGuj0L3maRVWb6O47HGzlMzniIy8WjL2dfgm2/ek+NxVR/yFnYTKDPr6+0uqSD/cb4eHaFbIj7v+k7H8hA1Ioz+duJ1ONAjn6KwneXxOXu15bYIR49P7Go0s9jCdSAP/r9NE5TnE3yiRiQzgEzw== tomk@node" + project_id: "local.project_id" + +``` + +```yaml +- name: Remove project ssh_key by id + hosts: localhost + tasks: + - equinix.cloud.metal_project_ssh_key: + id: "eef49903-7a09-4ca1-af67-4087c29ab5b6" + state: absent + +``` + + + + + + + + + + +## Parameters + +| Field | Type | Required | Description | +|-----------|------|----------|------------------------------------------------------------------------------| +| `id` |
`str`
|
Optional
| UUID of the ssh_key. | +| `name` |
`str`
|
Optional
| The name of the ssh_key. **(Updatable)** | +| `public_key` |
`str`
|
Optional
| The public key of the project ssh_key. **(Updatable)** | +| `project_id` |
`str`
|
Optional
| The ID of parent project. **(Updatable)** | + + + + + + +## Return Values + +- `metal_project_ssh_key` - The module object + + - Sample Response: + ```json + + { + "fingerprint": "98:9c:35:ed:f9:75:5b:52:e2:70:50:22:ea:77:5b:b6", + "id": "eef49903-7a09-4ca1-af67-4087c29ab5b6", + "public_key": "ssh-dss AAAAB3NzaC1kc3MAAACBAPLEVntPO3L7VUbEwWZ2ErkQJ3KJ8o9kFXJrPcpvVfdNag4jIhQDqbtAUgUy6BclhhbfH9l5nlGTprrpEFkxm/GL91qJUX6xrPkDMjMqx2wSKa4YraReOrCOfkqqEkC3o3G/gYSuvTzLgp2rmPiflypftZyzNM4JZT8jDwFGotJhAAAAFQDPk43bayONtUxjkAcOf+6zP1qb6QAAAIBZHHH0tIlth5ot+Xa/EYuB/M4qh77EkrWUbER0Kki7suskw/ffdKQ0y/v+ZhoAHtBU7BeE3HmP98Vrha1i4cOU+A7DCqV+lK/a+5LoEpua0M2M+VzNSGluYuV4qGpAOxNh3mxUi2R7yXxheN1oks1ROJ/bqkF4BJQXU9Nv49GkZgAAAIByWcsFeOitvzyDaNJOZzEHv9fqGuj0L3maRVWb6O47HGzlMzniIy8WjL2dfgm2/ek+NxVR/yFnYTKDPr6+0uqSD/cb4eHaFbIj7v+k7H8hA1Ioz+duJ1ONAjn6KwneXxOXu15bYIR49P7Go0s9jCdSAP/r9NE5TnE3yiRiQzgEzw== tomk@xps", + "name": "test_key", + "project_id": "local.project_id" + } + + ``` + + diff --git a/docs/modules/metal_project_ssh_key_info.md b/docs/modules/metal_project_ssh_key_info.md new file mode 100644 index 0000000..10bd318 --- /dev/null +++ b/docs/modules/metal_project_ssh_key_info.md @@ -0,0 +1,73 @@ +# metal_project_ssh_key_info + +Gather project SSH keys. Read more about project vs project SSH keys in [Equinix Metal documentation](https://metal.equinix.com/developers/docs/accounts/ssh-keys/#personal-keys-vs-project-keys). + + +- [Examples](#examples) +- [Parameters](#parameters) +- [Return Values](#return-values) + +## Examples + +```yaml + +- set_fact: + desired_name_substring: "tkarasek" + +- name: list project ssh keys + equinix.cloud.metal_project_ssh_key_info: + register: ssh_keys_listed + +- name: filter found ssh keys + set_fact: + both_ssh_keys_listed: "{{ ssh_keys_listed.resources | selectattr('name', 'match', desired_name_substring) }}" + +``` + + + + + + + + + + +## Parameters + +| Field | Type | Required | Description | +|-----------|------|----------|------------------------------------------------------------------------------| +| `name` |
`str`
|
**Required**
| Name to search for in existing keys. | + + + + + + +## Return Values + +- `resources` - Found resources + + - Sample Response: + ```json + + [ + { + "fingerprint": "70:c1:73:8b:3f:2f:a4:18:ea:4d:79:13:52:7b:c4:3e", + "id": "6edfcbc2-17e5-4221-9eac-2f40dbe60daf", + "key": "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAt5gwVMhwcCrxyxpMEKwiS0xgit3PIIEgVXt6SQHc8eONq0mYJJ5TOBNTnySqXd9RtSv/Jbf5Aq9BzBGWeoZ6sZfKwh984Ip35StJtjXtyIOlY3skovndtupBIwlGXgX/WQzyLr+G/+Yu9/nhdxQi801PDZnDvKoeomM0rMD29nV+m0ud+GrtsAt6VFul2PxqpypZ1TYviyED6IKo7rgQsQDkE9QHcNdfT1FZWiJbfP7o8TIurQJcAXg+MtLoc8rKKcxFMeZ9FSydgtTC7nP1h558RtECGWiUgaBPI7TpBmcdMtbEfAiBoGT17GWnT8qmy2u5xnEKPD9Qft4w4fjfpw==", + "label": "tkarasek", + "project_id": local.project_id + }, + { + "fingerprint": "ba:70:af:b3:0f:0e:7f:e5:eb:97:e2:27:b1:f5:6f:94", + "id": "d00c596d-b42a-44a7-ac14-e299b85e73d3", + "key": "ssh-dss AAAAB3NzaC1kc3MAAACBAOpXVtmc0Bla98bt0o5/Zj7sb4mHIukgVFZu7F32R3VK1cEKB4rEE8uS0oLS/qMRLue45TWVJwRMYGlPjt3p/VyraelxoyJZLuITIsqa5hBc9w0oTlB5Bmbkn16umW96WCaWEoq/aitpocbRChTiP5biI6FyQTQlIHDaYzBDOi11AAAAFQDUXy7cmuzphDpJSYYTiudiUhVokwAAAIEAyUQ9m8qL/1HPkFe6jbXAvtSSmW27F4c+G2xR5HizaHQzXgBOxPcsOsY17KTU+Ddbg+OF9soWNwSpm9pyVjVmNGqH3S8R1pwvuJF/O2Asy1m6wpWhbPw8JdEBW7WHoptBpfuzJoS2LOzJUEmUu4Eb+xS237KG1d1BVny/49KAoH0AAACBAJKBSsm9Xey0fUN6vYtTQgoYeGxxj/LqAIAOs/TpCxZDntly860y/SzHYai8x48k4t7whENY1CJ41fpMcPlz8xIsrNP3326Wbr0ExwOIvJKAVN1YLYqF8NXWzaVrjo5WbSeI8PiWTYemvLAujVxZssIrApTZBhp55nnwge6K1zTG tomk@air", + "label": "ansible-integration-test-ssh_key-ztiapihf-ssh_key1_renamed", + "project_id": local.project_id + } + ] + + ``` + + diff --git a/plugins/module_utils/metal/api_routes.py b/plugins/module_utils/metal/api_routes.py index 1b1d1cb..48b302d 100644 --- a/plugins/module_utils/metal/api_routes.py +++ b/plugins/module_utils/metal/api_routes.py @@ -91,6 +91,10 @@ def get_routes(mpc): ('metal_ssh_key', action.LIST): spec_types.Specs( equinix_metal.SSHKeysApi(mpc).find_ssh_keys, ), + ('metal_project_ssh_key', action.LIST): spec_types.Specs( + equinix_metal.SSHKeysApi(mpc).find_project_ssh_keys, + {'id': 'project_id'} + ), ('metal_organization', action.LIST): spec_types.Specs( equinix_metal.OrganizationsApi(mpc).find_organizations, {'personal': 'personal', 'with_projects': 'with_projects'}, @@ -130,7 +134,6 @@ def get_routes(mpc): equinix_metal.VLANsApi(mpc).delete_virtual_network, ), - # CREATORS ('metal_device', action.CREATE): spec_types.Specs( equinix_metal.DevicesApi(mpc).create_device, @@ -162,6 +165,11 @@ def get_routes(mpc): {}, equinix_metal.SSHKeyCreateInput, ), + ('metal_project_ssh_key', action.CREATE): spec_types.Specs( + equinix_metal.SSHKeysApi(mpc).create_project_ssh_key, + {'id': 'project_id'}, + equinix_metal.SSHKeyCreateInput, + ), ('metal_vlan', action.CREATE): spec_types.Specs( equinix_metal.VLANsApi(mpc).create_virtual_network, {'id': 'project_id'}, diff --git a/plugins/modules/metal_project_ssh_key.py b/plugins/modules/metal_project_ssh_key.py new file mode 100644 index 0000000..8f89673 --- /dev/null +++ b/plugins/modules/metal_project_ssh_key.py @@ -0,0 +1,213 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +# DOCUMENTATION, EXAMPLES, and RETURN are generated by +# ansible_specdoc. Do not edit them directly. + +DOCUMENTATION = ''' +author: Equinix DevRel Team (@equinix) +description: Manage project ssh key in Equinix Metal. Read more about personal and + project SSH keys in [Equinix Metal documentation](https://deploy.equinix.com/developers/docs/metal/accounts/ssh-keys/#personal-keys-vs-project-keys). + You can use *id* or *label* to lookup a project SSH key. If you want to create new + resource, you must provide *name*, *public_key* and *project_id*. +module: metal_project_ssh_key +notes: [] +options: + id: + description: + - UUID of the ssh_key. + required: false + type: str + name: + description: + - The name of the ssh_key. + required: false + type: str + project_id: + description: + - The ID of parent project. + required: false + type: str + public_key: + description: + - The public key of the project ssh_key. + required: false + type: str +requirements: null +short_description: Manage a project ssh key in Equinix Metal +''' +EXAMPLES = ''' +- name: Create new project project ssh_key + hosts: localhost + tasks: + - equinix.cloud.metal_project_ssh_key: + name: test_key + public_key: ssh-dss AAAAB3NzaC1kc3MAAACBAPLEVntPO3L7VUbEwWZ2ErkQJ3KJ8o9kFXJrPcpvVfdNag4jIhQDqbtAUgUy6BclhhbfH9l5nlGTprrpEFkxm/GL91qJUX6xrPkDMjMqx2wSKa4YraReOrCOfkqqEkC3o3G/gYSuvTzLgp2rmPiflypftZyzNM4JZT8jDwFGotJhAAAAFQDPk43bayONtUxjkAcOf+6zP1qb6QAAAIBZHHH0tIlth5ot+Xa/EYuB/M4qh77EkrWUbER0Kki7suskw/ffdKQ0y/v+ZhoAHtBU7BeE3HmP98Vrha1i4cOU+A7DCqV+lK/a+5LoEpua0M2M+VzNSGluYuV4qGpAOxNh3mxUi2R7yXxheN1oks1ROJ/bqkF4BJQXU9Nv49GkZgAAAIByWcsFeOitvzyDaNJOZzEHv9fqGuj0L3maRVWb6O47HGzlMzniIy8WjL2dfgm2/ek+NxVR/yFnYTKDPr6+0uqSD/cb4eHaFbIj7v+k7H8hA1Ioz+duJ1ONAjn6KwneXxOXu15bYIR49P7Go0s9jCdSAP/r9NE5TnE3yiRiQzgEzw== + tomk@node + project_id: b8c6c653-3c96-446e-987e-9c4d12f25353 +- name: Remove project ssh_key by id + hosts: localhost + tasks: + - equinix.cloud.metal_project_ssh_key: + id: eef49903-7a09-4ca1-af67-4087c29ab5b6 + state: absent +''' +RETURN = ''' +metal_project_ssh_key: + description: The module object + returned: always + sample: + - "\n{\n \"fingerprint\": \"98:9c:35:ed:f9:75:5b:52:e2:70:50:22:ea:77:5b:b6\",\n\ + \ \"id\": \"eef49903-7a09-4ca1-af67-4087c29ab5b6\",\n \"public_key\": \"ssh-dss\ + \ AAAAB3NzaC1kc3MAAACBAPLEVntPO3L7VUbEwWZ2ErkQJ3KJ8o9kFXJrPcpvVfdNag4jIhQDqbtAUgUy6BclhhbfH9l5nlGTprrpEFkxm/GL91qJUX6xrPkDMjMqx2wSKa4YraReOrCOfkqqEkC3o3G/gYSuvTzLgp2rmPiflypftZyzNM4JZT8jDwFGotJhAAAAFQDPk43bayONtUxjkAcOf+6zP1qb6QAAAIBZHHH0tIlth5ot+Xa/EYuB/M4qh77EkrWUbER0Kki7suskw/ffdKQ0y/v+ZhoAHtBU7BeE3HmP98Vrha1i4cOU+A7DCqV+lK/a+5LoEpua0M2M+VzNSGluYuV4qGpAOxNh3mxUi2R7yXxheN1oks1ROJ/bqkF4BJQXU9Nv49GkZgAAAIByWcsFeOitvzyDaNJOZzEHv9fqGuj0L3maRVWb6O47HGzlMzniIy8WjL2dfgm2/ek+NxVR/yFnYTKDPr6+0uqSD/cb4eHaFbIj7v+k7H8hA1Ioz+duJ1ONAjn6KwneXxOXu15bYIR49P7Go0s9jCdSAP/r9NE5TnE3yiRiQzgEzw==\ + \ tomk@xps\",\n \"name\": \"test_key\",\n \"project_id\": \"b8c6c653-3c96-446e-987e-9c4d12f25353\"\ + \n}\n" + type: dict +''' + +# End of generated documentation + +from ansible.module_utils._text import to_native +from ansible_specdoc.objects import ( + SpecField, + FieldType, + SpecReturnValue, +) +import traceback + +from ansible_collections.equinix.cloud.plugins.module_utils.equinix import ( + EquinixModule, + get_diff, + getSpecDocMeta, +) + + +MODULE_NAME = "metal_project_ssh_key" +METAL_SSH_KEY = "metal_ssh_key" + +module_spec = dict( + id=SpecField( + type=FieldType.string, + description=["UUID of the ssh_key."], + ), + label=SpecField( + type=FieldType.string, + description=["The name of the ssh_key."], + editable=True, + ), + key=SpecField( + type=FieldType.string, + description=["The public key of the project ssh_key."], + editable=True, + ), + project_id=SpecField( + type=FieldType.string, + description=["The ID of parent project."], + editable=True, + ), +) + + +specdoc_examples = [ + """ +- name: Create new project project ssh_key + hosts: localhost + tasks: + - equinix.cloud.metal_project_ssh_key: + label: "test_key" + key: "ssh-dss AAAAB3NzaC1kc3MAAACBAPLEVntPO3L7VUbEwWZ2ErkQJ3KJ8o9kFXJrPcpvVfdNag4jIhQDqbtAUgUy6BclhhbfH9l5nlGTprrpEFkxm/GL91qJUX6xrPkDMjMqx2wSKa4YraReOrCOfkqqEkC3o3G/gYSuvTzLgp2rmPiflypftZyzNM4JZT8jDwFGotJhAAAAFQDPk43bayONtUxjkAcOf+6zP1qb6QAAAIBZHHH0tIlth5ot+Xa/EYuB/M4qh77EkrWUbER0Kki7suskw/ffdKQ0y/v+ZhoAHtBU7BeE3HmP98Vrha1i4cOU+A7DCqV+lK/a+5LoEpua0M2M+VzNSGluYuV4qGpAOxNh3mxUi2R7yXxheN1oks1ROJ/bqkF4BJQXU9Nv49GkZgAAAIByWcsFeOitvzyDaNJOZzEHv9fqGuj0L3maRVWb6O47HGzlMzniIy8WjL2dfgm2/ek+NxVR/yFnYTKDPr6+0uqSD/cb4eHaFbIj7v+k7H8hA1Ioz+duJ1ONAjn6KwneXxOXu15bYIR49P7Go0s9jCdSAP/r9NE5TnE3yiRiQzgEzw== tomk@node" + project_id: "b8c6c653-3c96-446e-987e-9c4d12f25353" +""", + """ +- name: Remove project ssh_key by id + hosts: localhost + tasks: + - equinix.cloud.metal_project_ssh_key: + id: "eef49903-7a09-4ca1-af67-4087c29ab5b6" + state: absent +""", +] + +result_sample = [ + """ +{ + "fingerprint": "98:9c:35:ed:f9:75:5b:52:e2:70:50:22:ea:77:5b:b6", + "id": "eef49903-7a09-4ca1-af67-4087c29ab5b6", + "key": "ssh-dss AAAAB4NzaC1kc3MAAACBAPLEVntPO3L7VUbEwWZ2ErkQJ3KJ8o9kFXJrPcpvVfdNag4jIhQDqbtAUgUy6BclhhbfH9l5nlGTprrpEFkxm/GL91qJUX6xrPkDMjMqx2wSKa4YraReOrCOfkqqEkC3o3G/gYSuvTzLgp2rmPiflypftZyzNM4JZT8jDwFGotJhAAAAFQDPk43bayONtUxjkAcOf+6zP1qb6QAAAIBZHHH0tIlth5ot+Xa/EYuB/M4qh77EkrWUbER0Kki7suskw/ffdKQ0y/v+ZhoAHtBU7BeE3HmP98Vrha1i4cOU+A7DCqV+lK/a+5LoEpua0M2M+VzNSGluYuV4qGpAOxNh3mxUi2R7yXxheN1oks1ROJ/bqkF4BJQXU9Nv49GkZgAAAIByWcsFeOitvzyDaNJOZzEHv9fqGuj0L3maRVWb6O47HGzlMzniIy8WjL2dfgm2/ek+NxVR/yFnYTKDPr6+0uqSD/cb4eHaFbIj7v+k7H8hA1Ioz+duJ1ONAjn6KwneXxOXu15bYIR49P7Go0s9jCdSAP/r9NE5TnE3yiRiQzgEzw== tomk@xps", + "label": "test_key", + "project_id": "b8c6c653-3c96-446e-987e-9c4d12f25353" +} +""" +] + +MUTABLE_ATTRIBUTES = [k for k, v in module_spec.items() if v.editable] + +SPECDOC_META = getSpecDocMeta( + short_description="Manage a project ssh key in Equinix Metal", + description=( + "Manage project ssh key in Equinix Metal. " + "Read more about personal and project SSH keys in [Equinix Metal documentation](https://deploy.equinix.com/developers/docs/metal/accounts/ssh-keys/#personal-keys-vs-project-keys). " + "You can use *id* or *label* to lookup a project SSH key. " + "If you want to create new resource, you must provide *label*, *key* and *project_id*." + ), + examples=specdoc_examples, + options=module_spec, + return_values={ + MODULE_NAME: SpecReturnValue( + description="The module object", + type=FieldType.dict, + sample=result_sample, + ), + }, +) + + +def main(): + module = EquinixModule( + argument_spec=SPECDOC_META.ansible_spec, + required_one_of=[("label", "id")], + required_together=[("label", "key")], + ) + state = module.params.get("state") + changed = False + + try: + module.params_syntax_check() + if module.params.get("id"): + tolerate_not_found = state == "absent" + fetched = module.get_by_id(METAL_SSH_KEY, tolerate_not_found) + else: + fetched = module.get_one_from_list( + MODULE_NAME, + ["key"], + ) + + if fetched: + module.params["id"] = fetched["id"] + if state == "present": + diff = get_diff(module.params, fetched, MUTABLE_ATTRIBUTES) + if diff: + fetched = module.update_by_id(diff, METAL_SSH_KEY) + changed = True + + else: + module.delete_by_id(METAL_SSH_KEY) + changed = True + else: + if state == "present": + fetched = module.create(MODULE_NAME) + changed = True + else: + fetched = {} + except Exception as e: + tb = traceback.format_exc() + module.fail_json(msg=f"Error in {MODULE_NAME}: {to_native(e)}", exception=tb) + + fetched.update({"changed": changed}) + module.exit_json(**fetched) + + +if __name__ == "__main__": + main() diff --git a/plugins/modules/metal_project_ssh_key_info.py b/plugins/modules/metal_project_ssh_key_info.py new file mode 100644 index 0000000..46d5e64 --- /dev/null +++ b/plugins/modules/metal_project_ssh_key_info.py @@ -0,0 +1,145 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +# DOCUMENTATION, EXAMPLES, and RETURN are generated by +# ansible_specdoc. Do not edit them directly. + +DOCUMENTATION = ''' +author: Equinix DevRel Team (@equinix) +description: Gather project SSH keys. Read more about project vs project SSH keys + in [Equinix Metal documentation](https://metal.equinix.com/developers/docs/accounts/ssh-keys/#personal-keys-vs-project-keys). +module: metal_project_ssh_key_info +notes: [] +options: + name: + description: + - Name to search for in existing keys. + required: true + type: str +requirements: null +short_description: Gather project SSH keys. +''' +EXAMPLES = ''' +- set_fact: + desired_name_substring: tkarasek +- name: list project ssh keys + equinix.cloud.metal_project_ssh_key_info: null + register: ssh_keys_listed +- name: filter found ssh keys + set_fact: + both_ssh_keys_listed: '{{ ssh_keys_listed.resources | selectattr(''name'', ''match'', + desired_name_substring) }}' +''' +RETURN = ''' +resources: + description: Found resources + returned: always + sample: + - "\n[\n {\n \"fingerprint\": \"70:c1:73:8b:3f:2f:a4:18:ea:4d:79:13:52:7b:c4:3e\"\ + ,\n \"id\": \"6edfcbc2-17e5-4221-9eac-2f40dbe60daf\",\n \"key\"\ + : \"ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAt5gwVMhwcCrxyxpMEKwiS0xgit3PIIEgVXt6SQHc8eONq0mYJJ5TOBNTnySqXd9RtSv/Jbf5Aq9BzBGWeoZ6sZfKwh984Ip35StJtjXtyIOlY3skovndtupBIwlGXgX/WQzyLr+G/+Yu9/nhdxQi801PDZnDvKoeomM0rMD29nV+m0ud+GrtsAt6VFul2PxqpypZ1TYviyED6IKo7rgQsQDkE9QHcNdfT1FZWiJbfP7o8TIurQJcAXg+MtLoc8rKKcxFMeZ9FSydgtTC7nP1h558RtECGWiUgaBPI7TpBmcdMtbEfAiBoGT17GWnT8qmy2u5xnEKPD9Qft4w4fjfpw==\"\ + ,\n \"label\": \"tkarasek\",\n \"project_id\": b8c6c653-3c96-446e-987e-9c4d12f25353\n\ + \ },\n {\n \"fingerprint\": \"ba:70:af:b3:0f:0e:7f:e5:eb:97:e2:27:b1:f5:6f:94\"\ + ,\n \"id\": \"d00c596d-b42a-44a7-ac14-e299b85e73d3\",\n \"key\"\ + : \"ssh-dss AAAAB3NzaC1kc3MAAACBAOpXVtmc0Bla98bt0o5/Zj7sb4mHIukgVFZu7F32R3VK1cEKB4rEE8uS0oLS/qMRLue45TWVJwRMYGlPjt3p/VyraelxoyJZLuITIsqa5hBc9w0oTlB5Bmbkn16umW96WCaWEoq/aitpocbRChTiP5biI6FyQTQlIHDaYzBDOi11AAAAFQDUXy7cmuzphDpJSYYTiudiUhVokwAAAIEAyUQ9m8qL/1HPkFe6jbXAvtSSmW27F4c+G2xR5HizaHQzXgBOxPcsOsY17KTU+Ddbg+OF9soWNwSpm9pyVjVmNGqH3S8R1pwvuJF/O2Asy1m6wpWhbPw8JdEBW7WHoptBpfuzJoS2LOzJUEmUu4Eb+xS237KG1d1BVny/49KAoH0AAACBAJKBSsm9Xey0fUN6vYtTQgoYeGxxj/LqAIAOs/TpCxZDntly860y/SzHYai8x48k4t7whENY1CJ41fpMcPlz8xIsrNP3326Wbr0ExwOIvJKAVN1YLYqF8NXWzaVrjo5WbSeI8PiWTYemvLAujVxZssIrApTZBhp55nnwge6K1zTG\ + \ tomk@air\",\n \"label\": \"ansible-integration-test-ssh_key-ztiapihf-ssh_key1_renamed\"\ + ,\n \"project_id\": b8c6c653-3c96-446e-987e-9c4d12f25353\n }\n]\n" + type: dict +''' + +# End + +from ansible.module_utils._text import to_native +from ansible_specdoc.objects import SpecField, FieldType, SpecReturnValue +import traceback + +from ansible_collections.equinix.cloud.plugins.module_utils.equinix import ( + EquinixModule, + getSpecDocMeta, +) + +module_spec = dict( + label=SpecField( + type=FieldType.string, + description=["Name to search for in existing keys."], + required=False, + ), + project_id=SpecField( + type=FieldType.string, + description=["Name of the project for listing project keys."], + required=False, + ), +) + +specdoc_examples = [ + """ + +- set_fact: + desired_name_substring: "tkarasek" + +- name: list project ssh keys + equinix.cloud.metal_project_ssh_key_info: + register: ssh_keys_listed + +- name: filter found ssh keys + set_fact: + both_ssh_keys_listed: "{{ ssh_keys_listed.resources | selectattr('label', 'match', desired_name_substring) }}" +""", +] + +result_sample = [ + """ +[ + { + "fingerprint": "70:c1:73:8b:3f:2f:a4:18:ea:4d:79:13:52:7b:c4:3e", + "id": "6edfcbc2-17e5-4221-9eac-2f40dbe60daf", + "key": "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAt5gwVMhwcCrxyxpMEKwiS0xgit3PIIEgVXt6SQHc8eONq0mYJJ5TOBNTnySqXd9RtSv/Jbf5Aq9BzBGWeoZ6sZfKwh984Ip35StJtjXtyIOlY3skovndtupBIwlGXgX/WQzyLr+G/+Yu9/nhdxQi801PDZnDvKoeomM0rMD29nV+m0ud+GrtsAt6VFul2PxqpypZ1TYviyED6IKo7rgQsQDkE9QHcNdfT1FZWiJbfP7o8TIurQJcAXg+MtLoc8rKKcxFMeZ9FSydgtTC7nP1h558RtECGWiUgaBPI7TpBmcdMtbEfAiBoGT17GWnT8qmy2u5xnEKPD9Qft4w4fjfpw==", + "label": "tkarasek", + "project_id": b8c6c653-3c96-446e-987e-9c4d12f25353 + }, + { + "fingerprint": "ba:70:af:b3:0f:0e:7f:e5:eb:97:e2:27:b1:f5:6f:94", + "id": "d00c596d-b42a-44a7-ac14-e299b85e73d3", + "key": "ssh-dss AAAAB3NzaC1kc3MAAACBAOpXVtmc0Bla98bt0o5/Zj7sb4mHIukgVFZu7F32R3VK1cEKB4rEE8uS0oLS/qMRLue45TWVJwRMYGlPjt3p/VyraelxoyJZLuITIsqa5hBc9w0oTlB5Bmbkn16umW96WCaWEoq/aitpocbRChTiP5biI6FyQTQlIHDaYzBDOi11AAAAFQDUXy7cmuzphDpJSYYTiudiUhVokwAAAIEAyUQ9m8qL/1HPkFe6jbXAvtSSmW27F4c+G2xR5HizaHQzXgBOxPcsOsY17KTU+Ddbg+OF9soWNwSpm9pyVjVmNGqH3S8R1pwvuJF/O2Asy1m6wpWhbPw8JdEBW7WHoptBpfuzJoS2LOzJUEmUu4Eb+xS237KG1d1BVny/49KAoH0AAACBAJKBSsm9Xey0fUN6vYtTQgoYeGxxj/LqAIAOs/TpCxZDntly860y/SzHYai8x48k4t7whENY1CJ41fpMcPlz8xIsrNP3326Wbr0ExwOIvJKAVN1YLYqF8NXWzaVrjo5WbSeI8PiWTYemvLAujVxZssIrApTZBhp55nnwge6K1zTG tomk@air", + "label": "ansible-integration-test-ssh_key-ztiapihf-ssh_key1_renamed", + "project_id": b8c6c653-3c96-446e-987e-9c4d12f25353 + } +] +""", +] + +SPECDOC_META = getSpecDocMeta( + short_description="Gather project SSH keys.", + description=( + "Gather project SSH keys. Read more about project vs project SSH keys in [Equinix Metal documentation](https://metal.equinix.com/developers/docs/accounts/ssh-keys/#personal-keys-vs-project-keys)." + ), + examples=specdoc_examples, + options=module_spec, + return_values={ + "resources": SpecReturnValue( + description="Found resources", + type=FieldType.dict, + sample=result_sample, + ), + }, +) + + +def main(): + module = EquinixModule( + argument_spec=SPECDOC_META.ansible_spec, + is_info=True, + ) + try: + module.params_syntax_check() + return_value = {"resources": module.get_list("metal_project_ssh_key")} + except Exception as e: + tr = traceback.format_exc() + module.fail_json(msg=to_native(e), exception=tr) + module.exit_json(**return_value) + + +if __name__ == "__main__": + main() diff --git a/tests/integration/targets/metal_project/tasks/main.yml b/tests/integration/targets/metal_project/tasks/main.yml index de41a4e..dc78a74 100644 --- a/tests/integration/targets/metal_project/tasks/main.yml +++ b/tests/integration/targets/metal_project/tasks/main.yml @@ -60,13 +60,13 @@ - assert: that: - - "second_project_listed.resources | length == 1" + - "second_project_listed.resources | length == 1" - name: list both projects equinix.cloud.metal_project_info: name: "{{ test_prefix }}" register: both_projects_listed - + - assert: that: - "both_projects_listed.resources | length == 2" @@ -80,7 +80,7 @@ equinix.cloud.metal_project: id: "{{ second_project.id }}" state: absent - + always: - name: Announce teardown start debug: diff --git a/tests/integration/targets/metal_project_ssh_key/tasks/main.yml b/tests/integration/targets/metal_project_ssh_key/tasks/main.yml new file mode 100644 index 0000000..0aa475e --- /dev/null +++ b/tests/integration/targets/metal_project_ssh_key/tasks/main.yml @@ -0,0 +1,140 @@ +- name: metal_project_ssh_key + module_defaults: + equinix.cloud.metal_project_ssh_key: + metal_api_token: '{{ metal_api_token }}' + equinix.cloud.metal_device: + metal_api_token: '{{ metal_api_token }}' + equinix.cloud.metal_project_ssh_key_info: + metal_api_token: '{{ metal_api_token }}' + metal_ua_prefix: '{{ metal_ua_prefix }}' + equinix.cloud.metal_project: + metal_api_token: '{{ metal_api_token }}' + equinix.cloud.metal_project_info: + metal_api_token: '{{ metal_api_token }}' + block: + - set_fact: + test_resource_name_prefix: 'ansible-integration-test-ssh_key' + - set_fact: + unique_id: "{{ lookup('community.general.random_string', upper=false, numbers=false, special=false) }}" + - set_fact: + test_prefix: "{{ test_resource_name_prefix }}-{{ unique_id }}" + - set_fact: + test_key: "ssh-dss AAAAB3NzaC1kc3MAAACBAOpXVtmc0Bla98bt0o5/Zj7sb4mHIukgVFZu7F32R3VK1cEKB4rEE8uS0oLS/qMRLue45TWVJwRMYGlPjt3p/VyraelxoyJZLuITIsqa5hBc9w0oTlB5Bmbkn16umW96WCaWEoq/aitpocbRChTiP5biI6FyQTQlIHDaYzBDOi11AAAAFQDUXy7cmuzphDpJSYYTiudiUhVokwAAAIEAyUQ9m8qL/1HPkFe6jbXAvtSSmW27F4c+G2xR5HizaHQzXgBOxPcsOsY17KTU+Ddbg+OF9soWNwSpm9pyVjVmNGqH3S8R1pwvuJF/O2Asy1m6wpWhbPw8JdEBW7WHoptBpfuzJoS2LOzJUEmUu4Eb+xS237KG1d1BVny/49KAoH0AAACBAJKBSsm9Xey0fUN6vYtTQgoYeGxxj/LqAIAOs/TpCxZDntly860y/SzHYai8x48k4t7whENY1CJ41fpMcPlz8xIsrNP3326Wbr0ExwOIvJKAVN1YLYqF8NXWzaVrjo5WbSeI8PiWTYemvLAujVxZssIrApTZBhp55nnwge6K1zTG tomk@air" + - set_fact: + test_key2: "ssh-dss AAAAB3NzaC1kc3MAAACBAPWcHWkA06LxBQ67WmNsp1+aZMwNNz9v67pftePlQg94Z1cU4s/5j5S/Fknj7gapWw/ouiOYqXhC2p/hC9/1ARY15t0aHYqLjRhWzs3j8miL1YyXYjqLPLDtgNpX9E09We5ogjbYCB8CCtZrujm/MB6NWvX+T4uG8C/g66I4/bGdAAAAFQDa4SS+q9aQK/XwiqnWpFpAEY74TQAAAIEAklEfXCf1qbUvTquHhtNVKTiKm+qGRsqxnLnu7aduzU81JDFzveF/agkE5x30olTvKECb1PAziDmt63z/obO3Da8TUz0QVdqv81pNWU5JUNiTB8d3rDJU3B66DA6GI305W8qyt0AGUNGR3rDIzNpZY958faBg+TaILRg8ZFNh0PAAAACAdUhJS6bl5M5sQr6XNilHa0nOTk/PB54faGWWMq7zQvxUKJKsDklNTc0MCPjRppyuokbQ6297tq8pEEFqUAyllMvAf75X7DsBQivLzbNuzp41NqFdS/Oka+T1ypRD7mT6g0Kg8yCVYD2ti874wyTpV9riUUaoItveEF3AdC9AzmI= tomk@air" + + - name: create project for test + equinix.cloud.metal_project: + name: "{{ test_prefix }}-project" + register: project + + - assert: + that: + - project.name == '{{ test_prefix }}-project' + + - name: create first project ssh_key for test + equinix.cloud.metal_project_ssh_key: + label: "{{ test_prefix }}-ssh_key1" + key: "{{ test_key }}" + project_id: "{{ project.id }}" + register: first_ssh_key + + - name: create first ssh_key for test again, to check idempotence + equinix.cloud.metal_project_ssh_key: + label: "{{ test_prefix }}-ssh_key1" + key: "{{ test_key }}" + project_id: "{{ project.id }}" + register: first_ssh_key_2 + + - assert: + that: + - first_ssh_key.label == '{{ test_prefix }}-ssh_key1' + - first_ssh_key.key == "{{ test_key }}" + - first_ssh_key_2.changed == false + + - name: update ssh_key label + equinix.cloud.metal_project_ssh_key: + id: "{{ first_ssh_key.id }}" + key: "{{ test_key }}" + label: "{{ test_prefix }}-ssh_key1_renamed" + + - name: fetch updated ssh_key + equinix.cloud.metal_project_ssh_key: + id: "{{ first_ssh_key.id }}" + register: first_ssh_key_updated + + - assert: + that: + - first_ssh_key_updated.label == '{{ test_prefix }}-ssh_key1_renamed' + - first_ssh_key.key == "{{ test_key }}" + + - name: create second ssh_key for test + equinix.cloud.metal_project_ssh_key: + label: "{{ test_prefix }}-ssh_key2" + key: "{{ test_key2 }}" + project_id: "{{ project.id }}" + register: second_ssh_key + + - name: list ssh_keys + equinix.cloud.metal_project_ssh_key_info: + project_id: "{{ project.id }}" + register: ssh_keys_listed + + - debug: + msg: "{{ ssh_keys_listed.resources }}" + + - debug: + msg: 'ssh_keys_listed.resources | selectattr("label", "equalto", "{{ test_prefix }}-ssh_key2")' + + - assert: + that: + - 'ssh_keys_listed.resources | selectattr("label", "equalto", "{{ test_prefix }}-ssh_key2") | length == 1' + + - name: list test ssh keys + set_fact: + both_ssh_keys_listed: "{{ ssh_keys_listed.resources | selectattr('label', 'match', test_prefix) }}" + + - assert: + that: + - "both_ssh_keys_listed | length == 2" + + - name: delete second ssh_key + equinix.cloud.metal_project_ssh_key: + id: "{{ second_ssh_key.id }}" + state: absent + + - name: check that deleting nonexistent resource doesn't err + equinix.cloud.metal_project_ssh_key: + id: "{{ second_ssh_key.id }}" + state: absent + + always: + - name: Announce teardown start + debug: + msg: "***** TESTING COMPLETE. COMMENCE TEARDOWN *****" + + - name: list ssh_keys + equinix.cloud.metal_project_ssh_key_info: + project_id: "{{ project.id }}" + register: ssh_keys_listed + + - name: delete test ssh_keys + equinix.cloud.metal_project_ssh_key: + id: "{{ item.id }}" + project_id: "{{ project.id }}" + state: absent + loop: "{{ ssh_keys_listed.resources }}" + when: "test_prefix in item.label" + ignore_errors: yes + + - name: list test projects + equinix.cloud.metal_project_info: + name: "{{ test_prefix }}" + register: test_projects_listed + + - name: delete test projects + equinix.cloud.metal_project: + id: "{{ item.id }}" + state: absent + loop: "{{ test_projects_listed.resources }}" + ignore_errors: yes