diff --git a/Makefile b/Makefile index 1c5a50d0..6b0c5f10 100644 --- a/Makefile +++ b/Makefile @@ -62,26 +62,42 @@ gendocs: # ansible-test integration $(TEST_ARGS) --tags never integration-test: create-integration-config create-e2e-firewall @echo "Running Integration Test(s)..." - ansible-test integration $(TEST_ARGS) - -create-e2e-firewall: + { \ + ansible-test integration $(TEST_ARGS); \ + TEST_EXIT_CODE=$$?; \ + make delete-e2e-firewall; \ + exit $$TEST_EXIT_CODE; \ + } + +create-e2e-firewall: update-test-submodules @echo "Running create e2e firewall playbook..." - @if ansible-playbook e2e_scripts/cloud_security_scripts/cloud_e2e_firewall/ansible_linode/create_e2e_cloud_firewall.yaml > /dev/null; then \ - echo "Successfully created e2e firewall"; \ - else \ - echo "Failed to create e2e firewall. Please update the cloud firewall scripts using `git submodule update --init` if yaml file doesn't exist"; \ + @OUTPUT=$$(ansible-playbook e2e_scripts/cloud_security_scripts/cloud_e2e_firewall/ansible_linode/create_e2e_cloud_firewall.yaml 2>&1); \ + FAILED_COUNT=$$(echo "$$OUTPUT" | grep "failed=" | awk -F 'failed=' '{print $$2}' | awk '{print $$1}'); \ + if [ "$$FAILED_COUNT" -gt 0 ]; then \ + echo "Playbook execution failed:"; \ + echo "$$OUTPUT"; \ exit 1; \ + else \ + echo "E2E Cloud firewall created successfully."; \ fi -delete-e2e-firewall: + +delete-e2e-firewall: update-test-submodules @echo "Running delete e2e firewall playbook..." - @if ansible-playbook e2e_scripts/cloud_security_scripts/cloud_e2e_firewall/ansible_linode/delete_e2e_cloud_firewall.yaml > /dev/null; then \ - echo "Successfully deleted e2e firewall"; \ + @OUTPUT=$$(ansible-playbook e2e_scripts/cloud_security_scripts/cloud_e2e_firewall/ansible_linode/delete_e2e_cloud_firewall.yaml 2>&1); \ + FAILED_COUNT=$$(echo "$$OUTPUT" | grep "failed=" | awk -F 'failed=' '{print $$2}' | awk '{print $$1}'); \ + if [ "$$FAILED_COUNT" -gt 0 ]; then \ + echo "Playbook execution failed:"; \ + echo "$$OUTPUT"; \ + exit 1; \ else \ - echo "Failed to delete e2e firewall"; \ - fi + echo "E2E Cloud firewall created successfully."; \ + fi + +update-test-submodules: + @git submodule update --init -test: integration-test delete-e2e-firewall +test: integration-test testall: ./scripts/test_all.sh diff --git a/README.md b/README.md index 6932374b..1c04e31d 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Name | Description | [linode.cloud.lke_node_pool](./docs/modules/lke_node_pool.md)|Manage Linode LKE cluster node pools.| [linode.cloud.nodebalancer](./docs/modules/nodebalancer.md)|Manage a Linode NodeBalancer.| [linode.cloud.nodebalancer_node](./docs/modules/nodebalancer_node.md)|Manage Linode NodeBalancer Nodes.| -[linode.cloud.nodebalancer_stats](./docs/modules/nodebalancer_stats.md)|View a Linode NodeBalancers Stats.| +[linode.cloud.nodebalancer_stats](./docs/modules/nodebalancer_stats.md)|Get info about a Linode Node Balancer Stats.| [linode.cloud.object_keys](./docs/modules/object_keys.md)|Manage Linode Object Storage Keys.| [linode.cloud.placement_group](./docs/modules/placement_group.md)|Manage a Linode Placement Group.| [linode.cloud.placement_group_assign](./docs/modules/placement_group_assign.md)|Manages a single assignment between a Linode and a Placement Group.| @@ -62,14 +62,14 @@ Name | Description | [linode.cloud.database_mysql_info](./docs/modules/database_mysql_info.md)|Get info about a Linode MySQL Managed Database.| [linode.cloud.database_postgresql_info](./docs/modules/database_postgresql_info.md)|Get info about a Linode PostgreSQL Managed Database.| [linode.cloud.domain_info](./docs/modules/domain_info.md)|Get info about a Linode Domain.| -[linode.cloud.domain_record_info](./docs/modules/domain_record_info.md)|Get info about a Linode Domain Record.| +[linode.cloud.domain_record_info](./docs/modules/domain_record_info.md)|Get info about a Linode Domain Records.| [linode.cloud.firewall_info](./docs/modules/firewall_info.md)|Get info about a Linode Firewall.| [linode.cloud.image_info](./docs/modules/image_info.md)|Get info about a Linode Image.| [linode.cloud.instance_info](./docs/modules/instance_info.md)|Get info about a Linode Instance.| [linode.cloud.ip_info](./docs/modules/ip_info.md)|Get info about a Linode IP.| [linode.cloud.ipv6_range_info](./docs/modules/ipv6_range_info.md)|Get info about a Linode IPv6 range.| [linode.cloud.lke_cluster_info](./docs/modules/lke_cluster_info.md)|Get info about a Linode LKE cluster.| -[linode.cloud.nodebalancer_info](./docs/modules/nodebalancer_info.md)|Get info about a Linode NodeBalancer.| +[linode.cloud.nodebalancer_info](./docs/modules/nodebalancer_info.md)|Get info about a Linode Node Balancer.| [linode.cloud.object_cluster_info](./docs/modules/object_cluster_info.md)|**NOTE: This module has been deprecated because it relies on deprecated API endpoints. Going forward, `region` will be the preferred way to designate where Object Storage resources should be created.**| [linode.cloud.placement_group_info](./docs/modules/placement_group_info.md)|Get info about a Linode Placement Group.| [linode.cloud.profile_info](./docs/modules/profile_info.md)|Get info about a Linode Profile.| @@ -95,20 +95,20 @@ Name | Description | [linode.cloud.database_engine_list](./docs/modules/database_engine_list.md)|List and filter on Managed Database engine types.| [linode.cloud.database_list](./docs/modules/database_list.md)|List and filter on Linode Managed Databases.| [linode.cloud.domain_list](./docs/modules/domain_list.md)|List and filter on Domains.| -[linode.cloud.event_list](./docs/modules/event_list.md)|List and filter on Linode events.| +[linode.cloud.event_list](./docs/modules/event_list.md)|List and filter on Events.| [linode.cloud.firewall_list](./docs/modules/firewall_list.md)|List and filter on Firewalls.| [linode.cloud.image_list](./docs/modules/image_list.md)|List and filter on Images.| -[linode.cloud.instance_list](./docs/modules/instance_list.md)|List and filter on Linode Instances.| -[linode.cloud.instance_type_list](./docs/modules/instance_type_list.md)|List and filter on Linode Instance Types.| +[linode.cloud.instance_list](./docs/modules/instance_list.md)|List and filter on Instances.| +[linode.cloud.instance_type_list](./docs/modules/instance_type_list.md)|**NOTE: This module has been deprecated in favor of `type_list`.| [linode.cloud.lke_version_list](./docs/modules/lke_version_list.md)|List Kubernetes versions available for deployment to a Kubernetes cluster.| -[linode.cloud.nodebalancer_list](./docs/modules/nodebalancer_list.md)|List and filter on Nodebalancers.| +[linode.cloud.nodebalancer_list](./docs/modules/nodebalancer_list.md)|List and filter on Node Balancers.| [linode.cloud.object_cluster_list](./docs/modules/object_cluster_list.md)|**NOTE: This module has been deprecated because it relies on deprecated API endpoints. Going forward, `region` will be the preferred way to designate where Object Storage resources should be created.**| [linode.cloud.placement_group_list](./docs/modules/placement_group_list.md)|List and filter on Placement Groups.| -[linode.cloud.region_list](./docs/modules/region_list.md)|List and filter on Linode Regions.| +[linode.cloud.region_list](./docs/modules/region_list.md)|List and filter on Regions.| [linode.cloud.ssh_key_list](./docs/modules/ssh_key_list.md)|List and filter on SSH keys in the Linode profile.| [linode.cloud.stackscript_list](./docs/modules/stackscript_list.md)|List and filter on Linode stackscripts.| [linode.cloud.token_list](./docs/modules/token_list.md)|List and filter on Linode Account tokens.| -[linode.cloud.type_list](./docs/modules/type_list.md)|List and filter on Linode Instance Types.| +[linode.cloud.type_list](./docs/modules/type_list.md)|List and filter on Types.| [linode.cloud.user_list](./docs/modules/user_list.md)|List Users.| [linode.cloud.vlan_list](./docs/modules/vlan_list.md)|List and filter on Linode VLANs.| [linode.cloud.volume_list](./docs/modules/volume_list.md)|List and filter on Linode Volumes.| diff --git a/docs/modules/account_availability_info.md b/docs/modules/account_availability_info.md index 5b2fe5fe..c94e2792 100644 --- a/docs/modules/account_availability_info.md +++ b/docs/modules/account_availability_info.md @@ -2,7 +2,7 @@ Get info about a Linode Account Availability. -**:warning: This module makes use of beta endpoints and requires the `api_version` field be explicitly set to `v4beta`.** +WARNING! This module makes use of beta endpoints and requires the C(api_version) field be explicitly set to C(v4beta). - [Minimum Required Fields](#minimum-required-fields) - [Examples](#examples) @@ -45,6 +45,6 @@ Get info about a Linode Account Availability. } ``` - - See the [Linode API response documentation](TBD) for a list of returned fields + - See the [Linode API response documentation](https://techdocs.akamai.com/linode-api/reference/get-account-availability) for a list of returned fields diff --git a/docs/modules/account_availability_list.md b/docs/modules/account_availability_list.md index 3b21b205..5c04aecd 100644 --- a/docs/modules/account_availability_list.md +++ b/docs/modules/account_availability_list.md @@ -2,7 +2,7 @@ List and filter on Account Availabilities. -**:warning: This module makes use of beta endpoints and requires the `api_version` field be explicitly set to `v4beta`.** +WARNING! This module makes use of beta endpoints and requires the C(api_version) field be explicitly set to C(v4beta). - [Minimum Required Fields](#minimum-required-fields) - [Examples](#examples) @@ -36,7 +36,7 @@ List and filter on Account Availabilities. | Field | Type | Required | Description | |-----------|------|----------|------------------------------------------------------------------------------| -| `name` |
`str`
|
**Required**
| The name of the field to filter on. Valid filterable fields can be found [here](TBD). | +| `name` |
`str`
|
**Required**
| The name of the field to filter on. Valid filterable fields can be found [here](https://techdocs.akamai.com/linode-api/reference/get-account-availability). | | `values` |
`list`
|
**Required**
| A list of values to allow for this field. Fields will pass this filter if at least one of these values matches. | ## Return Values @@ -58,6 +58,6 @@ List and filter on Account Availabilities. } ] ``` - - See the [Linode API response documentation](TBD) for a list of returned fields + - See the [Linode API response documentation](https://techdocs.akamai.com/linode-api/reference/get-account-availability) for a list of returned fields diff --git a/docs/modules/account_info.md b/docs/modules/account_info.md index a2ffd468..b52e9802 100644 --- a/docs/modules/account_info.md +++ b/docs/modules/account_info.md @@ -22,7 +22,7 @@ Get info about a Linode Account. ## Return Values -- `account` - The account info in JSON serialized form. +- `account` - The returned Account. - Sample Response: ```json diff --git a/docs/modules/child_account_info.md b/docs/modules/child_account_info.md index d96a1d82..de7e65aa 100644 --- a/docs/modules/child_account_info.md +++ b/docs/modules/child_account_info.md @@ -65,5 +65,6 @@ NOTE: Parent/Child related features may not be generally available. "zip": "19102-1234" } ``` + - See the [Linode API response documentation](https://techdocs.akamai.com/linode-api/reference/get-child-account) for a list of returned fields diff --git a/docs/modules/child_account_list.md b/docs/modules/child_account_list.md index f26ea2a8..bd5f1f2e 100644 --- a/docs/modules/child_account_list.md +++ b/docs/modules/child_account_list.md @@ -35,7 +35,7 @@ NOTE: Parent/Child related features may not be generally available. | Field | Type | Required | Description | |-----------|------|----------|------------------------------------------------------------------------------| -| `name` |
`str`
|
**Required**
| The name of the field to filter on. Valid filterable fields can be found [here](). | +| `name` |
`str`
|
**Required**
| The name of the field to filter on. Valid filterable fields can be found [here](https://techdocs.akamai.com/linode-api/reference/get-child-accounts). | | `values` |
`list`
|
**Required**
| A list of values to allow for this field. Fields will pass this filter if at least one of these values matches. | ## Return Values @@ -74,5 +74,6 @@ NOTE: Parent/Child related features may not be generally available. "zip": "19102-1234" } ``` + - See the [Linode API response documentation](https://techdocs.akamai.com/linode-api/reference/get-child-accounts) for a list of returned fields diff --git a/docs/modules/domain.md b/docs/modules/domain.md index 35173768..89e7b445 100644 --- a/docs/modules/domain.md +++ b/docs/modules/domain.md @@ -106,20 +106,18 @@ Manage Linode Domains. - Sample Response: ```json - [ - { - "zone_file": [ - "; example.com [123]", - "$TTL 864000", - "@ IN SOA ns1.linode.com. user.example.com. 2021000066 14400 14400 1209600 86400", - "@ NS ns1.linode.com.", - "@ NS ns2.linode.com.", - "@ NS ns3.linode.com.", - "@ NS ns4.linode.com.", - "@ NS ns5.linode.com." - ] - } - ] + { + "zone_file": [ + "; example.com [123]", + "$TTL 864000", + "@ IN SOA ns1.linode.com. user.example.com. 2021000066 14400 14400 1209600 86400", + "@ NS ns1.linode.com.", + "@ NS ns2.linode.com.", + "@ NS ns3.linode.com.", + "@ NS ns4.linode.com.", + "@ NS ns5.linode.com." + ] + } ``` - See the [Linode API response documentation](https://techdocs.akamai.com/linode-api/reference/get-domain-zone) for a list of returned fields diff --git a/docs/modules/domain_info.md b/docs/modules/domain_info.md index 31f53287..b511d381 100644 --- a/docs/modules/domain_info.md +++ b/docs/modules/domain_info.md @@ -31,12 +31,12 @@ Get info about a Linode Domain. | Field | Type | Required | Description | |-----------|------|----------|------------------------------------------------------------------------------| -| `id` |
`int`
|
Optional
| The unique domain name of the Domain. Optional if `domain` is defined. **(Conflicts With: `domain`)** | -| `domain` |
`str`
|
Optional
| The unique id of the Domain. Optional if `id` is defined. **(Conflicts With: `id`)** | +| `id` |
`int`
|
Optional
| The ID of the Domain to resolve. **(Conflicts With: `domain`)** | +| `domain` |
`str`
|
Optional
| The domain of the Domain to resolve. **(Conflicts With: `id`)** | ## Return Values -- `domain` - The domain in JSON serialized form. +- `domain` - The returned Domain. - Sample Response: ```json @@ -63,7 +63,7 @@ Get info about a Linode Domain. - See the [Linode API response documentation](https://techdocs.akamai.com/linode-api/reference/get-domain) for a list of returned fields -- `records` - The domain record in JSON serialized form. +- `records` - The returned records. - Sample Response: ```json @@ -85,27 +85,25 @@ Get info about a Linode Domain. } ] ``` - - See the [Linode API response documentation](https://techdocs.akamai.com/linode-api/reference/get-domain-record) for a list of returned fields + - See the [Linode API response documentation](https://techdocs.akamai.com/linode-api/reference/get-domain-records) for a list of returned fields -- `zone_file` - The zone file for the last rendered zone for the specified domain. +- `zone_file` - The returned zone file. - Sample Response: ```json - [ - { - "zone_file": [ - "; example.com [123]", - "$TTL 864000", - "@ IN SOA ns1.linode.com. user.example.com. 2021000066 14400 14400 1209600 86400", - "@ NS ns1.linode.com.", - "@ NS ns2.linode.com.", - "@ NS ns3.linode.com.", - "@ NS ns4.linode.com.", - "@ NS ns5.linode.com." - ] - } - ] + { + "zone_file": [ + "; example.com [123]", + "$TTL 864000", + "@ IN SOA ns1.linode.com. user.example.com. 2021000066 14400 14400 1209600 86400", + "@ NS ns1.linode.com.", + "@ NS ns2.linode.com.", + "@ NS ns3.linode.com.", + "@ NS ns4.linode.com.", + "@ NS ns5.linode.com." + ] + } ``` - See the [Linode API response documentation](https://techdocs.akamai.com/linode-api/reference/get-domain-zone) for a list of returned fields diff --git a/docs/modules/domain_list.md b/docs/modules/domain_list.md index 02f84006..754183c2 100644 --- a/docs/modules/domain_list.md +++ b/docs/modules/domain_list.md @@ -32,21 +32,21 @@ List and filter on Domains. | Field | Type | Required | Description | |-----------|------|----------|------------------------------------------------------------------------------| -| `order` |
`str`
|
Optional
| The order to list domains in. **(Choices: `desc`, `asc`; Default: `asc`)** | -| `order_by` |
`str`
|
Optional
| The attribute to order domains by. | -| [`filters` (sub-options)](#filters) |
`list`
|
Optional
| A list of filters to apply to the resulting domains. | -| `count` |
`int`
|
Optional
| The number of results to return. If undefined, all results will be returned. | +| `order` |
`str`
|
Optional
| The order to list Domains in. **(Choices: `desc`, `asc`; Default: `asc`)** | +| `order_by` |
`str`
|
Optional
| The attribute to order Domains by. | +| [`filters` (sub-options)](#filters) |
`list`
|
Optional
| A list of filters to apply to the resulting Domains. | +| `count` |
`int`
|
Optional
| The number of Domains to return. If undefined, all results will be returned. | ### filters | Field | Type | Required | Description | |-----------|------|----------|------------------------------------------------------------------------------| -| `name` |
`str`
|
**Required**
| The name of the field to filter on. Valid filterable attributes can be found here: https://techdocs.akamai.com/linode-api/reference/get-domains | +| `name` |
`str`
|
**Required**
| The name of the field to filter on. Valid filterable fields can be found [here](https://techdocs.akamai.com/linode-api/reference/get-domains). | | `values` |
`list`
|
**Required**
| A list of values to allow for this field. Fields will pass this filter if at least one of these values matches. | ## Return Values -- `domains` - The returned domains. +- `domains` - The returned Domains. - Sample Response: ```json diff --git a/docs/modules/domain_record.md b/docs/modules/domain_record.md index 5f08966e..770f92a5 100644 --- a/docs/modules/domain_record.md +++ b/docs/modules/domain_record.md @@ -26,6 +26,20 @@ NOTE: Domain records are identified by their name, target, and type. state: present ``` +```yaml +- name: Create an SRV domain record + linode.cloud.domain_record: + domain: my-domain.com + service: srv-service + protocol: tcp + type: 'SRV' + target: host.example.com + port: 443 + priority: 0 + weight: 1 + state: present +``` + ```yaml - name: Delete a domain record linode.cloud.domain_record: @@ -53,7 +67,7 @@ NOTE: Domain records are identified by their name, target, and type. | `domain_id` |
`int`
|
Optional
| The ID of the parent Domain. | | `domain` |
`str`
|
Optional
| The name of the parent Domain. | | `record_id` |
`int`
|
Optional
| The id of the record to modify. **(Conflicts With: `name`)** | -| `name` |
`str`
|
Optional
| The name of this Record. NOTE: If the name of the record ends with the domain, it will be dropped from the resulting record's name. **(Conflicts With: `record_id`)** | +| `name` |
`str`
|
Optional
| The name of this Record. NOTE: If the name of the record ends with the domain, it will be dropped from the resulting record's name. Unused for SRV record. Use the service property to set the service name for this record. **(Conflicts With: `record_id`)** | | `port` |
`int`
|
Optional
| The port this Record points to. Only valid and required for SRV record requests. **(Updatable)** | | `priority` |
`int`
|
Optional
| The priority of the target host for this Record. Lower values are preferred. Only valid for MX and SRV record requests. Required for SRV record requests. **(Updatable)** | | `protocol` |
`str`
|
Optional
| The protocol this Record’s service communicates with. An underscore (_) is prepended automatically to the submitted value for this property. **(Updatable)** | diff --git a/docs/modules/domain_record_info.md b/docs/modules/domain_record_info.md index e7aca469..88ee0fe4 100644 --- a/docs/modules/domain_record_info.md +++ b/docs/modules/domain_record_info.md @@ -1,6 +1,6 @@ # domain_record_info -Get info about a Linode Domain Record. +Get info about a Linode Domain Records. - [Minimum Required Fields](#minimum-required-fields) - [Examples](#examples) @@ -35,14 +35,14 @@ Get info about a Linode Domain Record. | Field | Type | Required | Description | |-----------|------|----------|------------------------------------------------------------------------------| -| `domain_id` |
`int`
|
Optional
| The ID of the parent Domain. Optional if `domain` is defined. **(Conflicts With: `domain`)** | -| `domain` |
`str`
|
Optional
| The name of the parent Domain. Optional if `domain_id` is defined. **(Conflicts With: `domain_id`)** | -| `id` |
`int`
|
Optional
| The unique id of the subdomain. Optional if `name` is defined. **(Conflicts With: `name`)** | -| `name` |
`str`
|
Optional
| The name of the domain record. Optional if `id` is defined. **(Conflicts With: `id`)** | +| `domain_id` |
`int`
|
Optional
| The ID of the Domain ID for this resource. **(Conflicts With: `domain`)** | +| `domain` |
`str`
|
Optional
| The ID of the Domain for this resource. **(Conflicts With: `domain_id`)** | +| `id` |
`int`
|
Optional
| The ID of the Domain Records to resolve. **(Conflicts With: `name`)** | +| `name` |
`str`
|
Optional
| The name of the Domain Records to resolve. **(Conflicts With: `id`)** | ## Return Values -- `record` - View a single Record on this Domain. +- `record` - The returned Domain Records. - Sample Response: ```json diff --git a/docs/modules/event_list.md b/docs/modules/event_list.md index 625e13c5..0b3e6ff3 100644 --- a/docs/modules/event_list.md +++ b/docs/modules/event_list.md @@ -1,6 +1,6 @@ # event_list -List and filter on Linode events. +List and filter on Events. - [Minimum Required Fields](#minimum-required-fields) - [Examples](#examples) @@ -40,21 +40,21 @@ List and filter on Linode events. | Field | Type | Required | Description | |-----------|------|----------|------------------------------------------------------------------------------| -| `order` |
`str`
|
Optional
| The order to list events in. **(Choices: `desc`, `asc`; Default: `asc`)** | -| `order_by` |
`str`
|
Optional
| The attribute to order events by. | -| [`filters` (sub-options)](#filters) |
`list`
|
Optional
| A list of filters to apply to the resulting events. | -| `count` |
`int`
|
Optional
| The number of results to return. If undefined, all results will be returned. | +| `order` |
`str`
|
Optional
| The order to list Events in. **(Choices: `desc`, `asc`; Default: `asc`)** | +| `order_by` |
`str`
|
Optional
| The attribute to order Events by. | +| [`filters` (sub-options)](#filters) |
`list`
|
Optional
| A list of filters to apply to the resulting Events. | +| `count` |
`int`
|
Optional
| The number of Events to return. If undefined, all results will be returned. | ### filters | Field | Type | Required | Description | |-----------|------|----------|------------------------------------------------------------------------------| -| `name` |
`str`
|
**Required**
| The name of the field to filter on. Valid filterable attributes can be found here: https://techdocs.akamai.com/linode-api/reference/get-events | +| `name` |
`str`
|
**Required**
| The name of the field to filter on. Valid filterable fields can be found [here](https://techdocs.akamai.com/linode-api/reference/get-events). | | `values` |
`list`
|
**Required**
| A list of values to allow for this field. Fields will pass this filter if at least one of these values matches. | ## Return Values -- `events` - The returned events. +- `events` - The returned Events. - Sample Response: ```json diff --git a/docs/modules/image.md b/docs/modules/image.md index 1b1d3b17..9b13dc08 100644 --- a/docs/modules/image.md +++ b/docs/modules/image.md @@ -20,6 +20,8 @@ Manage a Linode Image. label: my-image description: Created using Ansible! disk_id: 12345 + tags: + - test state: present ``` @@ -29,6 +31,22 @@ Manage a Linode Image. label: my-image description: Created using Ansible! source_file: myimage.img.gz + tags: + - test + state: present +``` + +```yaml +- name: Replicate an image + linode.cloud.image: + label: my-image + description: Created using Ansible! + disk_id: 12345 + tags: + - test + replica_regions: + - us-east + - us-central state: present ``` @@ -54,6 +72,9 @@ Manage a Linode Image. | `source_file` |
`str`
|
Optional
| An image file to create this image with. **(Conflicts With: `disk_id`)** | | `wait` |
`bool`
|
Optional
| Wait for the image to have status `available` before returning. **(Default: `True`)** | | `wait_timeout` |
`int`
|
Optional
| The amount of time, in seconds, to wait for an image to have status `available`. **(Default: `600`)** | +| `tags` |
`list`
|
Optional
| A list of customized tags of this new Image. **(Updatable)** | +| `replica_regions` |
`list`
|
Optional
| A list of regions that customer wants to replicate this image in. At least one available region must be provided and only core regions allowed. Existing images in the regions not passed will be removed. NOTE: Image replication may not currently be available to all users. **(Updatable)** | +| `wait_for_replications` |
`bool`
|
Optional
| Wait for the all the replications `available` before returning. **(Default: `False`)** | ## Return Values @@ -64,19 +85,31 @@ Manage a Linode Image. { "capabilities": [], "created": "2021-08-14T22:44:02", - "created_by": "linode", + "created_by": "my-account", "deprecated": false, "description": "Example Image description.", "eol": "2026-07-01T04:00:00", "expiry": null, - "id": "linode/debian11", + "id": "private/123", "is_public": true, - "label": "Debian 11", + "label": "my-image", "size": 2500, "status": null, "type": "manual", "updated": "2021-08-14T22:44:02", - "vendor": "Debian" + "vendor": "Debian", + "tags": ["test"], + "total_size": 5000, + "regions": [ + { + "region": "us-east", + "status": "available" + }, + { + "region": "us-central", + "status": "pending" + } + ] } ``` - See the [Linode API response documentation](https://techdocs.akamai.com/linode-api/reference/get-image) for a list of returned fields diff --git a/docs/modules/image_info.md b/docs/modules/image_info.md index 5072433f..6ede4285 100644 --- a/docs/modules/image_info.md +++ b/docs/modules/image_info.md @@ -31,31 +31,43 @@ Get info about a Linode Image. | Field | Type | Required | Description | |-----------|------|----------|------------------------------------------------------------------------------| -| `id` |
`str`
|
Optional
| The ID of the image. **(Conflicts With: `label`)** | -| `label` |
`str`
|
Optional
| The label of the image. **(Conflicts With: `id`)** | +| `label` |
`str`
|
Optional
| The label of the Image to resolve. **(Conflicts With: `id`)** | +| `id` |
`str`
|
Optional
| The ID of the Image to resolve. **(Conflicts With: `label`)** | ## Return Values -- `image` - The image in JSON serialized form. +- `image` - The returned Image. - Sample Response: ```json { "capabilities": [], "created": "2021-08-14T22:44:02", - "created_by": "linode", + "created_by": "my-account", "deprecated": false, "description": "Example Image description.", "eol": "2026-07-01T04:00:00", "expiry": null, - "id": "linode/debian11", + "id": "private/123", "is_public": true, - "label": "Debian 11", + "label": "my-image", "size": 2500, "status": null, "type": "manual", "updated": "2021-08-14T22:44:02", - "vendor": "Debian" + "vendor": "Debian", + "tags": ["test"], + "total_size": 5000, + "regions": [ + { + "region": "us-east", + "status": "available" + }, + { + "region": "us-central", + "status": "pending" + } + ] } ``` - See the [Linode API response documentation](https://techdocs.akamai.com/linode-api/reference/get-image) for a list of returned fields diff --git a/docs/modules/image_list.md b/docs/modules/image_list.md index ac8a37da..03345cf8 100644 --- a/docs/modules/image_list.md +++ b/docs/modules/image_list.md @@ -61,20 +61,31 @@ List and filter on Images. [ { "created":"2021-08-14T22:44:02", - "created_by":"linode", + "created_by":"my-account", "deprecated":false, "description":"Example Image description.", "eol":"2026-07-01T04:00:00", "expiry":null, - "id":"linode/debian11", - "is_public":true, - "label":"Debian 11", + "id":"private/123", + "is_public":false, + "label":"test", "size":2500, "status":null, "type":"manual", "updated":"2021-08-14T22:44:02", - "vendor":"Debian" - } + "vendor":"Debian", + "tags": ["test"], + "total_size": 5000, + "regions": [ + { + "region": "us-east", + "status": "available" + }, + { + "region": "us-central", + "status": "pending" + }] + } ] ``` - See the [Linode API response documentation](https://techdocs.akamai.com/linode-api/reference/get-images) for a list of returned fields diff --git a/docs/modules/instance.md b/docs/modules/instance.md index d7a6aa0e..581e93f2 100644 --- a/docs/modules/instance.md +++ b/docs/modules/instance.md @@ -149,6 +149,7 @@ Manage Linode Instances, Configs, and Disks. | `auto_disk_resize` |
`bool`
|
Optional
| Whether implicitly created disks should be resized during a type change operation. **(Default: `False`)** | | `tags` |
`list`
|
Optional
| An array of tags applied to this object. Tags are for organizational purposes only. **(Updatable)** | | [`placement_group` (sub-options)](#placement_group) |
`dict`
|
Optional
| A Placement Group to create this Linode under. | +| `swap_size` |
`int`
|
Optional
| When deploying from an Image, this field is optional, otherwise it is ignored. This is used to set the swap disk size for the newly-created Linode. | ### configs diff --git a/docs/modules/instance_list.md b/docs/modules/instance_list.md index 752d7066..e0b63c07 100644 --- a/docs/modules/instance_list.md +++ b/docs/modules/instance_list.md @@ -1,6 +1,6 @@ # instance_list -List and filter on Linode Instances. +List and filter on Instances. - [Minimum Required Fields](#minimum-required-fields) - [Examples](#examples) @@ -32,21 +32,21 @@ List and filter on Linode Instances. | Field | Type | Required | Description | |-----------|------|----------|------------------------------------------------------------------------------| -| `order` |
`str`
|
Optional
| The order to list instances in. **(Choices: `desc`, `asc`; Default: `asc`)** | -| `order_by` |
`str`
|
Optional
| The attribute to order instances by. | -| [`filters` (sub-options)](#filters) |
`list`
|
Optional
| A list of filters to apply to the resulting instances. | -| `count` |
`int`
|
Optional
| The number of results to return. If undefined, all results will be returned. | +| `order` |
`str`
|
Optional
| The order to list Instances in. **(Choices: `desc`, `asc`; Default: `asc`)** | +| `order_by` |
`str`
|
Optional
| The attribute to order Instances by. | +| [`filters` (sub-options)](#filters) |
`list`
|
Optional
| A list of filters to apply to the resulting Instances. | +| `count` |
`int`
|
Optional
| The number of Instances to return. If undefined, all results will be returned. | ### filters | Field | Type | Required | Description | |-----------|------|----------|------------------------------------------------------------------------------| -| `name` |
`str`
|
**Required**
| The name of the field to filter on. Valid filterable attributes can be found here: https://techdocs.akamai.com/linode-api/reference/get-linode-instances | +| `name` |
`str`
|
**Required**
| The name of the field to filter on. Valid filterable fields can be found [here](https://techdocs.akamai.com/linode-api/reference/get-linode-instances). | | `values` |
`list`
|
**Required**
| A list of values to allow for this field. Fields will pass this filter if at least one of these values matches. | ## Return Values -- `instances` - The returned instances. +- `instances` - The returned Instances. - Sample Response: ```json diff --git a/docs/modules/instance_type_list.md b/docs/modules/instance_type_list.md index c9931d98..f3d18950 100644 --- a/docs/modules/instance_type_list.md +++ b/docs/modules/instance_type_list.md @@ -1,5 +1,7 @@ # instance_type_list +**NOTE: This module has been deprecated in favor of `type_list`. + List and filter on Linode Instance Types. - [Minimum Required Fields](#minimum-required-fields) @@ -32,21 +34,21 @@ List and filter on Linode Instance Types. | Field | Type | Required | Description | |-----------|------|----------|------------------------------------------------------------------------------| -| `order` |
`str`
|
Optional
| The order to list instance types in. **(Choices: `desc`, `asc`; Default: `asc`)** | -| `order_by` |
`str`
|
Optional
| The attribute to order instance types by. | -| [`filters` (sub-options)](#filters) |
`list`
|
Optional
| A list of filters to apply to the resulting instance types. | -| `count` |
`int`
|
Optional
| The number of results to return. If undefined, all results will be returned. | +| `order` |
`str`
|
Optional
| The order to list Instance Types in. **(Choices: `desc`, `asc`; Default: `asc`)** | +| `order_by` |
`str`
|
Optional
| The attribute to order Instance Types by. | +| [`filters` (sub-options)](#filters) |
`list`
|
Optional
| A list of filters to apply to the resulting Instance Types. | +| `count` |
`int`
|
Optional
| The number of Instance Types to return. If undefined, all results will be returned. | ### filters | Field | Type | Required | Description | |-----------|------|----------|------------------------------------------------------------------------------| -| `name` |
`str`
|
**Required**
| The name of the field to filter on. Valid filterable attributes can be found here: https://techdocs.akamai.com/linode-api/reference/get-linode-types | +| `name` |
`str`
|
**Required**
| The name of the field to filter on. Valid filterable fields can be found [here](https://techdocs.akamai.com/linode-api/reference/get-linode-types). | | `values` |
`list`
|
**Required**
| A list of values to allow for this field. Fields will pass this filter if at least one of these values matches. | ## Return Values -- `instance_types` - The returned instance types. +- `instance_types` - The returned Instance Types. - Sample Response: ```json diff --git a/docs/modules/ip_share.md b/docs/modules/ip_share.md index 96745f23..d69ff4c7 100644 --- a/docs/modules/ip_share.md +++ b/docs/modules/ip_share.md @@ -2,7 +2,7 @@ Manage the Linode shared IPs. -**:warning: This module makes use of beta endpoints and requires the `api_version` field be explicitly set to `v4beta`.** +WARNING! This module makes use of beta endpoints and requires the C(api_version) field be explicitly set to C(v4beta). - [Minimum Required Fields](#minimum-required-fields) - [Examples](#examples) diff --git a/docs/modules/nodebalancer_info.md b/docs/modules/nodebalancer_info.md index 1060595b..ba0e4e2a 100644 --- a/docs/modules/nodebalancer_info.md +++ b/docs/modules/nodebalancer_info.md @@ -1,6 +1,6 @@ # nodebalancer_info -Get info about a Linode NodeBalancer. +Get info about a Linode Node Balancer. - [Minimum Required Fields](#minimum-required-fields) - [Examples](#examples) @@ -31,12 +31,12 @@ Get info about a Linode NodeBalancer. | Field | Type | Required | Description | |-----------|------|----------|------------------------------------------------------------------------------| -| `id` |
`int`
|
Optional
| The ID of this NodeBalancer. Optional if `label` is defined. **(Conflicts With: `label`)** | -| `label` |
`str`
|
Optional
| The label of this NodeBalancer. Optional if `id` is defined. **(Conflicts With: `id`)** | +| `label` |
`str`
|
Optional
| The label of the Node Balancer to resolve. **(Conflicts With: `id`)** | +| `id` |
`int`
|
Optional
| The ID of the Node Balancer to resolve. **(Conflicts With: `label`)** | ## Return Values -- `node_balancer` - The NodeBalancer in JSON serialized form. +- `node_balancer` - The returned Node Balancer. - Sample Response: ```json @@ -64,7 +64,7 @@ Get info about a Linode NodeBalancer. - See the [Linode API response documentation](https://techdocs.akamai.com/linode-api/reference/get-node-balancer) for a list of returned fields -- `configs` - A list of configs applied to the NodeBalancer. +- `configs` - The returned configs. - Sample Response: ```json @@ -96,10 +96,10 @@ Get info about a Linode NodeBalancer. } ] ``` - - See the [Linode API response documentation](https://techdocs.akamai.com/linode-api/reference/get-node-balancer-config) for a list of returned fields + - See the [Linode API response documentation](https://techdocs.akamai.com/linode-api/reference/get-node-balancer-configs) for a list of returned fields -- `nodes` - A list of configs applied to the NodeBalancer. +- `nodes` - The returned nodes. - Sample Response: ```json @@ -116,10 +116,10 @@ Get info about a Linode NodeBalancer. } ] ``` - - See the [Linode API response documentation](https://techdocs.akamai.com/linode-api/reference/get-node-balancer-node) for a list of returned fields + - See the [Linode API response documentation](https://techdocs.akamai.com/linode-api/reference/get-node-balancer-config-nodes) for a list of returned fields -- `firewalls` - A list IDs for firewalls attached to this NodeBalancer. +- `firewalls` - The returned firewalls. - Sample Response: ```json @@ -131,3 +131,37 @@ Get info about a Linode NodeBalancer. - See the [Linode API response documentation](https://techdocs.akamai.com/linode-api/reference/get-node-balancer-firewalls) for a list of returned fields +- `firewalls_data` - The returned firewalls_data. + + - Sample Response: + ```json + [ + { + "created": "2020-04-10T13:34:00", + "entities": [ + { + "id": 1234, + "label": "example-label", + "type": "nodebalancer", + "url": "/v4/nodebalancers/1234" + } + ], + "id": 45678, + "label": "very-cool-label", + "rules": { + "fingerprint": "abcdefg", + "inbound": [], + "inbound_policy": "DROP", + "outbound": [], + "outbound_policy": "DROP", + "version": 1 + }, + "status": "enabled", + "tags": [], + "updated": "2020-04-10T13:34:01" + } + ] + ``` + - See the [Linode API response documentation](https://techdocs.akamai.com/linode-api/reference/get-node-balancer-firewalls) for a list of returned fields + + diff --git a/docs/modules/nodebalancer_list.md b/docs/modules/nodebalancer_list.md index 60853355..67cb2a28 100644 --- a/docs/modules/nodebalancer_list.md +++ b/docs/modules/nodebalancer_list.md @@ -1,6 +1,6 @@ # nodebalancer_list -List and filter on Nodebalancers. +List and filter on Node Balancers. - [Minimum Required Fields](#minimum-required-fields) - [Examples](#examples) @@ -32,21 +32,21 @@ List and filter on Nodebalancers. | Field | Type | Required | Description | |-----------|------|----------|------------------------------------------------------------------------------| -| `order` |
`str`
|
Optional
| The order to list nodebalancers in. **(Choices: `desc`, `asc`; Default: `asc`)** | -| `order_by` |
`str`
|
Optional
| The attribute to order nodebalancers by. | -| [`filters` (sub-options)](#filters) |
`list`
|
Optional
| A list of filters to apply to the resulting nodebalancers. | -| `count` |
`int`
|
Optional
| The number of results to return. If undefined, all results will be returned. | +| `order` |
`str`
|
Optional
| The order to list Node Balancers in. **(Choices: `desc`, `asc`; Default: `asc`)** | +| `order_by` |
`str`
|
Optional
| The attribute to order Node Balancers by. | +| [`filters` (sub-options)](#filters) |
`list`
|
Optional
| A list of filters to apply to the resulting Node Balancers. | +| `count` |
`int`
|
Optional
| The number of Node Balancers to return. If undefined, all results will be returned. | ### filters | Field | Type | Required | Description | |-----------|------|----------|------------------------------------------------------------------------------| -| `name` |
`str`
|
**Required**
| The name of the field to filter on. Valid filterable attributes can be found here: https://techdocs.akamai.com/linode-api/reference/get-node-balancers | +| `name` |
`str`
|
**Required**
| The name of the field to filter on. Valid filterable fields can be found [here](https://techdocs.akamai.com/linode-api/reference/get-node-balancers). | | `values` |
`list`
|
**Required**
| A list of values to allow for this field. Fields will pass this filter if at least one of these values matches. | ## Return Values -- `nodebalancers` - The returned nodebalancers. +- `nodebalancers` - The returned Node Balancers. - Sample Response: ```json diff --git a/docs/modules/nodebalancer_stats.md b/docs/modules/nodebalancer_stats.md index 7a1ae565..fcd344da 100644 --- a/docs/modules/nodebalancer_stats.md +++ b/docs/modules/nodebalancer_stats.md @@ -1,6 +1,6 @@ # nodebalancer_stats -View a Linode NodeBalancers Stats. +Get info about a Linode Node Balancer Stats. - [Minimum Required Fields](#minimum-required-fields) - [Examples](#examples) @@ -28,12 +28,12 @@ View a Linode NodeBalancers Stats. | Field | Type | Required | Description | |-----------|------|----------|------------------------------------------------------------------------------| -| `id` |
`int`
|
Optional
| The id of the nodebalancer for which the statistics apply to. **(Conflicts With: `label`)** | -| `label` |
`str`
|
Optional
| The label of the nodebalancer for which the statistics apply to. **(Conflicts With: `id`)** | +| `label` |
`str`
|
Optional
| The label of the Node Balancer Stats to resolve. **(Conflicts With: `id`)** | +| `id` |
`int`
|
Optional
| The ID of the Node Balancer Stats to resolve. **(Conflicts With: `label`)** | ## Return Values -- `node_balancer_stats` - The NodeBalancer Stats in JSON serialized form. +- `node_balancer_stats` - The returned Node Balancer Stats. - Sample Response: ```json diff --git a/docs/modules/placement_group.md b/docs/modules/placement_group.md index 92fb846f..b13b551c 100644 --- a/docs/modules/placement_group.md +++ b/docs/modules/placement_group.md @@ -82,6 +82,6 @@ NOTE: Placement Groups may not currently be available to all users. ] } ``` - - See the [Linode API response documentation](TBD) for a list of returned fields + - See the [Linode API response documentation](https://techdocs.akamai.com/linode-api/reference/get-placement-group) for a list of returned fields diff --git a/docs/modules/placement_group_assign.md b/docs/modules/placement_group_assign.md index 7c81dc16..fcdac1ed 100644 --- a/docs/modules/placement_group_assign.md +++ b/docs/modules/placement_group_assign.md @@ -40,7 +40,6 @@ NOTE: Placement Groups may not currently be available to all users. |-----------|------|----------|------------------------------------------------------------------------------| | `placement_group_id` |
`int`
|
**Required**
| The ID of the Placement Group for this assignment. | | `linode_id` |
`int`
|
**Required**
| The Linode ID to assign or unassign to the Placement Group. | -| `compliant_only` |
`bool`
|
Optional
| TODO | ## Return Values diff --git a/docs/modules/placement_group_info.md b/docs/modules/placement_group_info.md index 70f0b4c9..79799fa4 100644 --- a/docs/modules/placement_group_info.md +++ b/docs/modules/placement_group_info.md @@ -2,7 +2,7 @@ Get info about a Linode Placement Group. -**:warning: This module makes use of beta endpoints and requires the `api_version` field be explicitly set to `v4beta`.** +WARNING! This module makes use of beta endpoints and requires the C(api_version) field be explicitly set to C(v4beta). - [Minimum Required Fields](#minimum-required-fields) - [Examples](#examples) @@ -54,6 +54,6 @@ Get info about a Linode Placement Group. } ``` - - See the [Linode API response documentation](TBD) for a list of returned fields + - See the [Linode API response documentation](https://techdocs.akamai.com/linode-api/reference/get-placement-group) for a list of returned fields diff --git a/docs/modules/placement_group_list.md b/docs/modules/placement_group_list.md index 139334ac..8b74e292 100644 --- a/docs/modules/placement_group_list.md +++ b/docs/modules/placement_group_list.md @@ -2,7 +2,7 @@ List and filter on Placement Groups. -**:warning: This module makes use of beta endpoints and requires the `api_version` field be explicitly set to `v4beta`.** +WARNING! This module makes use of beta endpoints and requires the C(api_version) field be explicitly set to C(v4beta). - [Minimum Required Fields](#minimum-required-fields) - [Examples](#examples) @@ -36,7 +36,7 @@ List and filter on Placement Groups. | Field | Type | Required | Description | |-----------|------|----------|------------------------------------------------------------------------------| -| `name` |
`str`
|
**Required**
| The name of the field to filter on. Valid filterable fields can be found [here](TBD). | +| `name` |
`str`
|
**Required**
| The name of the field to filter on. Valid filterable fields can be found [here](https://techdocs.akamai.com/linode-api/reference/get-placement-groups). | | `values` |
`list`
|
**Required**
| A list of values to allow for this field. Fields will pass this filter if at least one of these values matches. | ## Return Values @@ -62,6 +62,6 @@ List and filter on Placement Groups. } ] ``` - - See the [Linode API response documentation](TBD) for a list of returned fields + - See the [Linode API response documentation](https://techdocs.akamai.com/linode-api/reference/get-placement-groups) for a list of returned fields diff --git a/docs/modules/profile_info.md b/docs/modules/profile_info.md index 436d1299..ebdcef6c 100644 --- a/docs/modules/profile_info.md +++ b/docs/modules/profile_info.md @@ -22,7 +22,7 @@ Get info about a Linode Profile. ## Return Values -- `profile` - The profile info in JSON serialized form. +- `profile` - The returned Profile. - Sample Response: ```json diff --git a/docs/modules/region_list.md b/docs/modules/region_list.md index c014b8ed..641f0515 100644 --- a/docs/modules/region_list.md +++ b/docs/modules/region_list.md @@ -1,6 +1,6 @@ # region_list -List and filter on Linode Regions. +List and filter on Regions. - [Minimum Required Fields](#minimum-required-fields) - [Examples](#examples) @@ -32,21 +32,21 @@ List and filter on Linode Regions. | Field | Type | Required | Description | |-----------|------|----------|------------------------------------------------------------------------------| -| `order` |
`str`
|
Optional
| The order to list regions in. **(Choices: `desc`, `asc`; Default: `asc`)** | -| `order_by` |
`str`
|
Optional
| The attribute to order regions by. | -| [`filters` (sub-options)](#filters) |
`list`
|
Optional
| A list of filters to apply to the resulting regions. | -| `count` |
`int`
|
Optional
| The number of results to return. If undefined, all results will be returned. | +| `order` |
`str`
|
Optional
| The order to list Regions in. **(Choices: `desc`, `asc`; Default: `asc`)** | +| `order_by` |
`str`
|
Optional
| The attribute to order Regions by. | +| [`filters` (sub-options)](#filters) |
`list`
|
Optional
| A list of filters to apply to the resulting Regions. | +| `count` |
`int`
|
Optional
| The number of Regions to return. If undefined, all results will be returned. | ### filters | Field | Type | Required | Description | |-----------|------|----------|------------------------------------------------------------------------------| -| `name` |
`str`
|
**Required**
| The name of the field to filter on. Valid filterable attributes can be found here: https://techdocs.akamai.com/linode-api/reference/get-regions | +| `name` |
`str`
|
**Required**
| The name of the field to filter on. Valid filterable fields can be found [here](https://techdocs.akamai.com/linode-api/reference/get-regions). | | `values` |
`list`
|
**Required**
| A list of values to allow for this field. Fields will pass this filter if at least one of these values matches. | ## Return Values -- `regions` - The returned regions. +- `regions` - The returned Regions. - Sample Response: ```json diff --git a/docs/modules/ssh_key.md b/docs/modules/ssh_key.md index 3d9755c1..a282e2b6 100644 --- a/docs/modules/ssh_key.md +++ b/docs/modules/ssh_key.md @@ -35,7 +35,7 @@ Manage a Linode SSH key. |-----------|------|----------|------------------------------------------------------------------------------| | `label` |
`str`
|
**Required**
| This SSH key's unique label. | | `state` |
`str`
|
**Required**
| The state of this SSH key. **(Choices: `present`, `absent`)** | -| `ssh_key` |
`str`
|
Optional
| The SSH public key value. **(Updatable)** | +| `ssh_key` |
`str`
|
Optional
| The SSH public key value. | ## Return Values diff --git a/docs/modules/type_list.md b/docs/modules/type_list.md index 58f90407..e6bf7fac 100644 --- a/docs/modules/type_list.md +++ b/docs/modules/type_list.md @@ -1,6 +1,6 @@ # type_list -List and filter on Linode Instance Types. +List and filter on Types. - [Minimum Required Fields](#minimum-required-fields) - [Examples](#examples) @@ -33,21 +33,21 @@ List and filter on Linode Instance Types. | Field | Type | Required | Description | |-----------|------|----------|------------------------------------------------------------------------------| -| `order` |
`str`
|
Optional
| The order to list Instance Types in. **(Choices: `desc`, `asc`; Default: `asc`)** | -| `order_by` |
`str`
|
Optional
| The attribute to order Instance Types by. | -| [`filters` (sub-options)](#filters) |
`list`
|
Optional
| A list of filters to apply to the resulting Instance Types. | -| `count` |
`int`
|
Optional
| The number of results to return. If undefined, all results will be returned. | +| `order` |
`str`
|
Optional
| The order to list Types in. **(Choices: `desc`, `asc`; Default: `asc`)** | +| `order_by` |
`str`
|
Optional
| The attribute to order Types by. | +| [`filters` (sub-options)](#filters) |
`list`
|
Optional
| A list of filters to apply to the resulting Types. | +| `count` |
`int`
|
Optional
| The number of Types to return. If undefined, all results will be returned. | ### filters | Field | Type | Required | Description | |-----------|------|----------|------------------------------------------------------------------------------| -| `name` |
`str`
|
**Required**
| The name of the field to filter on. Valid filterable attributes can be found here: https://techdocs.akamai.com/linode-api/reference/get-linode-types | +| `name` |
`str`
|
**Required**
| The name of the field to filter on. Valid filterable fields can be found [here](https://techdocs.akamai.com/linode-api/reference/get-linode-types). | | `values` |
`list`
|
**Required**
| A list of values to allow for this field. Fields will pass this filter if at least one of these values matches. | ## Return Values -- `types` - The returned Instance Types. +- `types` - The returned Types. - Sample Response: ```json diff --git a/docs/modules/user_info.md b/docs/modules/user_info.md index b4d1c1f2..2c57b4b3 100644 --- a/docs/modules/user_info.md +++ b/docs/modules/user_info.md @@ -25,11 +25,11 @@ Get info about a Linode User. | Field | Type | Required | Description | |-----------|------|----------|------------------------------------------------------------------------------| -| `username` |
`str`
|
**Required**
| The username of the user. | +| `username` |
`str`
|
**Required**
| The Username of the User to resolve. | ## Return Values -- `user` - The user info in JSON serialized form. +- `user` - The returned User. - Sample Response: ```json @@ -48,7 +48,7 @@ Get info about a Linode User. - See the [Linode API response documentation](https://techdocs.akamai.com/linode-api/reference/get-user) for a list of returned fields -- `grants` - The grants info in JSON serialized form. +- `grants` - The returned Grants. - Sample Response: ```json diff --git a/docs/modules/vlan_info.md b/docs/modules/vlan_info.md index e26ee87c..3d31800e 100644 --- a/docs/modules/vlan_info.md +++ b/docs/modules/vlan_info.md @@ -2,7 +2,7 @@ Get info about a Linode VLAN. -**:warning: This module makes use of beta endpoints and requires the `api_version` field be explicitly set to `v4beta`.** +WARNING! This module makes use of beta endpoints and requires the C(api_version) field be explicitly set to C(v4beta). - [Minimum Required Fields](#minimum-required-fields) - [Examples](#examples) diff --git a/docs/modules/vlan_list.md b/docs/modules/vlan_list.md index c2b676b3..893df5a1 100644 --- a/docs/modules/vlan_list.md +++ b/docs/modules/vlan_list.md @@ -2,7 +2,7 @@ List and filter on Linode VLANs. -**:warning: This module makes use of beta endpoints and requires the `api_version` field be explicitly set to `v4beta`.** +WARNING! This module makes use of beta endpoints and requires the C(api_version) field be explicitly set to C(v4beta). - [Minimum Required Fields](#minimum-required-fields) - [Examples](#examples) diff --git a/docs/modules/vpc.md b/docs/modules/vpc.md index e30c5228..9ec0a996 100644 --- a/docs/modules/vpc.md +++ b/docs/modules/vpc.md @@ -56,6 +56,6 @@ Create, read, and update a Linode VPC. "updated": "2023-08-31T18:35:03" } ``` - - See the [Linode API response documentation](TODO) for a list of returned fields + - See the [Linode API response documentation](https://techdocs.akamai.com/linode-api/reference/get-vpc) for a list of returned fields diff --git a/docs/modules/vpc_info.md b/docs/modules/vpc_info.md index b3caf931..985047fa 100644 --- a/docs/modules/vpc_info.md +++ b/docs/modules/vpc_info.md @@ -50,5 +50,6 @@ Get info about a Linode VPC. "updated": "2023-08-31T18:35:03" } ``` + - See the [Linode API response documentation](https://techdocs.akamai.com/linode-api/reference/get-vpc) for a list of returned fields diff --git a/docs/modules/vpc_ip_list.md b/docs/modules/vpc_ip_list.md index 9ca51294..859fd01e 100644 --- a/docs/modules/vpc_ip_list.md +++ b/docs/modules/vpc_ip_list.md @@ -35,7 +35,7 @@ List and filter on VPC IP Addresses. | Field | Type | Required | Description | |-----------|------|----------|------------------------------------------------------------------------------| -| `name` |
`str`
|
**Required**
| The name of the field to filter on. Valid filterable fields can be found [here](). | +| `name` |
`str`
|
**Required**
| The name of the field to filter on. Valid filterable fields can be found [here](https://techdocs.akamai.com/linode-api/reference/get-vpc-ips). | | `values` |
`list`
|
**Required**
| A list of values to allow for this field. Fields will pass this filter if at least one of these values matches. | ## Return Values @@ -62,5 +62,6 @@ List and filter on VPC IP Addresses. } ] ``` + - See the [Linode API response documentation](https://techdocs.akamai.com/linode-api/reference/get-vpc-ips) for a list of returned fields diff --git a/docs/modules/vpc_list.md b/docs/modules/vpc_list.md index 4016b9a5..1c6357cc 100644 --- a/docs/modules/vpc_list.md +++ b/docs/modules/vpc_list.md @@ -41,7 +41,7 @@ List and filter on VPCs. | Field | Type | Required | Description | |-----------|------|----------|------------------------------------------------------------------------------| -| `name` |
`str`
|
**Required**
| The name of the field to filter on. Valid filterable fields can be found [here](). | +| `name` |
`str`
|
**Required**
| The name of the field to filter on. Valid filterable fields can be found [here](https://techdocs.akamai.com/linode-api/reference/get-vpcs). | | `values` |
`list`
|
**Required**
| A list of values to allow for this field. Fields will pass this filter if at least one of these values matches. | ## Return Values @@ -62,5 +62,6 @@ List and filter on VPCs. } ] ``` + - See the [Linode API response documentation](https://techdocs.akamai.com/linode-api/reference/get-vpcs) for a list of returned fields diff --git a/docs/modules/vpc_subnet.md b/docs/modules/vpc_subnet.md index a81133d8..1d36de5b 100644 --- a/docs/modules/vpc_subnet.md +++ b/docs/modules/vpc_subnet.md @@ -61,6 +61,6 @@ Create, read, and update a Linode VPC Subnet. "updated": "2023-08-31T18:53:04" } ``` - - See the [Linode API response documentation](TODO) for a list of returned fields + - See the [Linode API response documentation](https://techdocs.akamai.com/linode-api/reference/get-vpc-subnet) for a list of returned fields diff --git a/docs/modules/vpc_subnet_info.md b/docs/modules/vpc_subnet_info.md index d55a690d..30d17bfd 100644 --- a/docs/modules/vpc_subnet_info.md +++ b/docs/modules/vpc_subnet_info.md @@ -57,5 +57,6 @@ Get info about a Linode VPC Subnet. "updated": "2023-08-31T18:53:04" } ``` + - See the [Linode API response documentation](https://techdocs.akamai.com/linode-api/reference/get-vpc-subnet) for a list of returned fields diff --git a/docs/modules/vpc_subnet_list.md b/docs/modules/vpc_subnet_list.md index 893db6d5..dc72a624 100644 --- a/docs/modules/vpc_subnet_list.md +++ b/docs/modules/vpc_subnet_list.md @@ -45,7 +45,7 @@ List and filter on VPC Subnets. | Field | Type | Required | Description | |-----------|------|----------|------------------------------------------------------------------------------| -| `name` |
`str`
|
**Required**
| The name of the field to filter on. Valid filterable fields can be found [here](). | +| `name` |
`str`
|
**Required**
| The name of the field to filter on. Valid filterable fields can be found [here](https://techdocs.akamai.com/linode-api/reference/get-vpc-subnets). | | `values` |
`list`
|
**Required**
| A list of values to allow for this field. Fields will pass this filter if at least one of these values matches. | ## Return Values @@ -70,5 +70,6 @@ List and filter on VPC Subnets. } ] ``` + - See the [Linode API response documentation](https://techdocs.akamai.com/linode-api/reference/get-vpc-subnets) for a list of returned fields diff --git a/docs/modules/vpcs_ip_list.md b/docs/modules/vpcs_ip_list.md index e994686d..af5cf5f1 100644 --- a/docs/modules/vpcs_ip_list.md +++ b/docs/modules/vpcs_ip_list.md @@ -33,7 +33,7 @@ List and filter on all VPC IP Addresses. | Field | Type | Required | Description | |-----------|------|----------|------------------------------------------------------------------------------| -| `name` |
`str`
|
**Required**
| The name of the field to filter on. Valid filterable fields can be found [here](). | +| `name` |
`str`
|
**Required**
| The name of the field to filter on. Valid filterable fields can be found [here](https://techdocs.akamai.com/linode-api/reference/get-vpcs-ips). | | `values` |
`list`
|
**Required**
| A list of values to allow for this field. Fields will pass this filter if at least one of these values matches. | ## Return Values @@ -61,5 +61,6 @@ List and filter on all VPC IP Addresses. } ] ``` + - See the [Linode API response documentation](https://techdocs.akamai.com/linode-api/reference/get-vpcs-ips) for a list of returned fields diff --git a/plugins/module_utils/doc_fragments/domain.py b/plugins/module_utils/doc_fragments/domain.py index b0f6ce55..18d1298c 100644 --- a/plugins/module_utils/doc_fragments/domain.py +++ b/plugins/module_utils/doc_fragments/domain.py @@ -49,17 +49,15 @@ } ]'''] -result_zone_file_samples = ['''[ - { - "zone_file": [ - "; example.com [123]", - "$TTL 864000", - "@ IN SOA ns1.linode.com. user.example.com. 2021000066 14400 14400 1209600 86400", - "@ NS ns1.linode.com.", - "@ NS ns2.linode.com.", - "@ NS ns3.linode.com.", - "@ NS ns4.linode.com.", - "@ NS ns5.linode.com." - ] - } -]'''] +result_zone_file_samples = ['''{ + "zone_file": [ + "; example.com [123]", + "$TTL 864000", + "@ IN SOA ns1.linode.com. user.example.com. 2021000066 14400 14400 1209600 86400", + "@ NS ns1.linode.com.", + "@ NS ns2.linode.com.", + "@ NS ns3.linode.com.", + "@ NS ns4.linode.com.", + "@ NS ns5.linode.com." + ] +}'''] diff --git a/plugins/module_utils/doc_fragments/domain_record.py b/plugins/module_utils/doc_fragments/domain_record.py index 9b898be9..8dcb7d31 100644 --- a/plugins/module_utils/doc_fragments/domain_record.py +++ b/plugins/module_utils/doc_fragments/domain_record.py @@ -8,6 +8,17 @@ type: 'A' target: '127.0.0.1' state: present''', ''' +- name: Create an SRV domain record + linode.cloud.domain_record: + domain: my-domain.com + service: srv-service + protocol: tcp + type: 'SRV' + target: host.example.com + port: 443 + priority: 0 + weight: 1 + state: present''', ''' - name: Delete a domain record linode.cloud.domain_record: domain: my-domain.com diff --git a/plugins/module_utils/doc_fragments/image.py b/plugins/module_utils/doc_fragments/image.py index daf80342..a6e70cb2 100644 --- a/plugins/module_utils/doc_fragments/image.py +++ b/plugins/module_utils/doc_fragments/image.py @@ -6,13 +6,28 @@ label: my-image description: Created using Ansible! disk_id: 12345 + tags: + - test state: present''', ''' - name: Create a basic image from a file linode.cloud.image: label: my-image description: Created using Ansible! source_file: myimage.img.gz + tags: + - test state: present''', ''' +- name: Replicate an image + linode.cloud.image: + label: my-image + description: Created using Ansible! + disk_id: 12345 + tags: + - test + replica_regions: + - us-east + - us-central + state: present''', ''' - name: Delete an image linode.cloud.image: label: my-image @@ -21,17 +36,29 @@ result_image_samples = ['''{ "capabilities": [], "created": "2021-08-14T22:44:02", - "created_by": "linode", + "created_by": "my-account", "deprecated": false, "description": "Example Image description.", "eol": "2026-07-01T04:00:00", "expiry": null, - "id": "linode/debian11", + "id": "private/123", "is_public": true, - "label": "Debian 11", + "label": "my-image", "size": 2500, "status": null, "type": "manual", "updated": "2021-08-14T22:44:02", - "vendor": "Debian" + "vendor": "Debian", + "tags": ["test"], + "total_size": 5000, + "regions": [ + { + "region": "us-east", + "status": "available" + }, + { + "region": "us-central", + "status": "pending" + } + ] }'''] diff --git a/plugins/module_utils/doc_fragments/image_list.py b/plugins/module_utils/doc_fragments/image_list.py index 9d9e2aa0..589d39c9 100644 --- a/plugins/module_utils/doc_fragments/image_list.py +++ b/plugins/module_utils/doc_fragments/image_list.py @@ -17,18 +17,29 @@ result_images_samples = ['''[ { "created":"2021-08-14T22:44:02", - "created_by":"linode", + "created_by":"my-account", "deprecated":false, "description":"Example Image description.", "eol":"2026-07-01T04:00:00", "expiry":null, - "id":"linode/debian11", - "is_public":true, - "label":"Debian 11", + "id":"private/123", + "is_public":false, + "label":"test", "size":2500, "status":null, "type":"manual", "updated":"2021-08-14T22:44:02", - "vendor":"Debian" - } + "vendor":"Debian", + "tags": ["test"], + "total_size": 5000, + "regions": [ + { + "region": "us-east", + "status": "available" + }, + { + "region": "us-central", + "status": "pending" + }] + } ]'''] diff --git a/plugins/module_utils/doc_fragments/nodebalancer.py b/plugins/module_utils/doc_fragments/nodebalancer.py index e0bf2dcc..aa6350e5 100644 --- a/plugins/module_utils/doc_fragments/nodebalancer.py +++ b/plugins/module_utils/doc_fragments/nodebalancer.py @@ -86,3 +86,30 @@ 1234, 5678 ]'''] + +result_firewalls_data_samples = ['''[ + { + "created": "2020-04-10T13:34:00", + "entities": [ + { + "id": 1234, + "label": "example-label", + "type": "nodebalancer", + "url": "/v4/nodebalancers/1234" + } + ], + "id": 45678, + "label": "very-cool-label", + "rules": { + "fingerprint": "abcdefg", + "inbound": [], + "inbound_policy": "DROP", + "outbound": [], + "outbound_policy": "DROP", + "version": 1 + }, + "status": "enabled", + "tags": [], + "updated": "2020-04-10T13:34:01" + } +]'''] diff --git a/plugins/module_utils/linode_common_info.py b/plugins/module_utils/linode_common_info.py index 36f01efc..709b5144 100644 --- a/plugins/module_utils/linode_common_info.py +++ b/plugins/module_utils/linode_common_info.py @@ -6,7 +6,8 @@ from __future__ import absolute_import, division, print_function from dataclasses import dataclass -from typing import Any, Callable, Dict, List, Optional +from enum import Enum +from typing import Any, Callable, Dict, List, Optional, Union from ansible_collections.linode.cloud.plugins.module_utils.linode_common import ( LinodeModuleBase, @@ -41,6 +42,28 @@ class InfoModuleParam: type: FieldType +class InfoModuleParamGroupPolicy(Enum): + """ + Defines the policies that can be set for a param group. + """ + + EXACTLY_ONE_OF = "exactly_one_of" + + +class InfoModuleParamGroup: + """ + A base class representing a group of InfoModuleParams. + """ + + def __init__( + self, + *param: InfoModuleParam, + policies: Optional[List[InfoModuleParamGroupPolicy]] = None, + ): + self.params = param + self.policies = policies or set() + + @dataclass class InfoModuleAttr: """ @@ -72,7 +95,8 @@ class InfoModuleResult: samples (Optional[List[str]]): A list of sample results for this field. get (Optional[Callable]): A function to call out to the API and return the data for this field. - NOTE: This is only relevant for secondary results. + NOTE: This is only relevant for secondary results + or primary result without any attributes. """ field_name: str @@ -82,7 +106,7 @@ class InfoModuleResult: docs_url: Optional[str] = None samples: Optional[List[str]] = None get: Optional[ - Callable[[LinodeClient, Dict[str, Any], Dict[str, Any]], Any] + Callable[[LinodeClient, Dict[str, Any], Optional[Dict[str, Any]]], Any] ] = None @@ -93,7 +117,9 @@ def __init__( self, primary_result: InfoModuleResult, secondary_results: List[InfoModuleResult] = None, - params: List[InfoModuleParam] = None, + params: Optional[ + List[Union[InfoModuleParam, InfoModuleParamGroup]] + ] = None, attributes: List[InfoModuleAttr] = None, examples: List[str] = None, description: List[str] = None, @@ -101,7 +127,6 @@ def __init__( ) -> None: self.primary_result = primary_result self.secondary_results = secondary_results or [] - self.params = params or [] self.attributes = attributes or [] self.examples = examples or [] self.description = description or [ @@ -109,6 +134,16 @@ def __init__( ] self.requires_beta = requires_beta + # Singular params should be translated into groups + self.param_groups = [ + ( + entry + if isinstance(entry, InfoModuleParamGroup) + else InfoModuleParamGroup(entry) + ) + for entry in params or [] + ] + self.module_arg_spec = self.spec.ansible_spec self.results: Dict[str, Any] = { k: None @@ -138,6 +173,16 @@ def exec_module(self, **kwargs: Any) -> Optional[dict]: ) break + if primary_result is None: + # Get the primary result using the result get function + try: + primary_result = self.primary_result.get(self.client, kwargs) + except Exception as exception: + self.fail( + msg="Failed to get result for " + f"{self.primary_result.display_name}: {exception}" + ) + if primary_result is None: raise ValueError("Expected a result; got None") @@ -172,12 +217,21 @@ def spec(self): } # Add params to spec - for param in self.params: - options[param.name] = SpecField( - type=param.type, - required=True, - description=f"The ID of the {param.display_name} for this resource.", - ) + for group in self.param_groups: + param_names = {param.name for param in group.params} + + for param in group.params: + param_spec = SpecField( + type=param.type, + required=True, + description=f"The ID of the {param.display_name} for this resource.", + ) + + if InfoModuleParamGroupPolicy.EXACTLY_ONE_OF in group.policies: + param_spec.conflicts_with = param_names ^ {param.name} + param_spec.required = False + + options[param.name] = param_spec # Add attrs to spec for attr in self.attributes: @@ -220,10 +274,22 @@ def run(self) -> None: """ Initializes and runs the info module. """ + base_module_args = { + "module_arg_spec": self.module_arg_spec, + "required_one_of": [], + "mutually_exclusive": [], + } + attribute_names = [v.name for v in self.attributes] - super().__init__( - module_arg_spec=self.module_arg_spec, - required_one_of=[attribute_names], - mutually_exclusive=[attribute_names], - ) + if len(attribute_names) > 0: + base_module_args["required_one_of"].append(attribute_names) + base_module_args["mutually_exclusive"].append(attribute_names) + + for entry in self.param_groups: + if InfoModuleParamGroupPolicy.EXACTLY_ONE_OF in entry.policies: + param_names = [param.name for param in entry.params] + base_module_args["required_one_of"].append(param_names) + base_module_args["mutually_exclusive"].append(param_names) + + super().__init__(**base_module_args) diff --git a/plugins/module_utils/linode_docs.py b/plugins/module_utils/linode_docs.py index bd8f3c5f..8e860f9e 100644 --- a/plugins/module_utils/linode_docs.py +++ b/plugins/module_utils/linode_docs.py @@ -6,11 +6,16 @@ "Phillip Campbell (@phillc)", "Lena Garber (@lbgarber)", "Jacob Riddle (@jriddle)", + "Zhiwei Liang (@zliang)", + "Ye Chen (@yechen)", + "Youjung Kim (@ykim)", + "Vinay Shanthegowda (@vshanthe)", + "Erik Zilber (@ezilber)", ] global_requirements = ["python >= 3"] BETA_DISCLAIMER = ( - "**:warning: This module makes use of beta endpoints and requires the `api_version` " - "field be explicitly set to `v4beta`.**" + "WARNING! This module makes use of beta endpoints and requires the C(api_version) " + "field be explicitly set to C(v4beta)." ) diff --git a/plugins/module_utils/linode_helper.py b/plugins/module_utils/linode_helper.py index 69dd8941..43124162 100644 --- a/plugins/module_utils/linode_helper.py +++ b/plugins/module_utils/linode_helper.py @@ -283,13 +283,13 @@ def get_all_paginated( result = [] current_page = 1 page_size = 100 - num_pages = 1 + num_pages: Optional[int] = None if num_results is not None and num_results < page_size: # Clamp the page size page_size = max(min(num_results, 100), 25) - while current_page <= num_pages and ( + while (num_pages is None or current_page <= num_pages) and ( num_results is None or len(result) < num_results ): response = client.get( @@ -300,6 +300,10 @@ def get_all_paginated( if "data" not in response or "page" not in response: raise Exception("Invalid list response") + # We only want to set num_pages once to avoid undefined behavior + # when the number of pages changes mid-aggregation + num_pages = num_pages or response["pages"] + result.extend(response["data"]) if num_results is not None and len(result) >= num_results: diff --git a/plugins/modules/account_availability_info.py b/plugins/modules/account_availability_info.py index 6fbbdb58..d8a20bfb 100644 --- a/plugins/modules/account_availability_info.py +++ b/plugins/modules/account_availability_info.py @@ -22,7 +22,7 @@ display_name="Account Availability", field_name="account_availability", field_type=FieldType.dict, - docs_url="TBD", + docs_url="https://techdocs.akamai.com/linode-api/reference/get-account-availability", samples=docs.result_account_availability_samples, ), attributes=[ diff --git a/plugins/modules/account_availability_list.py b/plugins/modules/account_availability_list.py index 6f777348..68c5177e 100644 --- a/plugins/modules/account_availability_list.py +++ b/plugins/modules/account_availability_list.py @@ -16,7 +16,7 @@ result_display_name="Account Availabilities", result_field_name="account_availabilities", endpoint_template="/account/availability", - result_docs_url="TBD", + result_docs_url="https://techdocs.akamai.com/linode-api/reference/get-account-availability", result_samples=docs.result_account_availabilities_samples, examples=docs.specdoc_examples, requires_beta=True, diff --git a/plugins/modules/account_info.py b/plugins/modules/account_info.py index e7add541..b48ac136 100644 --- a/plugins/modules/account_info.py +++ b/plugins/modules/account_info.py @@ -5,45 +5,27 @@ from __future__ import absolute_import, division, print_function -from typing import Any, List, Optional - import ansible_collections.linode.cloud.plugins.module_utils.doc_fragments.account_info as docs -from ansible_collections.linode.cloud.plugins.module_utils.linode_common import ( - LinodeModuleBase, -) -from ansible_collections.linode.cloud.plugins.module_utils.linode_docs import ( - global_authors, - global_requirements, +from ansible_collections.linode.cloud.plugins.module_utils.linode_common_info import ( + InfoModule, + InfoModuleResult, ) -from ansible_specdoc.objects import ( - FieldType, - SpecDocMeta, - SpecField, - SpecReturnValue, -) - -spec = { - # Disable the default values - "label": SpecField(type=FieldType.string, required=False, doc_hide=True), - "state": SpecField(type=FieldType.string, required=False, doc_hide=True), -} +from ansible_specdoc.objects import FieldType -SPECDOC_META = SpecDocMeta( - description=["Get info about a Linode Account."], - requirements=global_requirements, - author=global_authors, - options=spec, +module = InfoModule( examples=docs.specdoc_examples, - return_values={ - "account": SpecReturnValue( - description="The account info in JSON serialized form.", - docs_url="https://techdocs.akamai.com/linode-api/reference/get-account", - type=FieldType.dict, - sample=docs.result_account_samples, - ) - }, + primary_result=InfoModuleResult( + display_name="Account", + field_name="account", + field_type=FieldType.dict, + docs_url="https://techdocs.akamai.com/linode-api/reference/get-account", + samples=docs.result_account_samples, + get=lambda client, params: client.account()._raw_json, + ), ) +SPECDOC_META = module.spec + DOCUMENTATION = r""" """ EXAMPLES = r""" @@ -51,33 +33,5 @@ RETURN = r""" """ - -class Module(LinodeModuleBase): - """Module for getting info about a Linode Account""" - - def __init__(self) -> None: - self.required_one_of: List[str] = [] - self.results = {"account": None} - - self.module_arg_spec = SPECDOC_META.ansible_spec - - super().__init__( - module_arg_spec=self.module_arg_spec, - required_one_of=self.required_one_of, - ) - - def exec_module(self, **kwargs: Any) -> Optional[dict]: - """Entrypoint for volume info module""" - - self.results["account"] = self.client.account()._raw_json - - return self.results - - -def main() -> None: - """Constructs and calls the account_info module""" - Module() - - if __name__ == "__main__": - main() + module.run() diff --git a/plugins/modules/child_account_info.py b/plugins/modules/child_account_info.py index 321ca2f4..e47bd506 100644 --- a/plugins/modules/child_account_info.py +++ b/plugins/modules/child_account_info.py @@ -21,7 +21,7 @@ field_name="child_account", field_type=FieldType.dict, display_name="Child Account", - docs_url="", + docs_url="https://techdocs.akamai.com/linode-api/reference/get-child-account", samples=docs.result_child_account_samples, ), attributes=[ diff --git a/plugins/modules/child_account_list.py b/plugins/modules/child_account_list.py index cd1d49c8..f5851f96 100644 --- a/plugins/modules/child_account_list.py +++ b/plugins/modules/child_account_list.py @@ -18,7 +18,7 @@ result_display_name=RESULT_DISPLAY_NAME, result_field_name="child_accounts", endpoint_template="/account/child-accounts", - result_docs_url="", + result_docs_url="https://techdocs.akamai.com/linode-api/reference/get-child-accounts", examples=docs.specdoc_examples, result_samples=docs.result_child_accounts_samples, description=[ diff --git a/plugins/modules/domain.py b/plugins/modules/domain.py index 90a89239..ca46b6ac 100644 --- a/plugins/modules/domain.py +++ b/plugins/modules/domain.py @@ -154,7 +154,7 @@ "zone_file": SpecReturnValue( description="The zone file for the last rendered zone for the specified domain.", docs_url="https://techdocs.akamai.com/linode-api/reference/get-domain-zone", - type=FieldType.list, + type=FieldType.dict, sample=docs.result_zone_file_samples, ), }, diff --git a/plugins/modules/domain_info.py b/plugins/modules/domain_info.py index 919f5e23..010622e4 100644 --- a/plugins/modules/domain_info.py +++ b/plugins/modules/domain_info.py @@ -1,86 +1,79 @@ #!/usr/bin/python # -*- coding: utf-8 -*- -"""This module contains all of the functionality for Linode Domains.""" +"""This file contains the implementation of the domain_info module.""" from __future__ import absolute_import, division, print_function -from typing import Any, List, Optional - import ansible_collections.linode.cloud.plugins.module_utils.doc_fragments.domain as docs_parent import ansible_collections.linode.cloud.plugins.module_utils.doc_fragments.domain_info as docs -from ansible_collections.linode.cloud.plugins.module_utils.linode_common import ( - LinodeModuleBase, -) -from ansible_collections.linode.cloud.plugins.module_utils.linode_docs import ( - global_authors, - global_requirements, +from ansible_collections.linode.cloud.plugins.module_utils.linode_common_info import ( + InfoModule, + InfoModuleAttr, + InfoModuleResult, ) from ansible_collections.linode.cloud.plugins.module_utils.linode_helper import ( - create_filter_and, paginated_list_to_json, + safe_find, ) -from ansible_specdoc.objects import ( - FieldType, - SpecDocMeta, - SpecField, - SpecReturnValue, -) +from ansible_specdoc.objects import FieldType from linode_api4 import Domain -linode_domain_info_spec = { - # We need to overwrite attributes to exclude them as requirements - "state": SpecField(type=FieldType.string, required=False, doc_hide=True), - "label": SpecField(type=FieldType.string, required=False, doc_hide=True), - "id": SpecField( - type=FieldType.integer, - required=False, - conflicts_with=["domain"], - description=[ - "The unique domain name of the Domain.", - "Optional if `domain` is defined.", - ], - ), - "domain": SpecField( - type=FieldType.string, - required=False, - conflicts_with=["id"], - description=[ - "The unique id of the Domain.", - "Optional if `id` is defined.", - ], +module = InfoModule( + primary_result=InfoModuleResult( + field_name="domain", + field_type=FieldType.dict, + display_name="Domain", + docs_url="https://techdocs.akamai.com/linode-api/reference/get-domain", + samples=docs_parent.result_domain_samples, ), -} - -SPECDOC_META = SpecDocMeta( - description=["Get info about a Linode Domain."], - requirements=global_requirements, - author=global_authors, - options=linode_domain_info_spec, - examples=docs.specdoc_examples, - return_values={ - "domain": SpecReturnValue( - description="The domain in JSON serialized form.", - docs_url="https://techdocs.akamai.com/linode-api/reference/get-domain", - type=FieldType.dict, - sample=docs_parent.result_domain_samples, - ), - "records": SpecReturnValue( - description="The domain record in JSON serialized form.", - docs_url="https://techdocs.akamai.com/linode-api/reference/get-domain-record", - type=FieldType.list, - sample=docs_parent.result_records_samples, + secondary_results=[ + InfoModuleResult( + field_name="records", + field_type=FieldType.list, + display_name="records", + docs_url="https://techdocs.akamai.com/linode-api/reference/get-domain-records", + samples=docs_parent.result_records_samples, + get=lambda client, domain, params: paginated_list_to_json( + Domain(client, domain["id"]).records + ), ), - "zone_file": SpecReturnValue( - description="The zone file for the last rendered zone for the specified domain.", + InfoModuleResult( + field_name="zone_file", + field_type=FieldType.dict, + display_name="zone file", docs_url="https://techdocs.akamai.com/linode-api/reference/get-domain-zone", - type=FieldType.list, - sample=docs_parent.result_zone_file_samples, + samples=docs_parent.result_zone_file_samples, + get=lambda client, domain, params: { + "zone_file": Domain(client, domain["id"]).zone_file_view() + }, ), - }, + ], + attributes=[ + InfoModuleAttr( + display_name="ID", + name="id", + type=FieldType.integer, + get=lambda client, params: client.load( + Domain, + params.get("id"), + )._raw_json, + ), + InfoModuleAttr( + display_name="domain", + name="domain", + type=FieldType.string, + get=lambda client, params: safe_find( + client.domains, + Domain.domain == params.get("domain"), + raise_not_found=True, + )._raw_json, + ), + ], + examples=docs.specdoc_examples, ) -linode_domain_valid_filters = ["id", "domain"] +SPECDOC_META = module.spec DOCUMENTATION = r""" """ @@ -89,64 +82,5 @@ RETURN = r""" """ - -class LinodeDomainInfo(LinodeModuleBase): - """Module for getting info about a Linode Domain""" - - def __init__(self) -> None: - self.module_arg_spec = SPECDOC_META.ansible_spec - self.required_one_of: List[str] = [] - self.results = {"domain": None, "records": None, "zone_file": None} - - super().__init__( - module_arg_spec=self.module_arg_spec, - required_one_of=self.required_one_of, - ) - - def _get_matching_domain(self, spec_args: dict) -> Optional[Domain]: - filter_items = { - k: v - for k, v in spec_args.items() - if k in linode_domain_valid_filters and v is not None - } - - filter_statement = create_filter_and(Domain, filter_items) - - try: - # Special case because ID is not filterable - if "id" in filter_items.keys(): - result = Domain(self.client, spec_args.get("id")) - result._api_get() # Force lazy-loading - - return result - - return self.client.domains(filter_statement)[0] - except IndexError: - return None - except Exception as exception: - return self.fail(msg="failed to get domain {0}".format(exception)) - - def exec_module(self, **kwargs: Any) -> Optional[dict]: - """Entrypoint for domain info module""" - - domain = self._get_matching_domain(kwargs) - - if domain is None: - self.fail("failed to get domain") - - self.results["domain"] = domain._raw_json - self.results["records"] = paginated_list_to_json(domain.records) - self.results["zone_file"] = self.client.get( - "/domains/{}/zone-file".format(domain.id) - ) - - return self.results - - -def main() -> None: - """Constructs and calls the Linode Domain info module""" - LinodeDomainInfo() - - if __name__ == "__main__": - main() + module.run() diff --git a/plugins/modules/domain_list.py b/plugins/modules/domain_list.py index 2a18b73a..6f0ef311 100644 --- a/plugins/modules/domain_list.py +++ b/plugins/modules/domain_list.py @@ -1,96 +1,26 @@ +#!/usr/bin/python # -*- coding: utf-8 -*- -"""This module allows users to list Domains.""" -from __future__ import absolute_import, division, print_function +"""This file contains the implementation of the domain_list module.""" -from typing import Any, Dict, Optional +from __future__ import absolute_import, division, print_function import ansible_collections.linode.cloud.plugins.module_utils.doc_fragments.domain_list as docs -from ansible_collections.linode.cloud.plugins.module_utils.linode_common import ( - LinodeModuleBase, -) -from ansible_collections.linode.cloud.plugins.module_utils.linode_docs import ( - global_authors, - global_requirements, -) -from ansible_collections.linode.cloud.plugins.module_utils.linode_helper import ( - construct_api_filter, - get_all_paginated, -) -from ansible_specdoc.objects import ( - FieldType, - SpecDocMeta, - SpecField, - SpecReturnValue, +from ansible_collections.linode.cloud.plugins.module_utils.linode_common_list import ( + ListModule, ) -spec_filter = { - "name": SpecField( - type=FieldType.string, - required=True, - description=[ - "The name of the field to filter on.", - "Valid filterable attributes can be found here: " - "https://techdocs.akamai.com/linode-api/reference/get-domains", - ], - ), - "values": SpecField( - type=FieldType.list, - element_type=FieldType.string, - required=True, - description=[ - "A list of values to allow for this field.", - "Fields will pass this filter if at least one of these values matches.", - ], - ), -} - -spec = { - # Disable the default values - "state": SpecField(type=FieldType.string, required=False, doc_hide=True), - "label": SpecField(type=FieldType.string, required=False, doc_hide=True), - "order": SpecField( - type=FieldType.string, - description=["The order to list domains in."], - default="asc", - choices=["desc", "asc"], - ), - "order_by": SpecField( - type=FieldType.string, - description=["The attribute to order domains by."], - ), - "filters": SpecField( - type=FieldType.list, - element_type=FieldType.dict, - suboptions=spec_filter, - description=["A list of filters to apply to the resulting domains."], - ), - "count": SpecField( - type=FieldType.integer, - description=[ - "The number of results to return.", - "If undefined, all results will be returned.", - ], - ), -} - -SPECDOC_META = SpecDocMeta( - description=["List and filter on Domains."], - requirements=global_requirements, - author=global_authors, - options=spec, +module = ListModule( + result_display_name="Domains", + result_field_name="domains", + endpoint_template="/domains", + result_docs_url="https://techdocs.akamai.com/linode-api/reference/get-domains", examples=docs.specdoc_examples, - return_values={ - "domains": SpecReturnValue( - description="The returned domains.", - docs_url="https://techdocs.akamai.com/linode-api/reference/get-domains", - type=FieldType.list, - elements=FieldType.dict, - sample=docs.result_domains_samples, - ) - }, + result_samples=docs.result_domains_samples, ) +SPECDOC_META = module.spec + DOCUMENTATION = r""" """ EXAMPLES = r""" @@ -98,34 +28,5 @@ RETURN = r""" """ - -class Module(LinodeModuleBase): - """Module for getting a list of domains""" - - def __init__(self) -> None: - self.module_arg_spec = SPECDOC_META.ansible_spec - self.results: Dict[str, Any] = {"domains": []} - - super().__init__(module_arg_spec=self.module_arg_spec) - - def exec_module(self, **kwargs: Any) -> Optional[dict]: - """Entrypoint for domain list module""" - - filter_dict = construct_api_filter(self.module.params) - - self.results["domains"] = get_all_paginated( - self.client, - "/domains", - filter_dict, - num_results=self.module.params["count"], - ) - return self.results - - -def main() -> None: - """Constructs and calls the module""" - Module() - - if __name__ == "__main__": - main() + module.run() diff --git a/plugins/modules/domain_record.py b/plugins/modules/domain_record.py index 65be32d2..afa6a794 100644 --- a/plugins/modules/domain_record.py +++ b/plugins/modules/domain_record.py @@ -47,7 +47,9 @@ description=[ "The name of this Record.", "NOTE: If the name of the record ends with the domain, " - "it will be dropped from the resulting record's name.", + "it will be dropped from the resulting record's name. " + "Unused for SRV record. " + "Use the service property to set the service name for this record.", ], ), "port": SpecField( @@ -173,10 +175,9 @@ def __init__(self) -> None: self.module_arg_spec = SPECDOC_META.ansible_spec self.required_one_of: List[List[str]] = [ ["domain", "domain_id"], - ["name", "record_id"], + ["name", "record_id", "service"], ] self.mutually_exclusive: List[List[str]] = [["name", "record_id"]] - self.required_together: List[List[str]] = [["name", "type"]] self.results = {"changed": False, "actions": [], "record": None} self._domain: Optional[Domain] = None @@ -186,7 +187,6 @@ def __init__(self) -> None: module_arg_spec=self.module_arg_spec, required_one_of=self.required_one_of, mutually_exclusive=self.mutually_exclusive, - required_together=self.required_together, ) def _find_record( @@ -267,10 +267,13 @@ def _create_record(self) -> Optional[DomainRecord]: params = self.module.params record_type = params.pop("type") record_name = params.get("name") + record_service = params.get("service") try: self.register_action( - "Created domain record {0}".format(record_name) + "Created domain record type {0}: name is {1}; service is {2}".format( + record_type, record_name, record_service + ) ) return self._domain.record_create(record_type, **params) except Exception as exception: @@ -306,7 +309,9 @@ def _handle_present(self) -> None: "record with id {0} does not exist".format(record_id) ) - if self._record is None and record_name is not None: + if self._record is None and ( + record_name is not None or params.get("service") is not None + ): self._record = self._create_record() self._update_record() diff --git a/plugins/modules/domain_record_info.py b/plugins/modules/domain_record_info.py index 23bdfb7b..133236f4 100644 --- a/plugins/modules/domain_record_info.py +++ b/plugins/modules/domain_record_info.py @@ -5,7 +5,7 @@ from __future__ import absolute_import, division, print_function -from typing import Any, Dict, List, Optional +from typing import Any, Dict from ansible_collections.linode.cloud.plugins.module_utils.doc_fragments import ( domain_record as docs_parent, @@ -13,78 +13,87 @@ from ansible_collections.linode.cloud.plugins.module_utils.doc_fragments import ( domain_record_info as docs, ) -from ansible_collections.linode.cloud.plugins.module_utils.linode_common import ( - LinodeModuleBase, +from ansible_collections.linode.cloud.plugins.module_utils.linode_common_info import ( + InfoModule, + InfoModuleAttr, + InfoModuleParam, + InfoModuleParamGroup, + InfoModuleParamGroupPolicy, + InfoModuleResult, ) -from ansible_collections.linode.cloud.plugins.module_utils.linode_docs import ( - global_authors, - global_requirements, -) -from ansible_collections.linode.cloud.plugins.module_utils.linode_helper import ( - paginated_list_to_json, -) -from ansible_specdoc.objects import ( - FieldType, - SpecDocMeta, - SpecField, - SpecReturnValue, -) -from linode_api4 import Domain, DomainRecord +from ansible_specdoc.objects import FieldType +from linode_api4 import Domain, DomainRecord, LinodeClient -linode_domain_record_info_spec = { - # We need to overwrite attributes to exclude them as requirements - "state": SpecField(type=FieldType.string, required=False, doc_hide=True), - "label": SpecField(type=FieldType.string, required=False, doc_hide=True), - "domain_id": SpecField( - type=FieldType.integer, - conflicts_with=["domain"], - description=[ - "The ID of the parent Domain.", - "Optional if `domain` is defined.", - ], - ), - "domain": SpecField( - type=FieldType.string, - conflicts_with=["domain_id"], - description=[ - "The name of the parent Domain.", - "Optional if `domain_id` is defined.", - ], - ), - "id": SpecField( - type=FieldType.integer, - conflicts_with=["name"], - description=[ - "The unique id of the subdomain.", - "Optional if `name` is defined.", - ], - ), - "name": SpecField( - type=FieldType.string, - conflicts_with=["id"], - description=[ - "The name of the domain record.", - "Optional if `id` is defined.", - ], - ), -} -SPECDOC_META = SpecDocMeta( - description=["Get info about a Linode Domain Record."], - requirements=global_requirements, - author=global_authors, - options=linode_domain_record_info_spec, - examples=docs.specdoc_examples, - return_values={ - "record": SpecReturnValue( - description="View a single Record on this Domain.", - docs_url="https://techdocs.akamai.com/linode-api/reference/get-domain-record", - type=FieldType.dict, - sample=docs_parent.result_record_samples, +def _domain_from_params(client: LinodeClient, params: Dict[str, Any]) -> Domain: + domain_id = params.get("domain_id", None) + domain = params.get("domain", None) + + if domain_id is not None: + return Domain(client, domain_id) + + if domain is not None: + target_domains = client.domains(Domain.domain == domain) + if len(target_domains) < 1: + raise ValueError(f"No domain with name {domain} found") + + return target_domains[0] + + raise ValueError("One of domain_id or domain must be specified") + + +module = InfoModule( + primary_result=InfoModuleResult( + field_name="record", + field_type=FieldType.dict, + display_name="Domain Records", + docs_url="https://techdocs.akamai.com/linode-api/reference/get-domain-record", + samples=docs_parent.result_record_samples, + ), + params=[ + InfoModuleParamGroup( + InfoModuleParam( + display_name="Domain ID", + name="domain_id", + type=FieldType.integer, + ), + InfoModuleParam( + display_name="Domain", + name="domain", + type=FieldType.string, + ), + policies=[InfoModuleParamGroupPolicy.EXACTLY_ONE_OF], ) - }, + ], + attributes=[ + InfoModuleAttr( + display_name="ID", + name="id", + type=FieldType.integer, + get=lambda client, params: [ + client.load( + DomainRecord, + params.get("id"), + target_parent_id=_domain_from_params(client, params).id, + )._raw_json + ], + ), + InfoModuleAttr( + display_name="name", + name="name", + type=FieldType.string, + get=lambda client, params: [ + record._raw_json + for record in _domain_from_params(client, params).records + if record.name == params.get("name") + ], + ), + ], + examples=docs.specdoc_examples, ) +SPECDOC_META = module.spec + DOCUMENTATION = r""" """ EXAMPLES = r""" @@ -92,102 +101,5 @@ RETURN = r""" """ - -class LinodeDomainRecordInfo(LinodeModuleBase): - """Module for getting info about a Linode Domain record""" - - def __init__(self) -> None: - self.module_arg_spec = SPECDOC_META.ansible_spec - self.required_one_of: List[List[str]] = [ - ["domain_id", "domain"], - ["id", "name"], - ] - self.results: Dict[Any, Any] = {"records": []} - - super().__init__( - module_arg_spec=self.module_arg_spec, - required_one_of=self.required_one_of, - ) - - def _get_domain_by_name(self, name: str) -> Optional[Domain]: - try: - domain = self.client.domains(Domain.domain == name)[0] - return domain - except IndexError: - return None - except Exception as exception: - return self.fail( - msg="failed to get domain {0}: {1}".format(name, exception) - ) - - def _get_domain_from_params(self) -> Optional[Domain]: - domain_id = self.module.params.get("domain_id") - domain = self.module.params.get("domain") - - if domain is not None: - return self._get_domain_by_name(domain) - - if domain_id is not None: - result = Domain(self.client, domain_id) - result._api_get() - return result - - return None - - def _get_records_by_name( - self, domain: Domain, name: str - ) -> Optional[List[DomainRecord]]: - try: - result = [] - - for record in domain.records: - if record.name == name: - result.append(record) - - return result - except IndexError: - return [] - except Exception as exception: - return self.fail( - msg="failed to get domain record {0}: {1}".format( - name, exception - ) - ) - - def _get_records_from_params(self, domain: Domain) -> List[DomainRecord]: - record_id = self.module.params.get("id") - record_name = self.module.params.get("name") - - if record_name is not None: - return self._get_records_by_name(domain, record_name) - - if record_id is not None: - result = DomainRecord(self.client, record_id, domain.id) - result._api_get() - return [result] - - return [] - - def exec_module(self, **kwargs: Any) -> Optional[dict]: - """Entrypoint for domain record info module""" - - domain = self._get_domain_from_params() - if domain is None: - return self.fail("failed to get domain") - - records = self._get_records_from_params(domain) - if records is None: - return self.fail("failed to get records") - - self.results["record"] = paginated_list_to_json(records) - - return self.results - - -def main() -> None: - """Constructs and calls the Linode Domain Record info module""" - LinodeDomainRecordInfo() - - if __name__ == "__main__": - main() + module.run() diff --git a/plugins/modules/event_list.py b/plugins/modules/event_list.py index fcd1e61f..f79c1552 100644 --- a/plugins/modules/event_list.py +++ b/plugins/modules/event_list.py @@ -1,97 +1,26 @@ #!/usr/bin/python # -*- coding: utf-8 -*- -"""This module allows users to list Linode events.""" +"""This file contains the implementation of the event_list module.""" from __future__ import absolute_import, division, print_function -from typing import Any, Dict, Optional - import ansible_collections.linode.cloud.plugins.module_utils.doc_fragments.event_list as docs -from ansible_collections.linode.cloud.plugins.module_utils.linode_common import ( - LinodeModuleBase, -) -from ansible_collections.linode.cloud.plugins.module_utils.linode_docs import ( - global_authors, - global_requirements, -) -from ansible_collections.linode.cloud.plugins.module_utils.linode_helper import ( - construct_api_filter, - get_all_paginated, +from ansible_collections.linode.cloud.plugins.module_utils.linode_common_list import ( + ListModule, ) -from ansible_specdoc.objects import ( - FieldType, - SpecDocMeta, - SpecField, - SpecReturnValue, -) - -spec_filter = { - "name": SpecField( - type=FieldType.string, - required=True, - description=[ - "The name of the field to filter on.", - "Valid filterable attributes can be found here: " - "https://techdocs.akamai.com/linode-api/reference/get-events", - ], - ), - "values": SpecField( - type=FieldType.list, - element_type=FieldType.string, - required=True, - description=[ - "A list of values to allow for this field.", - "Fields will pass this filter if at least one of these values matches.", - ], - ), -} -spec = { - # Disable the default values - "state": SpecField(type=FieldType.string, required=False, doc_hide=True), - "label": SpecField(type=FieldType.string, required=False, doc_hide=True), - "order": SpecField( - type=FieldType.string, - description=["The order to list events in."], - default="asc", - choices=["desc", "asc"], - ), - "order_by": SpecField( - type=FieldType.string, description=["The attribute to order events by."] - ), - "filters": SpecField( - type=FieldType.list, - element_type=FieldType.dict, - suboptions=spec_filter, - description=["A list of filters to apply to the resulting events."], - ), - "count": SpecField( - type=FieldType.integer, - description=[ - "The number of results to return.", - "If undefined, all results will be returned.", - ], - ), -} - -SPECDOC_META = SpecDocMeta( - description=["List and filter on Linode events."], - requirements=global_requirements, - author=global_authors, - options=spec, +module = ListModule( + result_display_name="Events", + result_field_name="events", + endpoint_template="/account/events", + result_docs_url="https://techdocs.akamai.com/linode-api/reference/get-events", examples=docs.specdoc_examples, - return_values={ - "events": SpecReturnValue( - description="The returned events.", - docs_url="https://techdocs.akamai.com/linode-api/reference/get-events", - type=FieldType.list, - elements=FieldType.dict, - sample=docs.result_events_samples, - ) - }, + result_samples=docs.result_events_samples, ) +SPECDOC_META = module.spec + DOCUMENTATION = r""" """ EXAMPLES = r""" @@ -99,34 +28,5 @@ RETURN = r""" """ - -class Module(LinodeModuleBase): - """Module for getting info about a Linode events""" - - def __init__(self) -> None: - self.module_arg_spec = SPECDOC_META.ansible_spec - self.results: Dict[str, Any] = {"events": []} - - super().__init__(module_arg_spec=self.module_arg_spec) - - def exec_module(self, **kwargs: Any) -> Optional[dict]: - """Entrypoint for event list module""" - - filter_dict = construct_api_filter(self.module.params) - - self.results["events"] = get_all_paginated( - self.client, - "/account/events", - filter_dict, - num_results=self.module.params["count"], - ) - return self.results - - -def main() -> None: - """Constructs and calls the module""" - Module() - - if __name__ == "__main__": - main() + module.run() diff --git a/plugins/modules/image.py b/plugins/modules/image.py index c59ea959..7a34c7c5 100644 --- a/plugins/modules/image.py +++ b/plugins/modules/image.py @@ -89,6 +89,31 @@ "have status `available`." ], ), + "tags": SpecField( + type=FieldType.list, + element_type=FieldType.string, + editable=True, + description=["A list of customized tags of this new Image."], + ), + # `regions` send to API for image replication + "replica_regions": SpecField( + type=FieldType.list, + element_type=FieldType.string, + editable=True, + description=[ + "A list of regions that customer wants to replicate this image in. " + "At least one available region must be provided and only core regions allowed. " + "Existing images in the regions not passed will be removed. " + "NOTE: Image replication may not currently be available to all users.", + ], + ), + "wait_for_replications": SpecField( + type=FieldType.bool, + default=False, + description=[ + "Wait for the all the replications `available` before returning." + ], + ), } SPECDOC_META = SpecDocMeta( @@ -107,7 +132,7 @@ }, ) -MUTABLE_FIELDS = {"description"} +MUTABLE_FIELDS = {"description", "tags"} DOCUMENTATION = r""" """ @@ -165,11 +190,38 @@ def poll_func() -> bool: except polling.TimeoutException: self.fail("failed to wait for image status: timeout period expired") + def _wait_for_image_replication_status( + self, image: Image, status: Set[str] + ) -> None: + def poll_func() -> bool: + image._api_get() + for region in image.regions: + if region.status not in status: + return False + + return True + + # Initial attempt + if poll_func(): + return + + try: + polling.poll( + poll_func, + step=10, + timeout=self._timeout_ctx.seconds_remaining, + ) + except polling.TimeoutException: + self.fail( + "failed to wait for image replication status: timeout period expired" + ) + def _create_image_from_disk(self) -> Optional[Image]: disk_id = self.module.params.get("disk_id") label = self.module.params.get("label") description = self.module.params.get("description") cloud_init = self.module.params.get("cloud_init") + tags = self.module.params.get("tags") try: return self.client.images.create( @@ -177,6 +229,7 @@ def _create_image_from_disk(self) -> Optional[Image]: label=label, description=description, cloud_init=cloud_init, + tags=tags, ) except Exception as exception: return self.fail( @@ -189,6 +242,7 @@ def _create_image_from_file(self) -> Optional[Image]: region = self.module.params.get("region") source_file = self.module.params.get("source_file") cloud_init = self.module.params.get("cloud_init") + tags = self.module.params.get("tags") if not os.path.exists(source_file): return self.fail( @@ -198,7 +252,11 @@ def _create_image_from_file(self) -> Optional[Image]: # Create an image upload try: image, upload_to = self.client.images.create_upload( - label, region, description=description, cloud_init=cloud_init + label, + region, + description=description, + cloud_init=cloud_init, + tags=tags, ) except Exception as exception: return self.fail( @@ -260,6 +318,30 @@ def _handle_present(self) -> None: self._update_image(image) + replica_regions = params.get("replica_regions") + new_regions: list = [] if replica_regions is None else replica_regions + old_regions = [r.region for r in image.regions] + + # Replicate image in new regions + if replica_regions is not None and new_regions != old_regions: + if len(new_regions) == 0 or ( + not set(new_regions) & set(old_regions) + ): + return self.fail( + msg="failed to replicate image {0}: replica_regions value {1} is invalid. " + "At least one available region must be provided.".format( + label, new_regions + ) + ) + + image.replicate(new_regions) + self.register_action( + "Replicated image {0} in regions {1}".format(label, new_regions) + ) + + if params.get("wait_for_replications"): + self._wait_for_image_replication_status(image, {"available"}) + # Force lazy-loading image._api_get() diff --git a/plugins/modules/image_info.py b/plugins/modules/image_info.py index db2ab5a0..4902eb74 100644 --- a/plugins/modules/image_info.py +++ b/plugins/modules/image_info.py @@ -5,118 +5,51 @@ from __future__ import absolute_import, division, print_function -from typing import Any, Optional - import ansible_collections.linode.cloud.plugins.module_utils.doc_fragments.image as docs_parent import ansible_collections.linode.cloud.plugins.module_utils.doc_fragments.image_info as docs -from ansible_collections.linode.cloud.plugins.module_utils.linode_common import ( - LinodeModuleBase, -) -from ansible_collections.linode.cloud.plugins.module_utils.linode_docs import ( - global_authors, - global_requirements, +from ansible_collections.linode.cloud.plugins.module_utils.linode_common_info import ( + InfoModule, + InfoModuleAttr, + InfoModuleResult, ) from ansible_collections.linode.cloud.plugins.module_utils.linode_helper import ( - filter_null_values, -) -from ansible_specdoc.objects import ( - FieldType, - SpecDocMeta, - SpecField, - SpecReturnValue, + safe_find, ) +from ansible_specdoc.objects import FieldType from linode_api4 import Image -spec = { - # Disable the default values - "state": SpecField(type=FieldType.string, required=False, doc_hide=True), - "id": SpecField( - type=FieldType.string, - description=["The ID of the image."], - conflicts_with=["label"], - ), - "label": SpecField( - type=FieldType.string, - description=["The label of the image."], - conflicts_with=["id"], - ), -} - -SPECDOC_META = SpecDocMeta( - description=["Get info about a Linode Image."], - requirements=global_requirements, - author=global_authors, - options=spec, +module = InfoModule( examples=docs.specdoc_examples, - return_values={ - "image": SpecReturnValue( - description="The image in JSON serialized form.", - docs_url="https://techdocs.akamai.com/linode-api/reference/get-image", - type=FieldType.dict, - sample=docs_parent.result_image_samples, - ) - }, + primary_result=InfoModuleResult( + display_name="Image", + field_name="image", + field_type=FieldType.dict, + docs_url="https://techdocs.akamai.com/linode-api/reference/get-image", + samples=docs_parent.result_image_samples, + ), + attributes=[ + InfoModuleAttr( + name="id", + display_name="ID", + type=FieldType.string, + get=lambda client, params: client.load( + Image, params.get("id") + )._raw_json, + ), + InfoModuleAttr( + name="label", + display_name="label", + type=FieldType.string, + get=lambda client, params: safe_find( + client.images, + Image.label == params.get("label"), + raise_not_found=True, + )._raw_json, + ), + ], ) -DOCUMENTATION = r""" -""" -EXAMPLES = r""" -""" -RETURN = r""" -""" - - -class Module(LinodeModuleBase): - """Module for getting info about a Linode user""" - - def __init__(self) -> None: - self.module_arg_spec = SPECDOC_META.ansible_spec - self.results = {"image": None} - - super().__init__( - module_arg_spec=self.module_arg_spec, - required_one_of=[("id", "label")], - mutually_exclusive=[("id", "label")], - ) - - def _get_image_by_label(self, label: str) -> Optional[Image]: - try: - return self.client.images(Image.label == label)[0] - except IndexError: - return self.fail( - msg="failed to get image with label {0}: " - "image does not exist".format(label) - ) - except Exception as exception: - return self.fail( - msg="failed to get image {0}: {1}".format(label, exception) - ) - - def _get_image_by_id(self, image_id: int) -> Image: - return self._get_resource_by_id(Image, image_id) - - def exec_module(self, **kwargs: Any) -> Optional[dict]: - """Entrypoint for user info module""" - - params = filter_null_values(self.module.params) - - if "id" in params: - self.results["image"] = self._get_image_by_id( - params.get("id") - )._raw_json - - if "label" in params: - self.results["image"] = self._get_image_by_label( - params.get("label") - )._raw_json - - return self.results - - -def main() -> None: - """Constructs and calls the module""" - Module() - +SPECDOC_META = module.spec if __name__ == "__main__": - main() + module.run() diff --git a/plugins/modules/instance.py b/plugins/modules/instance.py index 2d5bb19d..eeb38bc6 100644 --- a/plugins/modules/instance.py +++ b/plugins/modules/instance.py @@ -523,6 +523,13 @@ suboptions=linode_instance_placement_group_spec, description=["A Placement Group to create this Linode under."], ), + "swap_size": SpecField( + type=FieldType.integer, + description=[ + "When deploying from an Image, this field is optional, otherwise it is ignored. " + "This is used to set the swap disk size for the newly-created Linode." + ], + ), } SPECDOC_META = SpecDocMeta( diff --git a/plugins/modules/instance_list.py b/plugins/modules/instance_list.py index cf174d72..3577c29b 100644 --- a/plugins/modules/instance_list.py +++ b/plugins/modules/instance_list.py @@ -4,94 +4,22 @@ """This module allows users to list Linode instances.""" from __future__ import absolute_import, division, print_function -from typing import Any, Dict, Optional - import ansible_collections.linode.cloud.plugins.module_utils.doc_fragments.instance_list as docs -from ansible_collections.linode.cloud.plugins.module_utils.linode_common import ( - LinodeModuleBase, -) -from ansible_collections.linode.cloud.plugins.module_utils.linode_docs import ( - global_authors, - global_requirements, -) -from ansible_collections.linode.cloud.plugins.module_utils.linode_helper import ( - construct_api_filter, - get_all_paginated, +from ansible_collections.linode.cloud.plugins.module_utils.linode_common_list import ( + ListModule, ) -from ansible_specdoc.objects import ( - FieldType, - SpecDocMeta, - SpecField, - SpecReturnValue, -) - -spec_filter = { - "name": SpecField( - type=FieldType.string, - required=True, - description=[ - "The name of the field to filter on.", - "Valid filterable attributes can be found here: " - "https://techdocs.akamai.com/linode-api/reference/get-linode-instances", - ], - ), - "values": SpecField( - type=FieldType.list, - element_type=FieldType.string, - required=True, - description=[ - "A list of values to allow for this field.", - "Fields will pass this filter if at least one of these values matches.", - ], - ), -} -spec = { - # Disable the default values - "state": SpecField(type=FieldType.string, required=False, doc_hide=True), - "label": SpecField(type=FieldType.string, required=False, doc_hide=True), - "order": SpecField( - type=FieldType.string, - description=["The order to list instances in."], - default="asc", - choices=["desc", "asc"], - ), - "order_by": SpecField( - type=FieldType.string, - description=["The attribute to order instances by."], - ), - "filters": SpecField( - type=FieldType.list, - element_type=FieldType.dict, - suboptions=spec_filter, - description=["A list of filters to apply to the resulting instances."], - ), - "count": SpecField( - type=FieldType.integer, - description=[ - "The number of results to return.", - "If undefined, all results will be returned.", - ], - ), -} - -SPECDOC_META = SpecDocMeta( - description=["List and filter on Linode Instances."], - requirements=global_requirements, - author=global_authors, - options=spec, +module = ListModule( + result_display_name="Instances", + result_field_name="instances", + endpoint_template="/linode/instances", + result_docs_url="https://techdocs.akamai.com/linode-api/reference/get-linode-instances", examples=docs.specdoc_examples, - return_values={ - "instances": SpecReturnValue( - description="The returned instances.", - docs_url="https://techdocs.akamai.com/linode-api/reference/get-linode-instances", - type=FieldType.list, - elements=FieldType.dict, - sample=docs.result_images_samples, - ) - }, + result_samples=docs.result_images_samples, ) +SPECDOC_META = module.spec + DOCUMENTATION = r""" """ EXAMPLES = r""" @@ -99,34 +27,5 @@ RETURN = r""" """ - -class Module(LinodeModuleBase): - """Module for getting a list of Linode instances""" - - def __init__(self) -> None: - self.module_arg_spec = SPECDOC_META.ansible_spec - self.results: Dict[str, Any] = {"instances": []} - - super().__init__(module_arg_spec=self.module_arg_spec) - - def exec_module(self, **kwargs: Any) -> Optional[dict]: - """Entrypoint for instance list module""" - - filter_dict = construct_api_filter(self.module.params) - - self.results["instances"] = get_all_paginated( - self.client, - "/linode/instances", - filter_dict, - num_results=self.module.params["count"], - ) - return self.results - - -def main() -> None: - """Constructs and calls the module""" - Module() - - if __name__ == "__main__": - main() + module.run() diff --git a/plugins/modules/instance_type_list.py b/plugins/modules/instance_type_list.py index 63a096f0..fe83f01c 100644 --- a/plugins/modules/instance_type_list.py +++ b/plugins/modules/instance_type_list.py @@ -1,101 +1,32 @@ #!/usr/bin/python # -*- coding: utf-8 -*- -"""This module allows users to list Linode instance types.""" +"""This module allows users to list Linode instance types. Deprecated in favor of type_list.""" from __future__ import absolute_import, division, print_function -from typing import Any, Dict, Optional - from ansible_collections.linode.cloud.plugins.module_utils.doc_fragments import ( instance_type_list as docs, ) -from ansible_collections.linode.cloud.plugins.module_utils.linode_common import ( - LinodeModuleBase, -) -from ansible_collections.linode.cloud.plugins.module_utils.linode_docs import ( - global_authors, - global_requirements, -) -from ansible_collections.linode.cloud.plugins.module_utils.linode_helper import ( - construct_api_filter, - get_all_paginated, +from ansible_collections.linode.cloud.plugins.module_utils.linode_common_list import ( + ListModule, ) -from ansible_specdoc.objects import ( - FieldType, - SpecDocMeta, - SpecField, - SpecReturnValue, -) - -spec_filter = { - "name": SpecField( - type=FieldType.string, - required=True, - description=[ - "The name of the field to filter on.", - "Valid filterable attributes can be found here: " - "https://techdocs.akamai.com/linode-api/reference/get-linode-types", - ], - ), - "values": SpecField( - type=FieldType.list, - element_type=FieldType.string, - required=True, - description=[ - "A list of values to allow for this field.", - "Fields will pass this filter if at least one of these values matches.", - ], - ), -} -spec = { - # Disable the default values - "state": SpecField(type=FieldType.string, required=False, doc_hide=True), - "label": SpecField(type=FieldType.string, required=False, doc_hide=True), - "order": SpecField( - type=FieldType.string, - description=["The order to list instance types in."], - default="asc", - choices=["desc", "asc"], - ), - "order_by": SpecField( - type=FieldType.string, - description=["The attribute to order instance types by."], - ), - "filters": SpecField( - type=FieldType.list, - element_type=FieldType.dict, - suboptions=spec_filter, - description=[ - "A list of filters to apply to the resulting instance types." - ], - ), - "count": SpecField( - type=FieldType.integer, - description=[ - "The number of results to return.", - "If undefined, all results will be returned.", - ], - ), -} - -SPECDOC_META = SpecDocMeta( - description=["List and filter on Linode Instance Types."], - requirements=global_requirements, - author=global_authors, - options=spec, +module = ListModule( + result_display_name="Instance Types", + result_field_name="instance_types", + endpoint_template="/linode/types", + result_docs_url="https://techdocs.akamai.com/linode-api/reference/get-linode-types", examples=docs.specdoc_examples, - return_values={ - "instance_types": SpecReturnValue( - description="The returned instance types.", - docs_url="https://techdocs.akamai.com/linode-api/reference/get-linode-types", - type=FieldType.list, - elements=FieldType.dict, - sample=docs.result_instance_type_samples, - ) - }, + result_samples=docs.result_instance_type_samples, ) +module.description = [ + "**NOTE: This module has been deprecated in favor of `type_list`.", + "List and filter on Linode Instance Types.", +] + +SPECDOC_META = module.spec + DOCUMENTATION = r""" """ EXAMPLES = r""" @@ -103,34 +34,5 @@ RETURN = r""" """ - -class Module(LinodeModuleBase): - """Module for getting a list of Linode instance types""" - - def __init__(self) -> None: - self.module_arg_spec = SPECDOC_META.ansible_spec - self.results: Dict[str, Any] = {"instance_types": []} - - super().__init__(module_arg_spec=self.module_arg_spec) - - def exec_module(self, **kwargs: Any) -> Optional[dict]: - """Entrypoint for instance type list module""" - - filter_dict = construct_api_filter(self.module.params) - - self.results["instance_types"] = get_all_paginated( - self.client, - "/linode/types", - filter_dict, - num_results=self.module.params["count"], - ) - return self.results - - -def main() -> None: - """Constructs and calls the module""" - Module() - - if __name__ == "__main__": - main() + module.run() diff --git a/plugins/modules/nodebalancer_info.py b/plugins/modules/nodebalancer_info.py index b5cc230d..4f3aed8d 100644 --- a/plugins/modules/nodebalancer_info.py +++ b/plugins/modules/nodebalancer_info.py @@ -1,11 +1,11 @@ #!/usr/bin/python # -*- coding: utf-8 -*- -"""This module contains all of the functionality for Linode NodeBalancers.""" +"""This module allows users to retrieve information about a Linode NodeBalancer.""" from __future__ import absolute_import, division, print_function -from typing import Any, List, Optional +from typing import Any, Dict, List from ansible_collections.linode.cloud.plugins.module_utils.doc_fragments import ( nodebalancer as docs_parent, @@ -13,83 +13,118 @@ from ansible_collections.linode.cloud.plugins.module_utils.doc_fragments import ( nodebalancer_info as docs, ) -from ansible_collections.linode.cloud.plugins.module_utils.linode_common import ( - LinodeModuleBase, -) -from ansible_collections.linode.cloud.plugins.module_utils.linode_docs import ( - global_authors, - global_requirements, +from ansible_collections.linode.cloud.plugins.module_utils.linode_common_info import ( + InfoModule, + InfoModuleAttr, + InfoModuleResult, ) from ansible_collections.linode.cloud.plugins.module_utils.linode_helper import ( - create_filter_and, -) -from ansible_specdoc.objects import ( - FieldType, - SpecDocMeta, - SpecField, - SpecReturnValue, + paginated_list_to_json, + safe_find, ) -from linode_api4 import NodeBalancer, NodeBalancerConfig, NodeBalancerNode - -linode_nodebalancer_info_spec = { - # We need to overwrite attributes to exclude them as requirements - "state": SpecField(type=FieldType.string, required=False, doc_hide=True), - "id": SpecField( - type=FieldType.integer, - required=False, - conflicts_with=["label"], - description=[ - "The ID of this NodeBalancer.", - "Optional if `label` is defined.", - ], +from ansible_specdoc.objects import FieldType +from linode_api4 import LinodeClient, NodeBalancer + + +def _get_firewalls_data( + client: LinodeClient, nodebalancer: NodeBalancer, params: Dict[str, Any] +) -> List[Any]: + firewalls = NodeBalancer(client, nodebalancer["id"]).firewalls() + firewalls_json = [] + for firewall in firewalls: + firewall._api_get() + firewalls_json.append(firewall._raw_json) + return firewalls_json + + +def _get_nodes( + client: LinodeClient, nodebalancer: NodeBalancer, params: Dict[str, Any] +) -> List[Any]: + configs = NodeBalancer(client, nodebalancer["id"]).configs + nodes_json = [] + for config in configs: + for node in config.nodes: + node._api_get() + nodes_json.append(node._raw_json) + return nodes_json + + +module = InfoModule( + primary_result=InfoModuleResult( + field_name="node_balancer", + field_type=FieldType.dict, + display_name="Node Balancer", + docs_url="https://techdocs.akamai.com/linode-api/reference/get-node-balancer", + samples=docs_parent.result_node_balancer_samples, ), - "label": SpecField( - type=FieldType.string, - required=False, - conflicts_with=["id"], - description=[ - "The label of this NodeBalancer.", - "Optional if `id` is defined.", - ], - ), -} - -SPECDOC_META = SpecDocMeta( - description=["Get info about a Linode NodeBalancer."], - requirements=global_requirements, - author=global_authors, - options=linode_nodebalancer_info_spec, - examples=docs.specdoc_examples, - return_values={ - "node_balancer": SpecReturnValue( - description="The NodeBalancer in JSON serialized form.", - docs_url="https://techdocs.akamai.com/linode-api/reference/get-node-balancer", - type="dict", - sample=docs_parent.result_node_balancer_samples, + secondary_results=[ + InfoModuleResult( + field_name="configs", + field_type=FieldType.list, + display_name="configs", + docs_url="https://techdocs.akamai.com/linode-api/reference/get-node-balancer-configs", + samples=docs_parent.result_configs_samples, + get=lambda client, nodebalancer, params: paginated_list_to_json( + NodeBalancer(client, nodebalancer["id"]).configs + ), ), - "configs": SpecReturnValue( - description="A list of configs applied to the NodeBalancer.", - docs_url="https://techdocs.akamai.com/linode-api/reference/get-node-balancer-config", - type=FieldType.list, - sample=docs_parent.result_configs_samples, + InfoModuleResult( + field_name="nodes", + field_type=FieldType.list, + display_name="nodes", + docs_url="https://techdocs.akamai.com/linode-api/" + + "reference/get-node-balancer-config-nodes", + samples=docs_parent.result_nodes_samples, + get=_get_nodes, ), - "nodes": SpecReturnValue( - description="A list of configs applied to the NodeBalancer.", - docs_url="https://techdocs.akamai.com/linode-api/reference/get-node-balancer-node", - type=FieldType.list, - sample=docs_parent.result_nodes_samples, + InfoModuleResult( + field_name="firewalls", + field_type=FieldType.list, + display_name="firewalls", + docs_url="https://techdocs.akamai.com/linode-api/reference/get-node-balancer-firewalls", + samples=docs_parent.result_firewalls_samples, + get=lambda client, nodebalancer, params: [ + firewall.id + for firewall in NodeBalancer( + client, nodebalancer["id"] + ).firewalls() + ], ), - "firewalls": SpecReturnValue( - description="A list IDs for firewalls attached to this NodeBalancer.", + InfoModuleResult( + field_name="firewalls_data", + field_type=FieldType.list, + display_name="firewalls_data", docs_url="https://techdocs.akamai.com/linode-api/reference/get-node-balancer-firewalls", - type=FieldType.list, - elements=FieldType.integer, - sample=docs_parent.result_firewalls_samples, + samples=docs_parent.result_firewalls_data_samples, + get=_get_firewalls_data, + ), + ], + attributes=[ + InfoModuleAttr( + display_name="ID", + name="id", + type=FieldType.integer, + get=lambda client, params: client.load( + NodeBalancer, + params.get("id"), + )._raw_json, + ), + InfoModuleAttr( + display_name="label", + name="label", + type=FieldType.string, + get=lambda client, params: safe_find( + client.nodebalancers, + NodeBalancer.label == params.get("label"), + raise_not_found=True, + )._raw_json, ), - }, + ], + examples=docs.specdoc_examples, ) -linode_nodebalancer_valid_filters = ["id", "label"] + +SPECDOC_META = module.spec DOCUMENTATION = r""" """ @@ -98,94 +133,5 @@ RETURN = r""" """ - -class LinodeNodeBalancerInfo(LinodeModuleBase): - """Module for getting info about a Linode NodeBalancer""" - - def __init__(self) -> None: - self.module_arg_spec = SPECDOC_META.ansible_spec - self.required_one_of: List[str] = [] - self.results: dict = { - "node_balancer": None, - "configs": [], - "nodes": [], - "firewalls": [], - } - - super().__init__( - module_arg_spec=self.module_arg_spec, - required_one_of=self.required_one_of, - ) - - def _get_matching_nodebalancer(self) -> Optional[NodeBalancer]: - filter_items = { - k: v - for k, v in self.module.params.items() - if k in linode_nodebalancer_valid_filters and v is not None - } - - filter_statement = create_filter_and(NodeBalancer, filter_items) - - try: - # Special case because ID is not filterable - if "id" in filter_items.keys(): - result = NodeBalancer(self.client, self.module.params.get("id")) - result._api_get() # Force lazy-loading - - return result - - return self.client.nodebalancers(filter_statement)[0] - except IndexError: - return None - except Exception as exception: - return self.fail( - msg="failed to get nodebalancer {0}".format(exception) - ) - - def _get_node_by_label( - self, config: NodeBalancerConfig, label: str - ) -> Optional[NodeBalancerNode]: - try: - return config.nodes(NodeBalancerNode.label == label)[0] - except IndexError: - return None - except Exception as exception: - return self.fail( - msg="failed to get nodebalancer node {0}, {1}".format( - label, exception - ) - ) - - def exec_module(self, **kwargs: Any) -> Optional[dict]: - """Entrypoint for NodeBalancer Info module""" - - node_balancer = self._get_matching_nodebalancer() - - if node_balancer is None: - return self.fail("failed to get nodebalancer") - - self.results["node_balancer"] = node_balancer._raw_json - - for config in node_balancer.configs: - self.results["configs"].append(config._raw_json) - - for node in config.nodes: - node._api_get() - - self.results["nodes"].append(node._raw_json) - - # NOTE: Only the Firewall IDs are used here to reduce the - # number of API requests made by this module and to simplify - # the module result. - self.results["firewalls"] = [v.id for v in node_balancer.firewalls()] - - return self.results - - -def main() -> None: - """Constructs and calls the Linode NodeBalancer Info module""" - LinodeNodeBalancerInfo() - - if __name__ == "__main__": - main() + module.run() diff --git a/plugins/modules/nodebalancer_list.py b/plugins/modules/nodebalancer_list.py index 8e9f30fb..8417f3c3 100644 --- a/plugins/modules/nodebalancer_list.py +++ b/plugins/modules/nodebalancer_list.py @@ -1,99 +1,26 @@ #!/usr/bin/python # -*- coding: utf-8 -*- -"""This module allows users to list Nodebalancers.""" -from __future__ import absolute_import, division, print_function +"""This module contains all of the functionality for listing Linode Node Balancers.""" -from typing import Any, Dict, Optional +from __future__ import absolute_import, division, print_function import ansible_collections.linode.cloud.plugins.module_utils.doc_fragments.nodebalancer_list as docs -from ansible_collections.linode.cloud.plugins.module_utils.linode_common import ( - LinodeModuleBase, -) -from ansible_collections.linode.cloud.plugins.module_utils.linode_docs import ( - global_authors, - global_requirements, -) -from ansible_collections.linode.cloud.plugins.module_utils.linode_helper import ( - construct_api_filter, - get_all_paginated, -) -from ansible_specdoc.objects import ( - FieldType, - SpecDocMeta, - SpecField, - SpecReturnValue, +from ansible_collections.linode.cloud.plugins.module_utils.linode_common_list import ( + ListModule, ) -spec_filter = { - "name": SpecField( - type=FieldType.string, - required=True, - description=[ - "The name of the field to filter on.", - "Valid filterable attributes can be found here: " - "https://techdocs.akamai.com/linode-api/reference/get-node-balancers", - ], - ), - "values": SpecField( - type=FieldType.list, - element_type=FieldType.string, - required=True, - description=[ - "A list of values to allow for this field.", - "Fields will pass this filter if at least one of these values matches.", - ], - ), -} - -spec = { - # Disable the default values - "state": SpecField(type=FieldType.string, required=False, doc_hide=True), - "label": SpecField(type=FieldType.string, required=False, doc_hide=True), - "order": SpecField( - type=FieldType.string, - description=["The order to list nodebalancers in."], - default="asc", - choices=["desc", "asc"], - ), - "order_by": SpecField( - type=FieldType.string, - description=["The attribute to order nodebalancers by."], - ), - "filters": SpecField( - type=FieldType.list, - element_type=FieldType.dict, - suboptions=spec_filter, - description=[ - "A list of filters to apply to the resulting nodebalancers." - ], - ), - "count": SpecField( - type=FieldType.integer, - description=[ - "The number of results to return.", - "If undefined, all results will be returned.", - ], - ), -} - -SPECDOC_META = SpecDocMeta( - description=["List and filter on Nodebalancers."], - requirements=global_requirements, - author=global_authors, - options=spec, +module = ListModule( + result_display_name="Node Balancers", + result_field_name="nodebalancers", + endpoint_template="/nodebalancers", + result_docs_url="https://techdocs.akamai.com/linode-api/reference/get-node-balancers", examples=docs.specdoc_examples, - return_values={ - "nodebalancers": SpecReturnValue( - description="The returned nodebalancers.", - docs_url="https://techdocs.akamai.com/linode-api/reference/get-node-balancers", - type=FieldType.list, - elements=FieldType.dict, - sample=docs.result_nodebalancers_samples, - ) - }, + result_samples=docs.result_nodebalancers_samples, ) +SPECDOC_META = module.spec + DOCUMENTATION = r""" """ EXAMPLES = r""" @@ -101,34 +28,5 @@ RETURN = r""" """ - -class Module(LinodeModuleBase): - """Module for getting a list of Linode Nodebalancers""" - - def __init__(self) -> None: - self.module_arg_spec = SPECDOC_META.ansible_spec - self.results: Dict[str, Any] = {"nodebalancers": []} - - super().__init__(module_arg_spec=self.module_arg_spec) - - def exec_module(self, **kwargs: Any) -> Optional[dict]: - """Entrypoint for nodebalancers list module""" - - filter_dict = construct_api_filter(self.module.params) - - self.results["nodebalancers"] = get_all_paginated( - self.client, - "/nodebalancers", - filter_dict, - num_results=self.module.params["count"], - ) - return self.results - - -def main() -> None: - """Constructs and calls the module""" - Module() - - if __name__ == "__main__": - main() + module.run() diff --git a/plugins/modules/nodebalancer_stats.py b/plugins/modules/nodebalancer_stats.py index ecad435c..c7b6d778 100644 --- a/plugins/modules/nodebalancer_stats.py +++ b/plugins/modules/nodebalancer_stats.py @@ -5,60 +5,54 @@ from __future__ import absolute_import, division, print_function -from typing import Any, Dict, List, Optional - from ansible_collections.linode.cloud.plugins.module_utils.doc_fragments import ( nodebalancer_stats as docs, ) -from ansible_collections.linode.cloud.plugins.module_utils.linode_common import ( - LinodeModuleBase, -) -from ansible_collections.linode.cloud.plugins.module_utils.linode_docs import ( - global_authors, - global_requirements, +from ansible_collections.linode.cloud.plugins.module_utils.linode_common_info import ( + InfoModule, + InfoModuleAttr, + InfoModuleResult, ) -from ansible_specdoc.objects import ( - FieldType, - SpecDocMeta, - SpecField, - SpecReturnValue, +from ansible_collections.linode.cloud.plugins.module_utils.linode_helper import ( + safe_find, ) +from ansible_specdoc.objects import FieldType from linode_api4 import NodeBalancer -linode_nodebalancer_stats_spec = { - "state": SpecField(type=FieldType.string, required=False, doc_hide=True), - "id": SpecField( - type=FieldType.integer, - description=[ - "The id of the nodebalancer for which the statistics apply to." - ], - conflicts_with=["label"], - ), - "label": SpecField( - type=FieldType.string, - description=[ - "The label of the nodebalancer for which the statistics apply to." - ], - conflicts_with=["id"], +module = InfoModule( + primary_result=InfoModuleResult( + field_name="node_balancer_stats", + field_type=FieldType.dict, + display_name="Node Balancer Stats", + docs_url="https://techdocs.akamai.com/linode-api/reference/get-node-balancer-stats", + samples=docs.result_nodebalancer_stats_samples, ), -} - -SPECDOC_META = SpecDocMeta( - description=["View a Linode NodeBalancers Stats."], - requirements=global_requirements, - author=global_authors, - options=linode_nodebalancer_stats_spec, - examples=docs.specdoc_examples, - return_values={ - "node_balancer_stats": SpecReturnValue( - description="The NodeBalancer Stats in JSON serialized form.", - docs_url="https://techdocs.akamai.com/linode-api/reference/get-node-balancer-stats", - type=FieldType.dict, - sample=docs.result_nodebalancer_stats_samples, + attributes=[ + InfoModuleAttr( + display_name="ID", + name="id", + type=FieldType.integer, + get=lambda client, params: client.load( + NodeBalancer, + params.get("id"), + )._raw_json, + ), + InfoModuleAttr( + display_name="label", + name="label", + type=FieldType.string, + get=lambda client, params: safe_find( + client.nodebalancers, + NodeBalancer.label == params.get("label"), + raise_not_found=True, + )._raw_json, ), - }, + ], + examples=docs.specdoc_examples, ) +SPECDOC_META = module.spec + DOCUMENTATION = r""" """ EXAMPLES = r""" @@ -66,69 +60,5 @@ RETURN = r""" """ - -class Module(LinodeModuleBase): - """Module for getting info about a NodeBalancer's Statistics""" - - def __init__(self) -> None: - self.required_one_of: List[str] = [] - self.results: Dict[str, Any] = {"node_balancer_stats": {}} - - self.module_arg_spec = SPECDOC_META.ansible_spec - - super().__init__( - module_arg_spec=self.module_arg_spec, - required_one_of=self.required_one_of, - ) - - def _get_stats_by_label(self, label: str) -> Optional[dict]: - try: - nodebalancer = self.client.nodebalancers( - NodeBalancer.label == label - )[0] - return self.client.get( - "/nodebalancers/{}/stats".format(nodebalancer.id) - ) - except IndexError: - return self.fail( - msg="failed to find nodebalancer with label {0}: " - "nodebalancer does not exist".format(label) - ) - except Exception as exception: - return self.fail( - msg="failed to get nodebalancer {0}: {1}".format( - label, exception - ) - ) - - def exec_module(self, **kwargs: Any) -> Optional[dict]: - """Entrypoint for NodeBalancer Statistics module""" - - if (kwargs["id"] is None and kwargs["label"] is None) or ( - kwargs["id"] is not None and kwargs["label"] is not None - ): - return self.fail( - msg="Label and ID are mutually exclusive and one " - + "must be used to resolve Nodebalancer statistics." - ) - - if kwargs["id"] is not None: - self.results["node_balancer_stats"] = self.client.get( - "/nodebalancers/{}/stats".format(kwargs["id"]) - ) - - if kwargs["label"] is not None: - self.results["node_balancer_stats"] = self._get_stats_by_label( - kwargs["label"] - ) - - return self.results - - -def main() -> None: - """Constructs and calls the nodebalancer_stats module""" - Module() - - if __name__ == "__main__": - main() + module.run() diff --git a/plugins/modules/placement_group.py b/plugins/modules/placement_group.py index 217a532d..1c42a1e8 100644 --- a/plugins/modules/placement_group.py +++ b/plugins/modules/placement_group.py @@ -69,7 +69,7 @@ return_values={ "placement_group": SpecReturnValue( description="The Placement Group in JSON serialized form.", - docs_url="TBD", + docs_url="https://techdocs.akamai.com/linode-api/reference/get-placement-group", type=FieldType.dict, sample=docs.result_placement_group_samples, ) diff --git a/plugins/modules/placement_group_assign.py b/plugins/modules/placement_group_assign.py index 3eaad34f..7c66298f 100644 --- a/plugins/modules/placement_group_assign.py +++ b/plugins/modules/placement_group_assign.py @@ -38,7 +38,8 @@ ), "compliant_only": SpecField( type=FieldType.bool, - description=["TODO"], + description=[], + doc_hide=True, ), } diff --git a/plugins/modules/placement_group_info.py b/plugins/modules/placement_group_info.py index dfb878b3..7d3ccc06 100644 --- a/plugins/modules/placement_group_info.py +++ b/plugins/modules/placement_group_info.py @@ -22,7 +22,7 @@ display_name="Placement Group", field_name="placement_group", field_type=FieldType.dict, - docs_url="TBD", + docs_url="https://techdocs.akamai.com/linode-api/reference/get-placement-group", samples=docs.result_placement_group_samples, ), attributes=[ diff --git a/plugins/modules/placement_group_list.py b/plugins/modules/placement_group_list.py index b6fedff6..5a3cd478 100644 --- a/plugins/modules/placement_group_list.py +++ b/plugins/modules/placement_group_list.py @@ -16,7 +16,7 @@ result_display_name="Placement Groups", result_field_name="placement_groups", endpoint_template="/placement/groups", - result_docs_url="TBD", + result_docs_url="https://techdocs.akamai.com/linode-api/reference/get-placement-groups", result_samples=docs.result_placement_groups_samples, examples=docs.specdoc_examples, requires_beta=True, diff --git a/plugins/modules/profile_info.py b/plugins/modules/profile_info.py index 0f9da33e..d81a2eec 100644 --- a/plugins/modules/profile_info.py +++ b/plugins/modules/profile_info.py @@ -1,50 +1,31 @@ #!/usr/bin/python # -*- coding: utf-8 -*- -"""This module allows users to retrieve information about the current Linode profile.""" +"""This module contains all of the functionality for Linode Profile info.""" from __future__ import absolute_import, division, print_function -from typing import Any, List, Optional - import ansible_collections.linode.cloud.plugins.module_utils.doc_fragments.profile_info as docs -from ansible_collections.linode.cloud.plugins.module_utils.linode_common import ( - LinodeModuleBase, -) -from ansible_collections.linode.cloud.plugins.module_utils.linode_docs import ( - global_authors, - global_requirements, -) -from ansible_specdoc.objects import ( - FieldType, - SpecDocMeta, - SpecField, - SpecReturnValue, +from ansible_collections.linode.cloud.plugins.module_utils.linode_common_info import ( + InfoModule, + InfoModuleResult, ) +from ansible_specdoc.objects import FieldType -spec = { - # Disable the default values - "label": SpecField(type=FieldType.string, required=False, doc_hide=True), - "state": SpecField(type=FieldType.string, required=False, doc_hide=True), -} - - -SPECDOC_META = SpecDocMeta( - description=["Get info about a Linode Profile."], - requirements=global_requirements, - author=global_authors, - options=spec, +module = InfoModule( examples=docs.specdoc_examples, - return_values={ - "profile": SpecReturnValue( - description="The profile info in JSON serialized form.", - docs_url="https://techdocs.akamai.com/linode-api/reference/get-profile", - type=FieldType.dict, - sample=docs.result_profile_samples, - ) - }, + primary_result=InfoModuleResult( + display_name="Profile", + field_name="profile", + field_type=FieldType.dict, + docs_url="https://techdocs.akamai.com/linode-api/reference/get-profile", + samples=docs.result_profile_samples, + get=lambda client, params: client.profile()._raw_json, + ), ) +SPECDOC_META = module.spec + DOCUMENTATION = r""" """ EXAMPLES = r""" @@ -52,33 +33,5 @@ RETURN = r""" """ - -class Module(LinodeModuleBase): - """Module for getting info about a Linode Profile""" - - def __init__(self) -> None: - self.required_one_of: List[str] = [] - self.results = {"profile": None} - - self.module_arg_spec = SPECDOC_META.ansible_spec - - super().__init__( - module_arg_spec=self.module_arg_spec, - required_one_of=self.required_one_of, - ) - - def exec_module(self, **kwargs: Any) -> Optional[dict]: - """Entrypoint for volume info module""" - - self.results["profile"] = self.client.profile()._raw_json - - return self.results - - -def main() -> None: - """Constructs and calls the profile_info module""" - Module() - - if __name__ == "__main__": - main() + module.run() diff --git a/plugins/modules/region_list.py b/plugins/modules/region_list.py index 21c8a054..40328cbf 100644 --- a/plugins/modules/region_list.py +++ b/plugins/modules/region_list.py @@ -4,94 +4,22 @@ """This module allows users to list Linode regions.""" from __future__ import absolute_import, division, print_function -from typing import Any, Dict, Optional - import ansible_collections.linode.cloud.plugins.module_utils.doc_fragments.region_list as docs -from ansible_collections.linode.cloud.plugins.module_utils.linode_common import ( - LinodeModuleBase, -) -from ansible_collections.linode.cloud.plugins.module_utils.linode_docs import ( - global_authors, - global_requirements, -) -from ansible_collections.linode.cloud.plugins.module_utils.linode_helper import ( - construct_api_filter, - get_all_paginated, +from ansible_collections.linode.cloud.plugins.module_utils.linode_common_list import ( + ListModule, ) -from ansible_specdoc.objects import ( - FieldType, - SpecDocMeta, - SpecField, - SpecReturnValue, -) - -spec_filter = { - "name": SpecField( - type=FieldType.string, - required=True, - description=[ - "The name of the field to filter on.", - "Valid filterable attributes can be found here: " - "https://techdocs.akamai.com/linode-api/reference/get-regions", - ], - ), - "values": SpecField( - type=FieldType.list, - element_type=FieldType.string, - required=True, - description=[ - "A list of values to allow for this field.", - "Fields will pass this filter if at least one of these values matches.", - ], - ), -} -spec = { - # Disable the default values - "state": SpecField(type=FieldType.string, required=False, doc_hide=True), - "label": SpecField(type=FieldType.string, required=False, doc_hide=True), - "order": SpecField( - type=FieldType.string, - description=["The order to list regions in."], - default="asc", - choices=["desc", "asc"], - ), - "order_by": SpecField( - type=FieldType.string, - description=["The attribute to order regions by."], - ), - "filters": SpecField( - type=FieldType.list, - element_type=FieldType.dict, - suboptions=spec_filter, - description=["A list of filters to apply to the resulting regions."], - ), - "count": SpecField( - type=FieldType.integer, - description=[ - "The number of results to return.", - "If undefined, all results will be returned.", - ], - ), -} - -SPECDOC_META = SpecDocMeta( - description=["List and filter on Linode Regions."], - requirements=global_requirements, - author=global_authors, - options=spec, +module = ListModule( + result_display_name="Regions", + result_field_name="regions", + endpoint_template="/regions", + result_docs_url="https://techdocs.akamai.com/linode-api/reference/get-regions", examples=docs.specdoc_examples, - return_values={ - "regions": SpecReturnValue( - description="The returned regions.", - docs_url="https://techdocs.akamai.com/linode-api/reference/get-regions", - type=FieldType.list, - elements=FieldType.dict, - sample=docs.result_regions_samples, - ) - }, + result_samples=docs.result_regions_samples, ) +SPECDOC_META = module.spec + DOCUMENTATION = r""" """ EXAMPLES = r""" @@ -99,34 +27,5 @@ RETURN = r""" """ - -class Module(LinodeModuleBase): - """Module for getting a list of Linode regions""" - - def __init__(self) -> None: - self.module_arg_spec = SPECDOC_META.ansible_spec - self.results: Dict[str, Any] = {"regions": []} - - super().__init__(module_arg_spec=self.module_arg_spec) - - def exec_module(self, **kwargs: Any) -> Optional[dict]: - """Entrypoint for region list module""" - - filter_dict = construct_api_filter(self.module.params) - - self.results["regions"] = get_all_paginated( - self.client, - "/regions", - filter_dict, - num_results=self.module.params["count"], - ) - return self.results - - -def main() -> None: - """Constructs and calls the module""" - Module() - - if __name__ == "__main__": - main() + module.run() diff --git a/plugins/modules/ssh_key.py b/plugins/modules/ssh_key.py index 6d6c1030..ccd81bfb 100644 --- a/plugins/modules/ssh_key.py +++ b/plugins/modules/ssh_key.py @@ -40,7 +40,6 @@ ), "ssh_key": SpecField( type=FieldType.string, - editable=True, description=["The SSH public key value."], ), } diff --git a/plugins/modules/type_list.py b/plugins/modules/type_list.py index 23f13b8a..12b5b819 100644 --- a/plugins/modules/type_list.py +++ b/plugins/modules/type_list.py @@ -2,99 +2,24 @@ # -*- coding: utf-8 -*- """This module allows users to list Linode Instance Types.""" - from __future__ import absolute_import, division, print_function -from typing import Any, Dict, Optional - import ansible_collections.linode.cloud.plugins.module_utils.doc_fragments.type_list as docs -from ansible_collections.linode.cloud.plugins.module_utils.linode_common import ( - LinodeModuleBase, -) -from ansible_collections.linode.cloud.plugins.module_utils.linode_docs import ( - global_authors, - global_requirements, -) -from ansible_collections.linode.cloud.plugins.module_utils.linode_helper import ( - construct_api_filter, - get_all_paginated, -) -from ansible_specdoc.objects import ( - FieldType, - SpecDocMeta, - SpecField, - SpecReturnValue, +from ansible_collections.linode.cloud.plugins.module_utils.linode_common_list import ( + ListModule, ) -spec_filter = { - "name": SpecField( - type=FieldType.string, - required=True, - description=[ - "The name of the field to filter on.", - "Valid filterable attributes can be found here: " - "https://techdocs.akamai.com/linode-api/reference/get-linode-types", - ], - ), - "values": SpecField( - type=FieldType.list, - element_type=FieldType.string, - required=True, - description=[ - "A list of values to allow for this field.", - "Fields will pass this filter if at least one of these values matches.", - ], - ), -} - -spec = { - # Disable the default values - "state": SpecField(type=FieldType.string, required=False, doc_hide=True), - "label": SpecField(type=FieldType.string, required=False, doc_hide=True), - "order": SpecField( - type=FieldType.string, - description=["The order to list Instance Types in."], - default="asc", - choices=["desc", "asc"], - ), - "order_by": SpecField( - type=FieldType.string, - description=["The attribute to order Instance Types by."], - ), - "filters": SpecField( - type=FieldType.list, - element_type=FieldType.dict, - suboptions=spec_filter, - description=[ - "A list of filters to apply to the resulting Instance Types." - ], - ), - "count": SpecField( - type=FieldType.integer, - description=[ - "The number of results to return.", - "If undefined, all results will be returned.", - ], - ), -} - -SPECDOC_META = SpecDocMeta( - description=["List and filter on Linode Instance Types."], - requirements=global_requirements, - author=global_authors, - options=spec, +module = ListModule( + result_display_name="Types", + result_field_name="types", + endpoint_template="/linode/types", + result_docs_url="https://techdocs.akamai.com/linode-api/reference/get-linode-types", examples=docs.specdoc_examples, - return_values={ - "types": SpecReturnValue( - description="The returned Instance Types.", - docs_url="https://techdocs.akamai.com/linode-api/reference/get-linode-types", - type=FieldType.list, - elements=FieldType.dict, - sample=docs.result_type_samples, - ) - }, + result_samples=docs.result_type_samples, ) +SPECDOC_META = module.spec + DOCUMENTATION = r""" """ EXAMPLES = r""" @@ -102,34 +27,5 @@ RETURN = r""" """ - -class Module(LinodeModuleBase): - """Module for getting info about a Linode Instance Types""" - - def __init__(self) -> None: - self.module_arg_spec = SPECDOC_META.ansible_spec - self.results: Dict[str, Any] = {"types": []} - - super().__init__(module_arg_spec=self.module_arg_spec) - - def exec_module(self, **kwargs: Any) -> Optional[dict]: - """Entrypoint for Instance Types list module""" - - filter_dict = construct_api_filter(self.module.params) - - self.results["types"] = get_all_paginated( - self.client, - "/linode/types", - filter_dict, - num_results=self.module.params["count"], - ) - return self.results - - -def main() -> None: - """Constructs and calls the module""" - Module() - - if __name__ == "__main__": - main() + module.run() diff --git a/plugins/modules/user_info.py b/plugins/modules/user_info.py index c918f006..6550c72f 100644 --- a/plugins/modules/user_info.py +++ b/plugins/modules/user_info.py @@ -5,57 +5,53 @@ from __future__ import absolute_import, division, print_function -from typing import Any, List, Optional - import ansible_collections.linode.cloud.plugins.module_utils.doc_fragments.user_info as docs -from ansible_collections.linode.cloud.plugins.module_utils.linode_common import ( - LinodeModuleBase, -) -from ansible_collections.linode.cloud.plugins.module_utils.linode_docs import ( - global_authors, - global_requirements, -) -from ansible_specdoc.objects import ( - FieldType, - SpecDocMeta, - SpecField, - SpecReturnValue, +from ansible_collections.linode.cloud.plugins.module_utils.linode_common_info import ( + InfoModule, + InfoModuleAttr, + InfoModuleResult, ) +from ansible_specdoc.objects import FieldType from linode_api4 import User -spec = { - # Disable the default values - "label": SpecField(type=FieldType.string, required=False, doc_hide=True), - "state": SpecField(type=FieldType.string, required=False, doc_hide=True), - "username": SpecField( - type=FieldType.string, - required=True, - description=["The username of the user."], +module = InfoModule( + primary_result=InfoModuleResult( + field_name="user", + field_type=FieldType.dict, + display_name="User", + docs_url="https://techdocs.akamai.com/linode-api/reference/get-user", + samples=docs.result_user_samples, ), -} - -SPECDOC_META = SpecDocMeta( - description=["Get info about a Linode User."], - requirements=global_requirements, - author=global_authors, - options=spec, - examples=docs.specdoc_examples, - return_values={ - "user": SpecReturnValue( - description="The user info in JSON serialized form.", - docs_url="https://techdocs.akamai.com/linode-api/reference/get-user", - type=FieldType.dict, - sample=docs.result_user_samples, - ), - "grants": SpecReturnValue( - description="The grants info in JSON serialized form.", + secondary_results=[ + InfoModuleResult( + field_name="grants", + field_type=FieldType.dict, + display_name="Grants", docs_url="https://techdocs.akamai.com/linode-api/reference/get-user-grants", - type=FieldType.dict, - sample=docs.result_grants_samples, - ), - }, + samples=docs.result_grants_samples, + get=lambda client, user, params: client.get( + # We can't use the UserGrants type here because + # it does not serialize directly to JSON or store + # the API response JSON. + f"/account/users/{user['username']}/grants" + ), + ) + ], + attributes=[ + InfoModuleAttr( + name="username", + display_name="Username", + type=FieldType.string, + get=lambda client, params: client.load( + User, params.get("username") + )._raw_json, + ) + ], + examples=docs.specdoc_examples, ) +SPECDOC_META = module.spec + DOCUMENTATION = r""" """ EXAMPLES = r""" @@ -63,39 +59,5 @@ RETURN = r""" """ - -class Module(LinodeModuleBase): - """Module for getting info about a Linode user""" - - def __init__(self) -> None: - self.required_one_of: List[str] = [] - self.results = {"user": None} - - self.module_arg_spec = SPECDOC_META.ansible_spec - - super().__init__( - module_arg_spec=self.module_arg_spec, - required_one_of=self.required_one_of, - ) - - def exec_module(self, **kwargs: Any) -> Optional[dict]: - """Entrypoint for user info module""" - - user = self.client.account.users( - User.username == self.module.params.get("username") - ) - grants = user.grants - - self.results["user"] = user._raw_json - self.results["grants"] = grants._raw_json - - return self.results - - -def main() -> None: - """Constructs and calls the module""" - Module() - - if __name__ == "__main__": - main() + module.run() diff --git a/plugins/modules/vpc.py b/plugins/modules/vpc.py index bbc90a04..bbf86791 100644 --- a/plugins/modules/vpc.py +++ b/plugins/modules/vpc.py @@ -62,7 +62,7 @@ return_values={ "vpc": SpecReturnValue( description="The VPC in JSON serialized form.", - docs_url="TODO", + docs_url="https://techdocs.akamai.com/linode-api/reference/get-vpc", type=FieldType.dict, sample=docs.result_vpc_samples, ) diff --git a/plugins/modules/vpc_info.py b/plugins/modules/vpc_info.py index 8655fedd..9a539b03 100644 --- a/plugins/modules/vpc_info.py +++ b/plugins/modules/vpc_info.py @@ -23,7 +23,7 @@ field_name="vpc", field_type=FieldType.dict, display_name="VPC", - docs_url="", + docs_url="https://techdocs.akamai.com/linode-api/reference/get-vpc", samples=docs_parent.result_vpc_samples, ), attributes=[ diff --git a/plugins/modules/vpc_ip_list.py b/plugins/modules/vpc_ip_list.py index 323bb433..12226fe9 100644 --- a/plugins/modules/vpc_ip_list.py +++ b/plugins/modules/vpc_ip_list.py @@ -16,7 +16,7 @@ result_display_name="VPC IP Addresses", result_field_name="vpcs_ips", endpoint_template="/vpcs/{vpc_id}/ips", - result_docs_url="", + result_docs_url="https://techdocs.akamai.com/linode-api/reference/get-vpc-ips", examples=docs.specdoc_examples, result_samples=docs.result_vpc_ip_view_samples, params=[ diff --git a/plugins/modules/vpc_list.py b/plugins/modules/vpc_list.py index c4f7d3c6..9e9498c0 100644 --- a/plugins/modules/vpc_list.py +++ b/plugins/modules/vpc_list.py @@ -14,7 +14,7 @@ result_display_name="VPCs", result_field_name="vpcs", endpoint_template="/vpcs", - result_docs_url="", + result_docs_url="https://techdocs.akamai.com/linode-api/reference/get-vpcs", examples=docs.specdoc_examples, result_samples=docs.result_vpc_samples, ) diff --git a/plugins/modules/vpc_subnet.py b/plugins/modules/vpc_subnet.py index 50b79cee..497082ce 100644 --- a/plugins/modules/vpc_subnet.py +++ b/plugins/modules/vpc_subnet.py @@ -63,7 +63,7 @@ return_values={ "subnet": SpecReturnValue( description="The VPC in JSON serialized form.", - docs_url="TODO", + docs_url="https://techdocs.akamai.com/linode-api/reference/get-vpc-subnet", type=FieldType.dict, sample=docs.result_subnet_samples, ) diff --git a/plugins/modules/vpc_subnet_info.py b/plugins/modules/vpc_subnet_info.py index 181bcaa0..db69185c 100644 --- a/plugins/modules/vpc_subnet_info.py +++ b/plugins/modules/vpc_subnet_info.py @@ -42,7 +42,7 @@ def _subnet_by_label( field_name="subnet", field_type=FieldType.dict, display_name="VPC Subnet", - docs_url="", + docs_url="https://techdocs.akamai.com/linode-api/reference/get-vpc-subnet", samples=docs_parent.result_subnet_samples, ), params=[ diff --git a/plugins/modules/vpc_subnet_list.py b/plugins/modules/vpc_subnet_list.py index cbdd82af..d08b8b5d 100644 --- a/plugins/modules/vpc_subnet_list.py +++ b/plugins/modules/vpc_subnet_list.py @@ -16,7 +16,7 @@ result_display_name="VPC Subnets", result_field_name="subnets", endpoint_template="/vpcs/{vpc_id}/subnets", - result_docs_url="", + result_docs_url="https://techdocs.akamai.com/linode-api/reference/get-vpc-subnets", result_samples=docs.result_vpc_samples, examples=docs.specdoc_examples, params=[ diff --git a/plugins/modules/vpcs_ip_list.py b/plugins/modules/vpcs_ip_list.py index 97fc2456..33dca9b1 100644 --- a/plugins/modules/vpcs_ip_list.py +++ b/plugins/modules/vpcs_ip_list.py @@ -14,7 +14,7 @@ result_display_name="all VPC IP Addresses", result_field_name="vpcs_ips", endpoint_template="/vpcs/ips", - result_docs_url="", + result_docs_url="https://techdocs.akamai.com/linode-api/reference/get-vpcs-ips", examples=docs.specdoc_examples, result_samples=docs.result_vpc_samples, ) diff --git a/requirements.txt b/requirements.txt index ba864887..856067fa 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -linode-api4>=5.19.0 +linode-api4>=5.20.0 polling>=0.3.2 types-requests==2.32.0.20240712 ansible-specdoc>=0.0.15 diff --git a/tests/integration/targets/domain_record/tasks/main.yaml b/tests/integration/targets/domain_record/tasks/main.yaml index fee9f8be..765515bd 100644 --- a/tests/integration/targets/domain_record/tasks/main.yaml +++ b/tests/integration/targets/domain_record/tasks/main.yaml @@ -87,6 +87,20 @@ - record_info_id.record[0].ttl_sec == 14400 - record_info_id.record[0].weight == 62 + - name: Get domain_record_info with both domain_id and domain + linode.cloud.domain_record_info: + domain: '{{ domain_create.domain.domain }}' + domain_id: '{{ domain_create.domain.id }}' + id: '{{ record_create.record.id }}' + register: info_mutually_exclusive + failed_when: '"mutually exclusive" not in info_mutually_exclusive.msg' + + - name: Get domain_record_info with neither domain_id nor domain + linode.cloud.domain_record_info: + id: '{{ record_create.record.id }}' + register: info_one_of + failed_when: '"one of the following" not in info_one_of.msg' + - name: Create domain_record with domain id linode.cloud.domain_record: domain_id: '{{ domain_create.domain.id }}' @@ -146,6 +160,24 @@ - record_dupe_update.record.ttl_sec == 300 - record_dupe_update.record.weight == 55 + - name: Create an SRV domain record + linode.cloud.domain_record: + domain: '{{ domain_create.domain.domain }}' + service: carddavs + protocol: tcp + type: "SRV" + target: host.example.com + port: 443 + priority: 0 + weight: 1 + state: present + register: srv_create + + - name: Assert SRV record is created + assert: + that: + - srv_create.record.type == 'SRV' + - name: Get domain_info linode.cloud.domain_info: domain: '{{ domain_create.domain.domain }}' @@ -154,7 +186,7 @@ - name: Assert domain_info response assert: that: - - domain_info.records|length == 3 + - domain_info.records|length == 4 - name: Create domain_record containing FQDN linode.cloud.domain_record: @@ -243,7 +275,20 @@ assert: that: - record_dupe_delete.changed - - record_dupe_delete.record.id == record_dupe_delete.record.id + - record_dupe_delete.record.id == record_dupe_create.record.id + + - name: Delete SRV domain_record + linode.cloud.domain_record: + domain: '{{ domain_create.domain.domain }}' + record_id: '{{ srv_create.record.id }}' + state: absent + register: srv_record_delete + + - name: Assert SRV domain_record is deleted + assert: + that: + - srv_record_delete.changed + - srv_record_delete.record.id == srv_create.record.id - name: Delete domain linode.cloud.domain: diff --git a/tests/integration/targets/image_basic/tasks/main.yaml b/tests/integration/targets/image_basic/tasks/main.yaml index 0404cb01..f0b72f18 100644 --- a/tests/integration/targets/image_basic/tasks/main.yaml +++ b/tests/integration/targets/image_basic/tasks/main.yaml @@ -1,4 +1,4 @@ -- name: stackscript_basic +- name: image_basic block: - set_fact: r: "{{ 1000000000 | random }}" @@ -6,7 +6,7 @@ - name: Create an instance to image linode.cloud.instance: label: 'ansible-test-{{ r }}' - region: us-ord + region: us-east type: g6-standard-1 image: linode/alpine3.19 state: present @@ -19,6 +19,9 @@ disk_id: '{{ instance_create.disks.0.id }}' description: 'cool' cloud_init: true + tags: + - 'test-tag' + - 'image-gen2' state: present register: image_create @@ -28,6 +31,8 @@ - image_create.image.status == 'available' - image_create.image.description == 'cool' - image_create.image.capabilities[0] == 'cloud-init' + - image_create.image.tags | length == 2 + - image_create.image.size == image_create.image.total_size - name: Get image_info by ID linode.cloud.image_info: @@ -58,6 +63,8 @@ label: 'ansible-test-{{ r }}' disk_id: '{{ instance_create.disks.0.id }}' description: 'cool2' + tags: + - 'test' state: present register: image_update @@ -66,12 +73,62 @@ that: - image_update.image.status == 'available' - image_update.image.description == 'cool2' + - image_update.image.tags[0] == 'test' + + - name: Replicate the image + linode.cloud.image: + label: 'ansible-test-{{ r }}' + disk_id: '{{ instance_create.disks.0.id }}' + description: 'cool2' + tags: + - 'test' + replica_regions: + - 'us-east' + - 'eu-west' + wait_for_replications: yes + wait_timeout: 1200 + state: present + register: image_replicate + + - name: Assert image is replicated in 2 regions + assert: + that: + - image_replicate.changed + - image_replicate.image.id == image_create.image.id + - image_replicate.image.regions | length == 2 + - image_replicate.image.regions[0].region == 'us-east' + - image_replicate.image.regions[0].status == 'available' + - image_replicate.image.regions[1].status == 'available' + + - name: Remove one of the image replicas + linode.cloud.image: + label: 'ansible-test-{{ r }}' + disk_id: '{{ instance_create.disks.0.id }}' + description: 'cool2' + tags: + - 'test' + replica_regions: + - 'eu-west' + wait_for_replications: yes + wait_timeout: 1200 + state: present + register: image_replicate + + - name: Assert image only has one replica left + assert: + that: + - image_replicate.changed + - image_replicate.image.regions | length == 1 + - image_replicate.image.regions[0].region == 'eu-west' + - image_replicate.image.regions[0].status == 'available' - name: Overwrite the image linode.cloud.image: label: 'ansible-test-{{ r }}' disk_id: '{{ instance_create.disks.0.id }}' description: 'yooo' + tags: + - 'new-tag' recreate: yes wait: no state: present @@ -83,6 +140,7 @@ - image_recreate.changed - image_recreate.image.id != image_create.image.id - image_recreate.image.description == 'yooo' + - image_recreate.image.tags[0] == 'new-tag' always: - ignore_errors: yes diff --git a/tests/integration/targets/instance_booted/tasks/main.yaml b/tests/integration/targets/instance_booted/tasks/main.yaml index 00ed40f6..5b0cd0ce 100644 --- a/tests/integration/targets/instance_booted/tasks/main.yaml +++ b/tests/integration/targets/instance_booted/tasks/main.yaml @@ -12,6 +12,7 @@ root_pass: Fn$$oobar123 private_ip: true booted: true + swap_size: 512 state: present firewall_id: '{{ firewall_id }}' register: create diff --git a/tests/integration/targets/nodebalancer_populated/tasks/main.yaml b/tests/integration/targets/nodebalancer_populated/tasks/main.yaml index 19958f1f..12b41757 100644 --- a/tests/integration/targets/nodebalancer_populated/tasks/main.yaml +++ b/tests/integration/targets/nodebalancer_populated/tasks/main.yaml @@ -248,26 +248,34 @@ - rm_config.configs|length == 1 - rm_config.nodes|length == 1 - - name: Get info about the NodeBalancer + - name: Get info about the NodeBalancer by label linode.cloud.nodebalancer_info: label: '{{ create_populated_nodebalancer.node_balancer.label }}' + register: nb_info_label + + - name: Get info about the NodeBalancer by id + linode.cloud.nodebalancer_info: id: '{{ create_populated_nodebalancer.node_balancer.id }}' - register: nb_info + register: nb_info_id - name: Assert that info is valid assert: that: - - nb_info.node_balancer.label == rm_config.node_balancer.label - - nb_info.configs|length == 1 - - nb_info.nodes|length == 1 - - nb_info.nodes[0] != None + - nb_info_label.node_balancer.label == rm_config.node_balancer.label + - nb_info_label.configs|length == 1 + - nb_info_label.nodes|length == 1 + - nb_info_label.nodes[0] != None + - nb_info_id.node_balancer.id == rm_config.node_balancer.id + - nb_info_id.configs|length == 1 + - nb_info_id.nodes|length == 1 + - nb_info_id.nodes[0] != None - name: Get info about a NodeBalancer that doesn't exist linode.cloud.nodebalancer_info: label: 'fake_nodebalancer-{{ r }}' register: fake_nb_info failed_when: - - "'failed' not in fake_nb_info.msg" + - "'Failed' not in fake_nb_info.msg" always: - ignore_errors: yes diff --git a/tests/integration/targets/nodebalancer_stats/tasks/main.yaml b/tests/integration/targets/nodebalancer_stats/tasks/main.yaml index b51b77cd..0d002d69 100644 --- a/tests/integration/targets/nodebalancer_stats/tasks/main.yaml +++ b/tests/integration/targets/nodebalancer_stats/tasks/main.yaml @@ -76,13 +76,11 @@ linode.cloud.nodebalancer_stats: id: '{{ create_populated_nodebalancer.node_balancer.id }}' register: nodebalancer_stats_id - failed_when: '"Stats are unavailable at this time" not in nodebalancer_stats_id.msg' - name: Get stats about the Nodebalancer by label linode.cloud.nodebalancer_stats: label: '{{ create_populated_nodebalancer.node_balancer.label }}' register: nodebalancer_stats_label - failed_when: '"Stats are unavailable at this time" not in nodebalancer_stats_label.msg' always: - ignore_errors: yes diff --git a/tests/integration/targets/user_info/tasks/main.yaml b/tests/integration/targets/user_info/tasks/main.yaml index b87b3648..efa15d3e 100644 --- a/tests/integration/targets/user_info/tasks/main.yaml +++ b/tests/integration/targets/user_info/tasks/main.yaml @@ -1,52 +1,50 @@ - name: user_info block: - - debug: - msg: Skipping for now...(https://jira.linode.com/browse/TPT-2939) -# - set_fact: -# r: "{{ 1000000000 | random }}" -# -# - name: Create Linode User -# linode.cloud.user: -# username: 'ansible-test-{{ r }}' -# email: 'ansible-test-{{ r }}@linode.com' -# state: present -# register: create -# -# - name: Assert user created -# assert: -# that: -# - create.user.email is not none -# - create.user.restricted == true -# -# - name: Print username for the created user -# debug: -# msg: "The username is: {{ create.user.username }}" -# -# - name: Get info about a user -# linode.cloud.user_info: -# username: "{{ create.user.username }}" -# register: user_info -# -# - name: Assert user_info for the created user -# assert: -# that: -# - user_info_valid | default(false) -# - user_info.user.email is defined -# - user_info.user.email | length > 0 -# when: user_info_valid | default(false) -# -# always: -# - ignore_errors: yes -# block: -# - name: Delete a Linode User -# linode.cloud.user: -# username: '{{ create.user.username }}' -# state: absent -# -# environment: -# LINODE_UA_PREFIX: '{{ ua_prefix }}' -# LINODE_API_TOKEN: '{{ api_token }}' -# LINODE_API_URL: '{{ api_url }}' -# LINODE_API_VERSION: '{{ api_version }}' -# LINODE_CA: '{{ ca_file or "" }}' -# + - set_fact: + r: "{{ 1000000000 | random }}" + + - name: Create Linode User + linode.cloud.user: + username: 'ansible-test-{{ r }}' + email: 'ansible-test-{{ r }}@linode.com' + state: present + register: create + + - name: Assert user created + assert: + that: + - create.user.email is not none + - create.user.restricted == true + + - name: Print username for the created user + debug: + msg: "The username is: {{ create.user.username }}" + + - name: Get info about a user + linode.cloud.user_info: + username: "{{ create.user.username }}" + register: user_info + + - name: Assert user_info for the created user + assert: + that: + - user_info_valid | default(false) + - user_info.user.email is defined + - user_info.user.email | length > 0 + when: user_info_valid | default(false) + + always: + - ignore_errors: yes + block: + - name: Delete a Linode User + linode.cloud.user: + username: '{{ create.user.username }}' + state: absent + + environment: + LINODE_UA_PREFIX: '{{ ua_prefix }}' + LINODE_API_TOKEN: '{{ api_token }}' + LINODE_API_URL: '{{ api_url }}' + LINODE_API_VERSION: '{{ api_version }}' + LINODE_CA: '{{ ca_file or "" }}' +