diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index f8a086cf..483155e9 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -206,7 +206,7 @@ jobs: steps: - name: Notify Slack id: main_message - uses: slackapi/slack-github-action@v2.0.0 + uses: slackapi/slack-github-action@v2.1.0 with: method: chat.postMessage token: ${{ secrets.SLACK_BOT_TOKEN }} @@ -238,7 +238,7 @@ jobs: - name: Test summary thread if: success() - uses: slackapi/slack-github-action@v2.0.0 + uses: slackapi/slack-github-action@v2.1.0 with: method: chat.postMessage token: ${{ secrets.SLACK_BOT_TOKEN }} diff --git a/.github/workflows/nightly-smoke-tests.yml b/.github/workflows/nightly-smoke-tests.yml index 58c239a8..867e5533 100644 --- a/.github/workflows/nightly-smoke-tests.yml +++ b/.github/workflows/nightly-smoke-tests.yml @@ -54,7 +54,7 @@ jobs: - name: Notify Slack if: (success() || failure()) && github.repository == 'linode/ansible_linode' - uses: slackapi/slack-github-action@v2.0.0 + uses: slackapi/slack-github-action@v2.1.0 with: method: chat.postMessage token: ${{ secrets.SLACK_BOT_TOKEN }} diff --git a/.github/workflows/release-notify-slack.yml b/.github/workflows/release-notify-slack.yml index d3f53cd0..6c8fd08b 100644 --- a/.github/workflows/release-notify-slack.yml +++ b/.github/workflows/release-notify-slack.yml @@ -11,7 +11,7 @@ jobs: steps: - name: Notify Slack - Main Message id: main_message - uses: slackapi/slack-github-action@v2.0.0 + uses: slackapi/slack-github-action@v2.1.0 with: method: chat.postMessage token: ${{ secrets.SLACK_BOT_TOKEN }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index f5cd811b..f423ebe2 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -18,12 +18,6 @@ jobs: with: path: .ansible/collections/ansible_collections/linode/cloud - - name: update packages - run: sudo apt-get update -y - - - name: install make - run: sudo apt-get install -y build-essential - - name: setup python 3 uses: actions/setup-python@v5 with: diff --git a/Makefile b/Makefile index d29c3113..1e9faa4f 100644 --- a/Makefile +++ b/Makefile @@ -122,9 +122,9 @@ else exit 1; endif @echo "ua_prefix: E2E" >> $(INTEGRATION_CONFIG) - @echo "api_url: $(TEST_API_URL)" >> $(INTEGRATION_CONFIG) - @echo "api_version: $(TEST_API_VERSION)" >> $(INTEGRATION_CONFIG) - @echo "ca_file: $(TEST_API_CA)" >> $(INTEGRATION_CONFIG) + @echo "api_url: $$(url=$${LINODE_API_URL:-$${TEST_API_URL:-https://api.linode.com}}; echo $${url%/}/)" >> $(INTEGRATION_CONFIG) + @echo "api_version: $${LINODE_API_VERSION:-$${TEST_API_VERSION:-v4beta}}" >> $(INTEGRATION_CONFIG) + @echo "ca_file: $${LINODE_CA:-$${TEST_API_CA}}" >> $(INTEGRATION_CONFIG) inject: @echo "Injecting documentation into source files" diff --git a/README.md b/README.md index 93aff512..28dea3cf 100644 --- a/README.md +++ b/README.md @@ -62,6 +62,7 @@ Name | Description | [linode.cloud.account_availability_info](./docs/modules/account_availability_info.md)|Get info about a Linode Account Availability.| [linode.cloud.account_info](./docs/modules/account_info.md)|Get info about a Linode Account.| [linode.cloud.child_account_info](./docs/modules/child_account_info.md)|Get info about a Linode Child Account.| +[linode.cloud.database_config_info](./docs/modules/database_config_info.md)|Get info about a Linode Configuration.| [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.| @@ -75,6 +76,7 @@ Name | Description | [linode.cloud.lke_version_info](./docs/modules/lke_version_info.md)|Get info about a Linode LKE Version.| [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.object_storage_quota_info](./docs/modules/object_storage_quota_info.md)|Get info about a Linode Object Storage Quota.| [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.| [linode.cloud.region_info](./docs/modules/region_info.md)|Get info about a Linode Region.| @@ -112,6 +114,7 @@ Name | Description | [linode.cloud.nodebalancer_type_list](./docs/modules/nodebalancer_type_list.md)|List and filter on Node Balancer Types.| [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.object_storage_endpoint_list](./docs/modules/object_storage_endpoint_list.md)|List and filter on Object Storage Endpoints.| +[linode.cloud.object_storage_quota_list](./docs/modules/object_storage_quota_list.md)|List and filter on Object Storage Quotas.| [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 Regions.| [linode.cloud.ssh_key_list](./docs/modules/ssh_key_list.md)|List and filter on SSH Keys.| diff --git a/docs/modules/database_config_info.md b/docs/modules/database_config_info.md new file mode 100644 index 00000000..34547c07 --- /dev/null +++ b/docs/modules/database_config_info.md @@ -0,0 +1,275 @@ +# database_config_info + +Get info about a Linode Configuration. + +- [Minimum Required Fields](#minimum-required-fields) +- [Examples](#examples) +- [Parameters](#parameters) +- [Return Values](#return-values) + +## Minimum Required Fields +| Field | Type | Required | Description | +|-------------|-------|--------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `api_token` | `str` | **Required** | The Linode account personal access token. It is necessary to run the module.
It can be exposed by the environment variable `LINODE_API_TOKEN` instead.
See details in [Usage](https://github.com/linode/ansible_linode?tab=readme-ov-file#usage). | + +## Examples + +```yaml +- name: Get all available engine configuration fields for MySQL databases + linode.cloud.database_config_info: + engine: mysql +``` + +```yaml +- name: Get all available engine configuration fields for PostgreSQL databases + linode.cloud.database_config_info: + engine: postgresql +``` + + +## Parameters + +| Field | Type | Required | Description | +|-----------|------|----------|------------------------------------------------------------------------------| +| `engine` |
`str`
|
**Required**
| The Database Engine of the Configuration to resolve. | + +## Return Values + +- `config` - The returned Configuration. + + - Sample Response: + ```json + + { + "binlog_retention_period": { + "description": "The minimum amount of time in seconds to keep binlog entries before deletion. This may be extended for services that require binlog entries for longer than the default for example if using the MySQL Debezium Kafka connector.", + "example": 600, + "maximum": 86400, + "minimum": 600, + "requires_restart": false, + "type": "integer" + }, + "mysql": { + "connect_timeout": { + "description": "The number of seconds that the mysqld server waits for a connect packet before responding with Bad handshake", + "example": 10, + "maximum": 3600, + "minimum": 2, + "requires_restart": false, + "type": "integer" + }, + "default_time_zone": { + "description": "Default server time zone as an offset from UTC (from -12:00 to +12:00), a time zone name, or 'SYSTEM' to use the MySQL server default.", + "example": "+03:00", + "maxLength": 100, + "minLength": 2, + "pattern": "^([-+][\\d:]*|[\\w/]*)$", + "requires_restart": false, + "type": "string" + }, + "group_concat_max_len": { + "description": "The maximum permitted result length in bytes for the GROUP_CONCAT() function.", + "example": 1024, + "maximum": 18446744073709551615, + "minimum": 4, + "requires_restart": false, + "type": "integer" + }, + "information_schema_stats_expiry": { + "description": "The time, in seconds, before cached statistics expire", + "example": 86400, + "maximum": 31536000, + "minimum": 900, + "requires_restart": false, + "type": "integer" + }, + "innodb_change_buffer_max_size": { + "description": "Maximum size for the InnoDB change buffer, as a percentage of the total size of the buffer pool. Default is 25", + "example": 30, + "maximum": 50, + "minimum": 0, + "requires_restart": false, + "type": "integer" + }, + "innodb_flush_neighbors": { + "description": "Specifies whether flushing a page from the InnoDB buffer pool also flushes other dirty pages in the same extent (default is 1): 0 - dirty pages in the same extent are not flushed, 1 - flush contiguous dirty pages in the same extent, 2 - flush dirty pages in the same extent", + "example": 0, + "maximum": 2, + "minimum": 0, + "requires_restart": false, + "type": "integer" + }, + "innodb_ft_min_token_size": { + "description": "Minimum length of words that are stored in an InnoDB FULLTEXT index. Changing this parameter will lead to a restart of the MySQL service.", + "example": 3, + "maximum": 16, + "minimum": 0, + "requires_restart": true, + "type": "integer" + }, + "innodb_ft_server_stopword_table": { + "description": "This option is used to specify your own InnoDB FULLTEXT index stopword list for all InnoDB tables.", + "example": "db_name/table_name", + "maxLength": 1024, + "pattern": "^.+/.+$", + "requires_restart": false, + "type": [ + "null", + "string" + ] + }, + "innodb_lock_wait_timeout": { + "description": "The length of time in seconds an InnoDB transaction waits for a row lock before giving up. Default is 120.", + "example": 50, + "maximum": 3600, + "minimum": 1, + "requires_restart": false, + "type": "integer" + }, + "innodb_log_buffer_size": { + "description": "The size in bytes of the buffer that InnoDB uses to write to the log files on disk.", + "example": 16777216, + "maximum": 4294967295, + "minimum": 1048576, + "requires_restart": false, + "type": "integer" + }, + "innodb_online_alter_log_max_size": { + "description": "The upper limit in bytes on the size of the temporary log files used during online DDL operations for InnoDB tables.", + "example": 134217728, + "maximum": 1099511627776, + "minimum": 65536, + "requires_restart": false, + "type": "integer" + }, + "innodb_read_io_threads": { + "description": "The number of I/O threads for read operations in InnoDB. Default is 4. Changing this parameter will lead to a restart of the MySQL service.", + "example": 10, + "maximum": 64, + "minimum": 1, + "requires_restart": true, + "type": "integer" + }, + "innodb_rollback_on_timeout": { + "description": "When enabled a transaction timeout causes InnoDB to abort and roll back the entire transaction. Changing this parameter will lead to a restart of the MySQL service.", + "example": true, + "requires_restart": true, + "type": "boolean" + }, + "innodb_thread_concurrency": { + "description": "Defines the maximum number of threads permitted inside of InnoDB. Default is 0 (infinite concurrency - no limit)", + "example": 10, + "maximum": 1000, + "minimum": 0, + "requires_restart": false, + "type": "integer" + }, + "innodb_write_io_threads": { + "description": "The number of I/O threads for write operations in InnoDB. Default is 4. Changing this parameter will lead to a restart of the MySQL service.", + "example": 10, + "maximum": 64, + "minimum": 1, + "requires_restart": true, + "type": "integer" + }, + "interactive_timeout": { + "description": "The number of seconds the server waits for activity on an interactive connection before closing it.", + "example": 3600, + "maximum": 604800, + "minimum": 30, + "requires_restart": false, + "type": "integer" + }, + "internal_tmp_mem_storage_engine": { + "description": "The storage engine for in-memory internal temporary tables.", + "enum": [ + "TempTable", + "MEMORY" + ], + "example": "TempTable", + "requires_restart": false, + "type": "string" + }, + "max_allowed_packet": { + "description": "Size of the largest message in bytes that can be received by the server. Default is 67108864 (64M)", + "example": 67108864, + "maximum": 1073741824, + "minimum": 102400, + "requires_restart": false, + "type": "integer" + }, + "max_heap_table_size": { + "description": "Limits the size of internal in-memory tables. Also set tmp_table_size. Default is 16777216 (16M)", + "example": 16777216, + "maximum": 1073741824, + "minimum": 1048576, + "requires_restart": false, + "type": "integer" + }, + "net_buffer_length": { + "description": "Start sizes of connection buffer and result buffer. Default is 16384 (16K). Changing this parameter will lead to a restart of the MySQL service.", + "example": 16384, + "maximum": 1048576, + "minimum": 1024, + "requires_restart": true, + "type": "integer" + }, + "net_read_timeout": { + "description": "The number of seconds to wait for more data from a connection before aborting the read.", + "example": 30, + "maximum": 3600, + "minimum": 1, + "requires_restart": false, + "type": "integer" + }, + "net_write_timeout": { + "description": "The number of seconds to wait for a block to be written to a connection before aborting the write.", + "example": 30, + "maximum": 3600, + "minimum": 1, + "requires_restart": false, + "type": "integer" + }, + "sort_buffer_size": { + "description": "Sort buffer size in bytes for ORDER BY optimization. Default is 262144 (256K)", + "example": 262144, + "maximum": 1073741824, + "minimum": 32768, + "requires_restart": false, + "type": "integer" + }, + "sql_mode": { + "description": "Global SQL mode. Set to empty to use MySQL server defaults. When creating a new service and not setting this field Akamai default SQL mode (strict, SQL standard compliant) will be assigned.", + "example": "ANSI,TRADITIONAL", + "maxLength": 1024, + "pattern": "^[A-Z_]*(,[A-Z_]+)*$", + "requires_restart": false, + "type": "string" + }, + "sql_require_primary_key": { + "description": "Require primary key to be defined for new tables or old tables modified with ALTER TABLE and fail if missing. It is recommended to always have primary keys because various functionality may break if any large table is missing them.", + "example": true, + "requires_restart": false, + "type": "boolean" + }, + "tmp_table_size": { + "description": "Limits the size of internal in-memory tables. Also set max_heap_table_size. Default is 16777216 (16M)", + "example": 16777216, + "maximum": 1073741824, + "minimum": 1048576, + "requires_restart": false, + "type": "integer" + }, + "wait_timeout": { + "description": "The number of seconds the server waits for activity on a noninteractive connection before closing it.", + "example": 28800, + "maximum": 2147483, + "minimum": 1, + "requires_restart": false, + "type": "integer" + } + } + } + ``` + + diff --git a/docs/modules/database_mysql_v2.md b/docs/modules/database_mysql_v2.md index cb9d7b0f..93fdf3e5 100644 --- a/docs/modules/database_mysql_v2.md +++ b/docs/modules/database_mysql_v2.md @@ -40,12 +40,16 @@ Create, read, and update a Linode MySQL database. ``` ```yaml -- name: Create a MySQL database with an explicit maintenance schedule +- name: Create a MySQL database with an explicit maintenance schedule and engine configuration linode.cloud.database_mysql_v2: label: my-db region: us-mia engine: mysql/8 type: g6-nanode-1 + engine_config: + binlog_retention_period: 600 + mysql: + connect_timeout: 20 updates: duration: 4 frequency: weekly @@ -78,10 +82,11 @@ Create, read, and update a Linode MySQL database. | Field | Type | Required | Description | |-----------|------|----------|------------------------------------------------------------------------------| -| `state` |
`str`
|
**Required**
| The desired state of the Managed Database. **(Choices: `present`, `absent`)** | +| `state` |
`str`
|
**Required**
| The desired state of the Managed Database. **(Choices: `resume`, `suspend`, `present`, `absent`)** | | `allow_list` |
`list`
|
Optional
| A list of IP addresses and CIDR ranges that can access the Managed Database. **(Updatable)** | | `cluster_size` |
`int`
|
Optional
| The number of Linode instance nodes deployed to the Managed Database. **(Updatable)** | | `engine` |
`str`
|
Optional
| The Managed Database engine in engine/version format. **(Updatable)** | +| [`engine_config` (sub-options)](#engine_config) |
`dict`
|
Optional
| Various parameters used to configure this database's underlying engine. NOTE: If a configuration parameter is not current accepted by this field, configure using the linode.cloud.api_request module. **(Updatable)** | | `label` |
`str`
|
Optional
| The label of the Managed Database. | | `region` |
`str`
|
Optional
| The region of the Managed Database. | | `type` |
`str`
|
Optional
| The Linode Instance type used by the Managed Database for its nodes. **(Updatable)** | @@ -89,6 +94,45 @@ Create, read, and update a Linode MySQL database. | [`updates` (sub-options)](#updates) |
`dict`
|
Optional
| Configuration settings for automated patch update maintenance for the Managed Database. **(Updatable)** | | `wait_timeout` |
`int`
|
Optional
| The maximum number of seconds a poll operation can take before raising an error. **(Default: `2700`)** | +### engine_config + +| Field | Type | Required | Description | +|-----------|------|----------|------------------------------------------------------------------------------| +| [`mysql` (sub-options)](#mysql) |
`dict`
|
Optional
| MySQL specific configuration fields. | +| `binlog_retention_period` |
`int`
|
Optional
| The minimum amount of time in seconds to keep binlog entries before deletion. This may be extended for use cases like MySQL Debezium Kafka connector. | + +### mysql + +| Field | Type | Required | Description | +|-----------|------|----------|------------------------------------------------------------------------------| +| `connect_timeout` |
`int`
|
Optional
| The number of seconds that the mysqld server waits for a connect packet before responding with Bad handshake. | +| `default_time_zone` |
`str`
|
Optional
| Default server time zone as an offset from UTC (from -12:00 to +12:00), a time zone name, or 'SYSTEM' to use the MySQL server default. | +| `group_concat_max_len` |
`int`
|
Optional
| The maximum permitted result length in bytes for the GROUP_CONCAT() function. | +| `information_schema_stats_expiry` |
`int`
|
Optional
| The time, in seconds, before cached statistics expire. | +| `innodb_change_buffer_max_size` |
`int`
|
Optional
| Maximum size for the InnoDB change buffer, as a percentage of the total size of the buffer pool. | +| `innodb_flush_neighbors` |
`int`
|
Optional
| Specifies whether flushing a page from the InnoDB buffer pool also flushes other dirty pages in the same extent. | +| `innodb_ft_min_token_size` |
`int`
|
Optional
| Minimum length of words that are stored in an InnoDB FULLTEXT index. | +| `innodb_ft_server_stopword_table` |
`str`
|
Optional
| This option is used to specify your own InnoDB FULLTEXT index stopword list for all InnoDB tables. | +| `innodb_lock_wait_timeout` |
`int`
|
Optional
| The length of time in seconds an InnoDB transaction waits for a row lock before giving up. | +| `innodb_log_buffer_size` |
`int`
|
Optional
| The size in bytes of the buffer that InnoDB uses to write to the log files on disk. | +| `innodb_online_alter_log_max_size` |
`int`
|
Optional
| The upper limit in bytes on the size of the temporary log files used during online DDL operations for InnoDB tables. | +| `innodb_read_io_threads` |
`int`
|
Optional
| The number of I/O threads for read operations in InnoDB. | +| `innodb_rollback_on_timeout` |
`bool`
|
Optional
| When enabled a transaction timeout causes InnoDB to abort and roll back the entire transaction. | +| `innodb_thread_concurrency` |
`int`
|
Optional
| Defines the maximum number of threads permitted inside of InnoDB. | +| `innodb_write_io_threads` |
`int`
|
Optional
| The number of I/O threads for write operations in InnoDB. | +| `interactive_timeout` |
`int`
|
Optional
| The number of seconds the server waits for activity on an interactive connection before closing it. | +| `internal_tmp_mem_storage_engine` |
`str`
|
Optional
| The storage engine for in-memory internal temporary tables. **(Choices: `TempTable`, `MEMORY`)** | +| `max_allowed_packet` |
`int`
|
Optional
| Size of the largest message in bytes that can be received by the server. Default is 67108864 (64M). | +| `max_heap_table_size` |
`int`
|
Optional
| Limits the size of internal in-memory tables. Also set tmp_table_size. Default is 16777216 (16M). | +| `net_buffer_length` |
`int`
|
Optional
| Start sizes of connection buffer and result buffer. Default is 16384 (16K). | +| `net_read_timeout` |
`int`
|
Optional
| The number of seconds to wait for more data from a connection before aborting the read. | +| `net_write_timeout` |
`int`
|
Optional
| The number of seconds to wait for a block to be written to a connection before aborting the write. | +| `sort_buffer_size` |
`int`
|
Optional
| Sort buffer size in bytes for ORDER BY optimization. Default is 262144 (256K). | +| `sql_mode` |
`str`
|
Optional
| Global SQL mode. Set to empty to use MySQL server defaults. | +| `sql_require_primary_key` |
`bool`
|
Optional
| Require primary key to be defined for new tables or old tables modified with ALTER TABLE and fail if missing. | +| `tmp_table_size` |
`int`
|
Optional
| Limits the size of internal in-memory tables. Also sets max_heap_table_size. Default is 16777216 (16M). | +| `wait_timeout` |
`int`
|
Optional
| The number of seconds the server waits for activity on a noninteractive connection before closing it. | + ### fork | Field | Type | Required | Description | @@ -112,42 +156,48 @@ Create, read, and update a Linode MySQL database. - Sample Response: ```json { - "allow_list": [ - "10.0.0.3/32" - ], - "cluster_size": 3, - "created": "2025-02-10T20:10:20", - "encrypted": true, - "engine": "mysql", - "hosts": { - "primary": "a225891-akamai-prod-1798333-default.g2a.akamaidb.net", - "standby": "replica-a225891-akamai-prod-1798333-default.g2a.akamaidb.net" - }, - "id": 12345, - "label": "my-db", - "members": { - "172.104.207.136": "primary", - "194.195.112.177": "failover", - "45.79.126.72": "failover" - }, - "oldest_restore_time": "2025-02-10T20:15:07", - "platform": "rdbms-default", - "port": 11876, - "region": "ap-west", - "ssl_connection": true, - "status": "active", - "total_disk_size_gb": 30, - "type": "g6-standard-1", - "updated": "2025-02-10T20:25:55", - "updates": { - "day_of_week": 4, - "duration": 4, - "frequency": "weekly", - "hour_of_day": 16, - "pending": [] - }, - "used_disk_size_gb": 0, - "version": "8.0.35" + "allow_list": [ + "10.0.0.3/32" + ], + "cluster_size": 3, + "created": "2025-02-10T20:10:20", + "encrypted": true, + "engine": "mysql", + "engine_config": { + "binlog_retention_period": 600, + "mysql": { + "connect_timeout": 20 + } + }, + "hosts": { + "primary": "a225891-akamai-prod-1798333-default.g2a.akamaidb.net", + "standby": "replica-a225891-akamai-prod-1798333-default.g2a.akamaidb.net" + }, + "id": 12345, + "label": "my-db", + "members": { + "172.104.207.136": "primary", + "194.195.112.177": "failover", + "45.79.126.72": "failover" + }, + "oldest_restore_time": "2025-02-10T20:15:07", + "platform": "rdbms-default", + "port": 11876, + "region": "ap-west", + "ssl_connection": true, + "status": "active", + "total_disk_size_gb": 30, + "type": "g6-standard-1", + "updated": "2025-02-10T20:25:55", + "updates": { + "day_of_week": 4, + "duration": 4, + "frequency": "weekly", + "hour_of_day": 16, + "pending": [] + }, + "used_disk_size_gb": 0, + "version": "8.0.35" } ``` - See the [Linode API response documentation](https://techdocs.akamai.com/linode-api/reference/get-databases-mysql-instance) for a list of returned fields diff --git a/docs/modules/database_postgresql_v2.md b/docs/modules/database_postgresql_v2.md index 1c38d834..3528e7dc 100644 --- a/docs/modules/database_postgresql_v2.md +++ b/docs/modules/database_postgresql_v2.md @@ -40,12 +40,16 @@ Create, read, and update a Linode PostgreSQL database. ``` ```yaml -- name: Create a PostgreSQL database with an explicit maintenance schedule +- name: Create a PostgreSQL database with an explicit maintenance schedule and engine configuration linode.cloud.database_postgresql_v2: label: my-db region: us-mia engine: postgresql/16 type: g6-nanode-1 + engine_config: + work_mem: 1023 + pg: + autovacuum_analyze_scale_factor: 0.2 updates: duration: 4 frequency: weekly @@ -78,10 +82,11 @@ Create, read, and update a Linode PostgreSQL database. | Field | Type | Required | Description | |-----------|------|----------|------------------------------------------------------------------------------| -| `state` |
`str`
|
**Required**
| The desired state of the Managed Database. **(Choices: `present`, `absent`)** | +| `state` |
`str`
|
**Required**
| The desired state of the Managed Database. **(Choices: `resume`, `suspend`, `present`, `absent`)** | | `allow_list` |
`list`
|
Optional
| A list of IP addresses and CIDR ranges that can access the Managed Database. **(Updatable)** | | `cluster_size` |
`int`
|
Optional
| The number of Linode instance nodes deployed to the Managed Database. **(Updatable)** | | `engine` |
`str`
|
Optional
| The Managed Database engine in engine/version format. **(Updatable)** | +| [`engine_config` (sub-options)](#engine_config) |
`dict`
|
Optional
| Various parameters used to configure this database's underlying engine. NOTE: If a configuration parameter is not current accepted by this field, configure using the linode.cloud.api_request module. **(Updatable)** | | `label` |
`str`
|
Optional
| The label of the Managed Database. | | `region` |
`str`
|
Optional
| The region of the Managed Database. | | `type` |
`str`
|
Optional
| The Linode Instance type used by the Managed Database for its nodes. **(Updatable)** | @@ -89,6 +94,70 @@ Create, read, and update a Linode PostgreSQL database. | [`updates` (sub-options)](#updates) |
`dict`
|
Optional
| Configuration settings for automated patch update maintenance for the Managed Database. **(Updatable)** | | `wait_timeout` |
`int`
|
Optional
| The maximum number of seconds a poll operation can take before raising an error. **(Default: `2700`)** | +### engine_config + +| Field | Type | Required | Description | +|-----------|------|----------|------------------------------------------------------------------------------| +| [`pg` (sub-options)](#pg) |
`dict`
|
Optional
| The configuration for PostgreSQL. Contains settings and controls for database behavior. | +| [`pglookout` (sub-options)](#pglookout) |
`dict`
|
Optional
| The configuration for pglookout. Contains controls for failover and replication settings. | +| `pg_stat_monitor_enable` |
`bool`
|
Optional
| Enable the pg_stat_monitor extension. Enabling this extension will cause the cluster to be restarted. When this extension is enabled, pg_stat_statements results for utility commands are unreliable. | +| `shared_buffers_percentage` |
`float`
|
Optional
| Percentage of total RAM that the database server uses for shared memory buffers. Valid range is 20-60 (float), which corresponds to 20% - 60%. This setting adjusts the shared_buffers configuration value. | +| `work_mem` |
`int`
|
Optional
| Sets the maximum amount of memory to be used by a query operation (such as a sort or hash table) before writing to temporary disk files, in MB. Default is 1MB + 0.075% of total RAM (up to 32MB). | + +### pg + +| Field | Type | Required | Description | +|-----------|------|----------|------------------------------------------------------------------------------| +| `autovacuum_analyze_scale_factor` |
`float`
|
Optional
| Specifies a fraction of the table size to add to autovacuum_analyze_threshold when deciding whether to trigger an ANALYZE. The default is 0.2 (20% of table size). | +| `autovacuum_analyze_threshold` |
`int`
|
Optional
| Specifies the minimum number of inserted, updated or deleted tuples needed to trigger an ANALYZE in any one table. The default is 50 tuples. | +| `autovacuum_max_workers` |
`int`
|
Optional
| Specifies the maximum number of autovacuum processes (other than the autovacuum launcher) that may be running at any one time. The default is three. This parameter can only be set at server start. | +| `autovacuum_naptime` |
`int`
|
Optional
| Specifies the minimum delay between autovacuum runs on any given database. The delay is measured in seconds, and the default is one minute. | +| `autovacuum_vacuum_cost_delay` |
`int`
|
Optional
| Specifies the cost delay value that will be used in automatic VACUUM operations. If -1 is specified, the regular vacuum_cost_delay value will be used. The default value is 20 milliseconds. | +| `autovacuum_vacuum_cost_limit` |
`int`
|
Optional
| Specifies the cost limit value that will be used in automatic VACUUM operations. If -1 is specified (which is the default), the regular vacuum_cost_limit value will be used. | +| `autovacuum_vacuum_scale_factor` |
`float`
|
Optional
| Specifies a fraction of the table size to add to autovacuum_vacuum_threshold when deciding whether to trigger a VACUUM. The default is 0.2 (20% of table size). | +| `autovacuum_vacuum_threshold` |
`int`
|
Optional
| Specifies the minimum number of updated or deleted tuples needed to trigger a VACUUM in any one table. The default is 50 tuples. | +| `bgwriter_delay` |
`int`
|
Optional
| Specifies the delay between activity rounds for the background writer in milliseconds. Default is 200. | +| `bgwriter_flush_after` |
`int`
|
Optional
| Whenever more than bgwriter_flush_after bytes have been written by the background writer, attempt to force the OS to issue these writes to the underlying storage. Specified in kilobytes, default is 512. Setting of 0 disables forced writeback. | +| `bgwriter_lru_maxpages` |
`int`
|
Optional
| In each round, no more than this many buffers will be written by the background writer. Setting this to zero disables background writing. Default is 100. | +| `bgwriter_lru_multiplier` |
`float`
|
Optional
| The average recent need for new buffers is multiplied by bgwriter_lru_multiplier to arrive at an estimate of the number that will be needed during the next round, (up to bgwriter_lru_maxpages). 1.0 represents a “just in time” policy of writing exactly the number of buffers predicted to be needed. Larger values provide some cushion against spikes in demand, while smaller values intentionally leave writes to be done by server processes. The default is 2.0. | +| `deadlock_timeout` |
`int`
|
Optional
| This is the amount of time, in milliseconds, to wait on a lock before checking to see if there is a deadlock condition. | +| `default_toast_compression` |
`str`
|
Optional
| Specifies the default TOAST compression method for values of compressible columns (the default is lz4). **(Choices: `pglz`, `lz4`)** | +| `idle_in_transaction_session_timeout` |
`int`
|
Optional
| Time out sessions with open transactions after this number of milliseconds. | +| `jit` |
`bool`
|
Optional
| Controls system-wide use of Just-in-Time Compilation (JIT). | +| `max_files_per_process` |
`int`
|
Optional
| PostgreSQL maximum number of files that can be open per process. | +| `max_locks_per_transaction` |
`int`
|
Optional
| PostgreSQL maximum locks per transaction. | +| `max_logical_replication_workers` |
`int`
|
Optional
| PostgreSQL maximum logical replication workers (taken from the pool of max_parallel_workers). | +| `max_parallel_workers` |
`int`
|
Optional
| Sets the maximum number of workers that the system can support for parallel queries. | +| `max_parallel_workers_per_gather` |
`int`
|
Optional
| Sets the maximum number of workers that can be started by a single Gather or Gather Merge node. | +| `max_pred_locks_per_transaction` |
`int`
|
Optional
| PostgreSQL maximum predicate locks per transaction. | +| `max_replication_slots` |
`int`
|
Optional
| PostgreSQL maximum replication slots. | +| `max_slot_wal_keep_size` |
`int`
|
Optional
| PostgreSQL maximum WAL size (MB) reserved for replication slots. Default is -1 (unlimited). wal_keep_size minimum WAL size setting takes precedence over this. | +| `max_stack_depth` |
`int`
|
Optional
| Maximum depth of the stack in bytes. | +| `max_standby_archive_delay` |
`int`
|
Optional
| Max standby archive delay in milliseconds. | +| `max_standby_streaming_delay` |
`int`
|
Optional
| Max standby streaming delay in milliseconds. | +| `max_wal_senders` |
`int`
|
Optional
| PostgreSQL maximum WAL senders. | +| `max_worker_processes` |
`int`
|
Optional
| Sets the maximum number of background processes that the system can support. | +| `password_encryption` |
`str`
|
Optional
| Chooses the algorithm for encrypting passwords. **(Choices: `md5`, `scram-sha-256`)** | +| `pg_partman_bgw.interval` |
`int`
|
Optional
| Sets the time interval to run pg_partman's scheduled tasks. | +| `pg_partman_bgw.role` |
`str`
|
Optional
| Controls which role to use for pg_partman's scheduled background tasks. | +| `pg_stat_monitor.pgsm_enable_query_plan` |
`bool`
|
Optional
| Enables or disables query plan monitoring. | +| `pg_stat_monitor.pgsm_max_buckets` |
`int`
|
Optional
| Sets the maximum number of buckets. | +| `pg_stat_statements.track` |
`str`
|
Optional
| Controls which statements are counted. Specify 'top' to track top-level statements (those issued directly by clients), 'all' to also track nested statements (such as statements invoked within functions), or 'none' to disable statement statistics collection. The default value is 'top'. **(Choices: `top`, `all`, `none`)** | +| `temp_file_limit` |
`int`
|
Optional
| PostgreSQL temporary file limit in KiB, -1 for unlimited. | +| `timezone` |
`str`
|
Optional
| PostgreSQL service timezone. | +| `track_activity_query_size` |
`int`
|
Optional
| Specifies the number of bytes reserved to track the currently executing command for each active session. | +| `track_commit_timestamp` |
`str`
|
Optional
| Record commit time of transactions. **(Choices: `on`, `off`)** | +| `track_functions` |
`str`
|
Optional
| Enables tracking of function call counts and time used. **(Choices: `none`, `pl`, `all`)** | +| `track_io_timing` |
`str`
|
Optional
| Enables timing of database I/O calls. This parameter is off by default, because it will repeatedly query the operating system for the current time, which may cause significant overhead on some platforms. | +| `wal_sender_timeout` |
`int`
|
Optional
| Terminate replication connections that are inactive for longer than this amount of time, in milliseconds. Setting this value to zero disables the timeout. | +| `wal_writer_delay` |
`int`
|
Optional
| WAL flush interval in milliseconds. Note that setting this value to lower than the default 200ms may negatively impact performance. | + +### pglookout + +| Field | Type | Required | Description | +|-----------|------|----------|------------------------------------------------------------------------------| +| `max_failover_replication_time_lag` |
`int`
|
Optional
| Number of seconds of master unavailability before triggering database failover to standby. | + ### fork | Field | Type | Required | Description | @@ -112,42 +181,48 @@ Create, read, and update a Linode PostgreSQL database. - Sample Response: ```json { - "allow_list": [ - "10.0.0.3/32" - ], - "cluster_size": 3, - "created": "2025-02-10T20:10:20", - "encrypted": true, - "engine": "postgresql", - "hosts": { - "primary": "a225891-akamai-prod-1798333-default.g2a.akamaidb.net", - "standby": "replica-a225891-akamai-prod-1798333-default.g2a.akamaidb.net" - }, - "id": 12345, - "label": "my-db", - "members": { - "172.104.207.136": "primary", - "194.195.112.177": "failover", - "45.79.126.72": "failover" - }, - "oldest_restore_time": "2025-02-10T20:15:07", - "platform": "rdbms-default", - "port": 11876, - "region": "ap-west", - "ssl_connection": true, - "status": "active", - "total_disk_size_gb": 30, - "type": "g6-standard-1", - "updated": "2025-02-10T20:25:55", - "updates": { - "day_of_week": 4, - "duration": 4, - "frequency": "weekly", - "hour_of_day": 16, - "pending": [] + "allow_list": [ + "10.0.0.3/32" + ], + "cluster_size": 3, + "created": "2025-02-10T20:10:20", + "encrypted": true, + "engine": "postgresql", + "engine_config": { + "pg": { + "autovacuum_analyze_scale_factor": 0.2 }, - "used_disk_size_gb": 0, - "version": "8.0.35" + "work_mem": 1023 + }, + "hosts": { + "primary": "a225891-akamai-prod-1798333-default.g2a.akamaidb.net", + "standby": "replica-a225891-akamai-prod-1798333-default.g2a.akamaidb.net" + }, + "id": 12345, + "label": "my-db", + "members": { + "172.104.207.136": "primary", + "194.195.112.177": "failover", + "45.79.126.72": "failover" + }, + "oldest_restore_time": "2025-02-10T20:15:07", + "platform": "rdbms-default", + "port": 11876, + "region": "ap-west", + "ssl_connection": true, + "status": "active", + "total_disk_size_gb": 30, + "type": "g6-standard-1", + "updated": "2025-02-10T20:25:55", + "updates": { + "day_of_week": 4, + "duration": 4, + "frequency": "weekly", + "hour_of_day": 16, + "pending": [] + }, + "used_disk_size_gb": 0, + "version": "8.0.35" } ``` - See the [Linode API response documentation](https://techdocs.akamai.com/linode-api/reference/get-databases-postgre-sql-instance) for a list of returned fields diff --git a/docs/modules/object_storage_quota_info.md b/docs/modules/object_storage_quota_info.md new file mode 100644 index 00000000..6cdc9349 --- /dev/null +++ b/docs/modules/object_storage_quota_info.md @@ -0,0 +1,60 @@ +# object_storage_quota_info + +Get info about a Linode Object Storage Quota. + +- [Minimum Required Fields](#minimum-required-fields) +- [Examples](#examples) +- [Parameters](#parameters) +- [Return Values](#return-values) + +## Minimum Required Fields +| Field | Type | Required | Description | +|-------------|-------|--------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `api_token` | `str` | **Required** | The Linode account personal access token. It is necessary to run the module.
It can be exposed by the environment variable `LINODE_API_TOKEN` instead.
See details in [Usage](https://github.com/linode/ansible_linode?tab=readme-ov-file#usage). | + +## Examples + +```yaml +- name: Get info about an Object Storage quota + linode.cloud.object_storage_quota_info: + quota_id: obj-buckets-us-sea-1.linodeobjects.com +``` + + +## Parameters + +| Field | Type | Required | Description | +|-----------|------|----------|------------------------------------------------------------------------------| +| `quota_id` |
`str`
|
**Required**
| The Quota ID of the Object Storage Quota to resolve. | + +## Return Values + +- `object_storage_quota` - The returned Object Storage Quota. + + - Sample Response: + ```json + { + "description": "Maximum number of buckets this customer is allowed to have on this endpoint", + "endpoint_type": "E1", + "quota_id": "obj-buckets-us-sea-1.linodeobjects.com", + "quota_limit": 1000, + "quota_name": "Number of Buckets", + "resource_metric": "bucket", + "s3_endpoint": "us-sea-1.linodeobjects.com" + } + ``` + - See the [Linode API response documentation](https://techdocs.akamai.com/linode-api/reference/get-object-storage-quota) for a list of returned fields + + +- `quota_usage` - The returned Quota Usage. + + - Sample Response: + ```json + { + "quota_limit": 1000, + "usage": 0 + } + ``` + - See the [Linode API response documentation](https://techdocs.akamai.com/linode-api/reference/get-object-storage-quota-usage) for a list of returned fields + + diff --git a/docs/modules/object_storage_quota_list.md b/docs/modules/object_storage_quota_list.md new file mode 100644 index 00000000..1a90750d --- /dev/null +++ b/docs/modules/object_storage_quota_list.md @@ -0,0 +1,72 @@ +# object_storage_quota_list + +List and filter on Object Storage Quotas. + +- [Minimum Required Fields](#minimum-required-fields) +- [Examples](#examples) +- [Parameters](#parameters) +- [Return Values](#return-values) + +## Minimum Required Fields +| Field | Type | Required | Description | +|-------------|-------|--------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `api_token` | `str` | **Required** | The Linode account personal access token. It is necessary to run the module.
It can be exposed by the environment variable `LINODE_API_TOKEN` instead.
See details in [Usage](https://github.com/linode/ansible_linode?tab=readme-ov-file#usage). | + +## Examples + +```yaml +- name: List all of Object Storage Quotas for the current account + linode.cloud.object_storage_quotas: + filters: + - name: s3_endpoint + values: + - es-mad-1.linodeobjects.com +``` + + +## Parameters + +| Field | Type | Required | Description | +|-----------|------|----------|------------------------------------------------------------------------------| +| `order` |
`str`
|
Optional
| The order to list Object Storage Quotas in. **(Choices: `desc`, `asc`; Default: `asc`)** | +| `order_by` |
`str`
|
Optional
| The attribute to order Object Storage Quotas by. | +| [`filters` (sub-options)](#filters) |
`list`
|
Optional
| A list of filters to apply to the resulting Object Storage Quotas. | +| `count` |
`int`
|
Optional
| The number of Object Storage Quotas 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 fields can be found [here](https://techdocs.akamai.com/linode-api/reference/get-object-storage-quotas). | +| `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 + +- `object_storage_quotas` - The returned Object Storage Quotas. + + - Sample Response: + ```json + [ + { + "description": "Maximum number of buckets this customer is allowed to have on this endpoint", + "endpoint_type": "E1", + "quota_id": "obj-buckets-es-mad-1.linodeobjects.com", + "quota_limit": 1000, + "quota_name": "Number of Buckets", + "resource_metric": "bucket", + "s3_endpoint": "es-mad-1.linodeobjects.com" + }, + { + "description": "Maximum number of bytes this customer is allowed to have on this endpoint", + "endpoint_type": "E1", + "quota_id": "obj-bytes-es-mad-1.linodeobjects.com", + "quota_limit": 109951162777600, + "quota_name": "Total Capacity", + "resource_metric": "byte", + "s3_endpoint": "es-mad-1.linodeobjects.com" + } + ] + ``` + - See the [Linode API response documentation](https://techdocs.akamai.com/linode-api/reference/get-object-storage-quotas) for a list of returned fields + + diff --git a/e2e_scripts b/e2e_scripts index a906260b..aa2e53fe 160000 --- a/e2e_scripts +++ b/e2e_scripts @@ -1 +1 @@ -Subproject commit a906260be88208a24d0a1af002a48f9c5efbd561 +Subproject commit aa2e53fe5aa8675a96f4026645fbf748f15655c7 diff --git a/plugins/module_utils/doc_fragments/database_config_info.py b/plugins/module_utils/doc_fragments/database_config_info.py new file mode 100644 index 00000000..0acfd976 --- /dev/null +++ b/plugins/module_utils/doc_fragments/database_config_info.py @@ -0,0 +1,241 @@ +"""Documentation fragments for the database_mysql module""" + +specdoc_examples = [''' +- name: Get all available engine configuration fields for MySQL databases + linode.cloud.database_config_info: + engine: mysql''', ''' +- name: Get all available engine configuration fields for PostgreSQL databases + linode.cloud.database_config_info: + engine: postgresql'''] + +result_config_samples = [r''' +{ + "binlog_retention_period": { + "description": "The minimum amount of time in seconds to keep binlog entries before deletion. This may be extended for services that require binlog entries for longer than the default for example if using the MySQL Debezium Kafka connector.", + "example": 600, + "maximum": 86400, + "minimum": 600, + "requires_restart": false, + "type": "integer" + }, + "mysql": { + "connect_timeout": { + "description": "The number of seconds that the mysqld server waits for a connect packet before responding with Bad handshake", + "example": 10, + "maximum": 3600, + "minimum": 2, + "requires_restart": false, + "type": "integer" + }, + "default_time_zone": { + "description": "Default server time zone as an offset from UTC (from -12:00 to +12:00), a time zone name, or 'SYSTEM' to use the MySQL server default.", + "example": "+03:00", + "maxLength": 100, + "minLength": 2, + "pattern": "^([-+][\\d:]*|[\\w/]*)$", + "requires_restart": false, + "type": "string" + }, + "group_concat_max_len": { + "description": "The maximum permitted result length in bytes for the GROUP_CONCAT() function.", + "example": 1024, + "maximum": 18446744073709551615, + "minimum": 4, + "requires_restart": false, + "type": "integer" + }, + "information_schema_stats_expiry": { + "description": "The time, in seconds, before cached statistics expire", + "example": 86400, + "maximum": 31536000, + "minimum": 900, + "requires_restart": false, + "type": "integer" + }, + "innodb_change_buffer_max_size": { + "description": "Maximum size for the InnoDB change buffer, as a percentage of the total size of the buffer pool. Default is 25", + "example": 30, + "maximum": 50, + "minimum": 0, + "requires_restart": false, + "type": "integer" + }, + "innodb_flush_neighbors": { + "description": "Specifies whether flushing a page from the InnoDB buffer pool also flushes other dirty pages in the same extent (default is 1): 0 - dirty pages in the same extent are not flushed, 1 - flush contiguous dirty pages in the same extent, 2 - flush dirty pages in the same extent", + "example": 0, + "maximum": 2, + "minimum": 0, + "requires_restart": false, + "type": "integer" + }, + "innodb_ft_min_token_size": { + "description": "Minimum length of words that are stored in an InnoDB FULLTEXT index. Changing this parameter will lead to a restart of the MySQL service.", + "example": 3, + "maximum": 16, + "minimum": 0, + "requires_restart": true, + "type": "integer" + }, + "innodb_ft_server_stopword_table": { + "description": "This option is used to specify your own InnoDB FULLTEXT index stopword list for all InnoDB tables.", + "example": "db_name/table_name", + "maxLength": 1024, + "pattern": "^.+/.+$", + "requires_restart": false, + "type": [ + "null", + "string" + ] + }, + "innodb_lock_wait_timeout": { + "description": "The length of time in seconds an InnoDB transaction waits for a row lock before giving up. Default is 120.", + "example": 50, + "maximum": 3600, + "minimum": 1, + "requires_restart": false, + "type": "integer" + }, + "innodb_log_buffer_size": { + "description": "The size in bytes of the buffer that InnoDB uses to write to the log files on disk.", + "example": 16777216, + "maximum": 4294967295, + "minimum": 1048576, + "requires_restart": false, + "type": "integer" + }, + "innodb_online_alter_log_max_size": { + "description": "The upper limit in bytes on the size of the temporary log files used during online DDL operations for InnoDB tables.", + "example": 134217728, + "maximum": 1099511627776, + "minimum": 65536, + "requires_restart": false, + "type": "integer" + }, + "innodb_read_io_threads": { + "description": "The number of I/O threads for read operations in InnoDB. Default is 4. Changing this parameter will lead to a restart of the MySQL service.", + "example": 10, + "maximum": 64, + "minimum": 1, + "requires_restart": true, + "type": "integer" + }, + "innodb_rollback_on_timeout": { + "description": "When enabled a transaction timeout causes InnoDB to abort and roll back the entire transaction. Changing this parameter will lead to a restart of the MySQL service.", + "example": true, + "requires_restart": true, + "type": "boolean" + }, + "innodb_thread_concurrency": { + "description": "Defines the maximum number of threads permitted inside of InnoDB. Default is 0 (infinite concurrency - no limit)", + "example": 10, + "maximum": 1000, + "minimum": 0, + "requires_restart": false, + "type": "integer" + }, + "innodb_write_io_threads": { + "description": "The number of I/O threads for write operations in InnoDB. Default is 4. Changing this parameter will lead to a restart of the MySQL service.", + "example": 10, + "maximum": 64, + "minimum": 1, + "requires_restart": true, + "type": "integer" + }, + "interactive_timeout": { + "description": "The number of seconds the server waits for activity on an interactive connection before closing it.", + "example": 3600, + "maximum": 604800, + "minimum": 30, + "requires_restart": false, + "type": "integer" + }, + "internal_tmp_mem_storage_engine": { + "description": "The storage engine for in-memory internal temporary tables.", + "enum": [ + "TempTable", + "MEMORY" + ], + "example": "TempTable", + "requires_restart": false, + "type": "string" + }, + "max_allowed_packet": { + "description": "Size of the largest message in bytes that can be received by the server. Default is 67108864 (64M)", + "example": 67108864, + "maximum": 1073741824, + "minimum": 102400, + "requires_restart": false, + "type": "integer" + }, + "max_heap_table_size": { + "description": "Limits the size of internal in-memory tables. Also set tmp_table_size. Default is 16777216 (16M)", + "example": 16777216, + "maximum": 1073741824, + "minimum": 1048576, + "requires_restart": false, + "type": "integer" + }, + "net_buffer_length": { + "description": "Start sizes of connection buffer and result buffer. Default is 16384 (16K). Changing this parameter will lead to a restart of the MySQL service.", + "example": 16384, + "maximum": 1048576, + "minimum": 1024, + "requires_restart": true, + "type": "integer" + }, + "net_read_timeout": { + "description": "The number of seconds to wait for more data from a connection before aborting the read.", + "example": 30, + "maximum": 3600, + "minimum": 1, + "requires_restart": false, + "type": "integer" + }, + "net_write_timeout": { + "description": "The number of seconds to wait for a block to be written to a connection before aborting the write.", + "example": 30, + "maximum": 3600, + "minimum": 1, + "requires_restart": false, + "type": "integer" + }, + "sort_buffer_size": { + "description": "Sort buffer size in bytes for ORDER BY optimization. Default is 262144 (256K)", + "example": 262144, + "maximum": 1073741824, + "minimum": 32768, + "requires_restart": false, + "type": "integer" + }, + "sql_mode": { + "description": "Global SQL mode. Set to empty to use MySQL server defaults. When creating a new service and not setting this field Akamai default SQL mode (strict, SQL standard compliant) will be assigned.", + "example": "ANSI,TRADITIONAL", + "maxLength": 1024, + "pattern": "^[A-Z_]*(,[A-Z_]+)*$", + "requires_restart": false, + "type": "string" + }, + "sql_require_primary_key": { + "description": "Require primary key to be defined for new tables or old tables modified with ALTER TABLE and fail if missing. It is recommended to always have primary keys because various functionality may break if any large table is missing them.", + "example": true, + "requires_restart": false, + "type": "boolean" + }, + "tmp_table_size": { + "description": "Limits the size of internal in-memory tables. Also set max_heap_table_size. Default is 16777216 (16M)", + "example": 16777216, + "maximum": 1073741824, + "minimum": 1048576, + "requires_restart": false, + "type": "integer" + }, + "wait_timeout": { + "description": "The number of seconds the server waits for activity on a noninteractive connection before closing it.", + "example": 28800, + "maximum": 2147483, + "minimum": 1, + "requires_restart": false, + "type": "integer" + } + } +}'''] diff --git a/plugins/module_utils/doc_fragments/database_mysql_v2.py b/plugins/module_utils/doc_fragments/database_mysql_v2.py index 4a63fde6..2b462977 100644 --- a/plugins/module_utils/doc_fragments/database_mysql_v2.py +++ b/plugins/module_utils/doc_fragments/database_mysql_v2.py @@ -20,12 +20,16 @@ allow_list: - 0.0.0.0/0 state: present''', ''' -- name: Create a MySQL database with an explicit maintenance schedule +- name: Create a MySQL database with an explicit maintenance schedule and engine configuration linode.cloud.database_mysql_v2: label: my-db region: us-mia engine: mysql/8 type: g6-nanode-1 + engine_config: + binlog_retention_period: 600 + mysql: + connect_timeout: 20 updates: duration: 4 frequency: weekly @@ -47,42 +51,48 @@ state: absent'''] result_database_samples = ['''{ - "allow_list": [ - "10.0.0.3/32" - ], - "cluster_size": 3, - "created": "2025-02-10T20:10:20", - "encrypted": true, - "engine": "mysql", - "hosts": { - "primary": "a225891-akamai-prod-1798333-default.g2a.akamaidb.net", - "standby": "replica-a225891-akamai-prod-1798333-default.g2a.akamaidb.net" - }, - "id": 12345, - "label": "my-db", - "members": { - "172.104.207.136": "primary", - "194.195.112.177": "failover", - "45.79.126.72": "failover" - }, - "oldest_restore_time": "2025-02-10T20:15:07", - "platform": "rdbms-default", - "port": 11876, - "region": "ap-west", - "ssl_connection": true, - "status": "active", - "total_disk_size_gb": 30, - "type": "g6-standard-1", - "updated": "2025-02-10T20:25:55", - "updates": { - "day_of_week": 4, - "duration": 4, - "frequency": "weekly", - "hour_of_day": 16, - "pending": [] - }, - "used_disk_size_gb": 0, - "version": "8.0.35" + "allow_list": [ + "10.0.0.3/32" + ], + "cluster_size": 3, + "created": "2025-02-10T20:10:20", + "encrypted": true, + "engine": "mysql", + "engine_config": { + "binlog_retention_period": 600, + "mysql": { + "connect_timeout": 20 + } + }, + "hosts": { + "primary": "a225891-akamai-prod-1798333-default.g2a.akamaidb.net", + "standby": "replica-a225891-akamai-prod-1798333-default.g2a.akamaidb.net" + }, + "id": 12345, + "label": "my-db", + "members": { + "172.104.207.136": "primary", + "194.195.112.177": "failover", + "45.79.126.72": "failover" + }, + "oldest_restore_time": "2025-02-10T20:15:07", + "platform": "rdbms-default", + "port": 11876, + "region": "ap-west", + "ssl_connection": true, + "status": "active", + "total_disk_size_gb": 30, + "type": "g6-standard-1", + "updated": "2025-02-10T20:25:55", + "updates": { + "day_of_week": 4, + "duration": 4, + "frequency": "weekly", + "hour_of_day": 16, + "pending": [] + }, + "used_disk_size_gb": 0, + "version": "8.0.35" }'''] result_credentials_samples = ['''{ diff --git a/plugins/module_utils/doc_fragments/database_postgresql_v2.py b/plugins/module_utils/doc_fragments/database_postgresql_v2.py index e764b540..c093e57f 100644 --- a/plugins/module_utils/doc_fragments/database_postgresql_v2.py +++ b/plugins/module_utils/doc_fragments/database_postgresql_v2.py @@ -20,12 +20,16 @@ allow_list: - 0.0.0.0/0 state: present''', ''' -- name: Create a PostgreSQL database with an explicit maintenance schedule +- name: Create a PostgreSQL database with an explicit maintenance schedule and engine configuration linode.cloud.database_postgresql_v2: label: my-db region: us-mia engine: postgresql/16 type: g6-nanode-1 + engine_config: + work_mem: 1023 + pg: + autovacuum_analyze_scale_factor: 0.2 updates: duration: 4 frequency: weekly @@ -47,42 +51,48 @@ state: absent'''] result_database_samples = ['''{ - "allow_list": [ - "10.0.0.3/32" - ], - "cluster_size": 3, - "created": "2025-02-10T20:10:20", - "encrypted": true, - "engine": "postgresql", - "hosts": { - "primary": "a225891-akamai-prod-1798333-default.g2a.akamaidb.net", - "standby": "replica-a225891-akamai-prod-1798333-default.g2a.akamaidb.net" + "allow_list": [ + "10.0.0.3/32" + ], + "cluster_size": 3, + "created": "2025-02-10T20:10:20", + "encrypted": true, + "engine": "postgresql", + "engine_config": { + "pg": { + "autovacuum_analyze_scale_factor": 0.2 }, - "id": 12345, - "label": "my-db", - "members": { - "172.104.207.136": "primary", - "194.195.112.177": "failover", - "45.79.126.72": "failover" - }, - "oldest_restore_time": "2025-02-10T20:15:07", - "platform": "rdbms-default", - "port": 11876, - "region": "ap-west", - "ssl_connection": true, - "status": "active", - "total_disk_size_gb": 30, - "type": "g6-standard-1", - "updated": "2025-02-10T20:25:55", - "updates": { - "day_of_week": 4, - "duration": 4, - "frequency": "weekly", - "hour_of_day": 16, - "pending": [] - }, - "used_disk_size_gb": 0, - "version": "8.0.35" + "work_mem": 1023 + }, + "hosts": { + "primary": "a225891-akamai-prod-1798333-default.g2a.akamaidb.net", + "standby": "replica-a225891-akamai-prod-1798333-default.g2a.akamaidb.net" + }, + "id": 12345, + "label": "my-db", + "members": { + "172.104.207.136": "primary", + "194.195.112.177": "failover", + "45.79.126.72": "failover" + }, + "oldest_restore_time": "2025-02-10T20:15:07", + "platform": "rdbms-default", + "port": 11876, + "region": "ap-west", + "ssl_connection": true, + "status": "active", + "total_disk_size_gb": 30, + "type": "g6-standard-1", + "updated": "2025-02-10T20:25:55", + "updates": { + "day_of_week": 4, + "duration": 4, + "frequency": "weekly", + "hour_of_day": 16, + "pending": [] + }, + "used_disk_size_gb": 0, + "version": "8.0.35" }'''] result_credentials_samples = ['''{ diff --git a/plugins/module_utils/doc_fragments/object_storage_quota_info.py b/plugins/module_utils/doc_fragments/object_storage_quota_info.py new file mode 100644 index 00000000..3086b3a1 --- /dev/null +++ b/plugins/module_utils/doc_fragments/object_storage_quota_info.py @@ -0,0 +1,22 @@ +"""Documentation fragments for the object_storage_quota_info module""" + +result_object_storage_quota_samples = ['''{ + "description": "Maximum number of buckets this customer is allowed to have on this endpoint", + "endpoint_type": "E1", + "quota_id": "obj-buckets-us-sea-1.linodeobjects.com", + "quota_limit": 1000, + "quota_name": "Number of Buckets", + "resource_metric": "bucket", + "s3_endpoint": "us-sea-1.linodeobjects.com" +}'''] + +result_object_storage_quota_usage_samples = ['''{ + "quota_limit": 1000, + "usage": 0 +}'''] + + +specdoc_examples = [''' +- name: Get info about an Object Storage quota + linode.cloud.object_storage_quota_info: + quota_id: obj-buckets-us-sea-1.linodeobjects.com'''] diff --git a/plugins/module_utils/doc_fragments/object_storage_quota_list.py b/plugins/module_utils/doc_fragments/object_storage_quota_list.py new file mode 100644 index 00000000..804504f8 --- /dev/null +++ b/plugins/module_utils/doc_fragments/object_storage_quota_list.py @@ -0,0 +1,30 @@ +"""Documentation fragments for the object_storage_quota_list module""" + +specdoc_examples = [''' +- name: List all of Object Storage Quotas for the current account + linode.cloud.object_storage_quotas: + filters: + - name: s3_endpoint + values: + - es-mad-1.linodeobjects.com'''] + +result_object_storage_quotas_samples = ['''[ + { + "description": "Maximum number of buckets this customer is allowed to have on this endpoint", + "endpoint_type": "E1", + "quota_id": "obj-buckets-es-mad-1.linodeobjects.com", + "quota_limit": 1000, + "quota_name": "Number of Buckets", + "resource_metric": "bucket", + "s3_endpoint": "es-mad-1.linodeobjects.com" + }, + { + "description": "Maximum number of bytes this customer is allowed to have on this endpoint", + "endpoint_type": "E1", + "quota_id": "obj-bytes-es-mad-1.linodeobjects.com", + "quota_limit": 109951162777600, + "quota_name": "Total Capacity", + "resource_metric": "byte", + "s3_endpoint": "es-mad-1.linodeobjects.com" + } +]'''] diff --git a/plugins/module_utils/linode_common_list.py b/plugins/module_utils/linode_common_list.py index 7c82d9fa..e89e6d59 100644 --- a/plugins/module_utils/linode_common_list.py +++ b/plugins/module_utils/linode_common_list.py @@ -61,6 +61,7 @@ def __init__( deprecation_message: Optional[str] = None, custom_options: Optional[Dict[str, SpecField]] = None, custom_field_resolver: Optional[callable] = None, + custom_api_filter_constructor: Optional[callable] = None, ) -> None: self.result_display_name = result_display_name self.result_field_name = result_field_name @@ -69,6 +70,9 @@ def __init__( # Store the custom field resolver, if provided self.custom_field_resolver = custom_field_resolver + # Store the custom api filter constructor, if provided + self.custom_api_filter_constructor = custom_api_filter_constructor + self.result_docs_url = ( result_docs_url or "https://techdocs.akamai.com/linode-api/reference/api" @@ -102,7 +106,12 @@ def exec_module(self, **kwargs: Any) -> Optional[dict]: if self.deprecated: self.warn(self.deprecation_message) - filter_dict = construct_api_filter(self.module.params) + # Use custom API filter constructor if provided + filter_dict = ( + self.custom_api_filter_constructor(self.module.params) + if self.custom_api_filter_constructor + else construct_api_filter(self.module.params) + ) # Dynamically resolve fields if custom logic is provided if self.custom_field_resolver: diff --git a/plugins/module_utils/linode_helper.py b/plugins/module_utils/linode_helper.py index 4a30c474..a68885f4 100644 --- a/plugins/module_utils/linode_helper.py +++ b/plugins/module_utils/linode_helper.py @@ -5,6 +5,7 @@ import linode_api4 import polling from linode_api4 import ( + JSONObject, LinodeClient, LKENodePool, LKENodePoolNode, @@ -190,6 +191,9 @@ def parse_linode_types(value: any) -> any: if isinstance(value, dict): return {k: parse_linode_types(elem) for k, elem in value.items()} + if issubclass(type(value), JSONObject): + return parse_linode_types(value.dict) + if type(value) in { linode_api4.objects.linode.Type, linode_api4.objects.linode.Region, diff --git a/plugins/modules/database_config_info.py b/plugins/modules/database_config_info.py new file mode 100644 index 00000000..d34af086 --- /dev/null +++ b/plugins/modules/database_config_info.py @@ -0,0 +1,76 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +""" +Implementation of linode.cloud.database_config_info module. + +More information is available here: + https://techdocs.akamai.com/linode-api/reference/get-databases-mysql-config + https://techdocs.akamai.com/linode-api/reference/get-databases-postgresql-config +""" + +from __future__ import absolute_import, division, print_function + +from typing import Any, Dict + +from ansible_collections.linode.cloud.plugins.module_utils.doc_fragments import ( + database_config_info as docs, +) +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 LinodeClient + + +def __resolve_by_engine( + client: LinodeClient, params: Dict[str, Any] +) -> Dict[str, Any]: + engine_resolvers = { + "mysql": client.database.mysql_config_options, + "postgresql": client.database.postgresql_config_options, + } + + engine = params.get("engine").lower() + if engine not in engine_resolvers: + raise ValueError( + f"Invalid engine {engine}; must be one of {', '.join(engine_resolvers.keys())}." + ) + + return engine_resolvers[engine]() + + +module = InfoModule( + primary_result=InfoModuleResult( + field_name="config", + field_type=FieldType.dict, + display_name="Configuration", + docs_url=None, + samples=docs.result_config_samples, + ), + attributes=[ + InfoModuleAttr( + display_name="Database Engine", + name="engine", + type=FieldType.string, + get=__resolve_by_engine, + ) + ], + examples=docs.specdoc_examples, +) + +SPECDOC_META = module.spec + +DOCUMENTATION = r""" +""" +EXAMPLES = r""" +""" +RETURN = r""" +""" + +if __name__ == "__main__": + module.run() diff --git a/plugins/modules/database_mysql_v2.py b/plugins/modules/database_mysql_v2.py index 9a7d114f..63e0c9c4 100644 --- a/plugins/modules/database_mysql_v2.py +++ b/plugins/modules/database_mysql_v2.py @@ -37,10 +37,210 @@ ) from linode_api4 import MySQLDatabase +SPEC_ENGINE_CONFIG_MYSQL = { + "connect_timeout": SpecField( + type=FieldType.integer, + description=[ + "The number of seconds that the mysqld server waits for a connect packet " + + "before responding with Bad handshake." + ], + ), + "default_time_zone": SpecField( + type=FieldType.string, + description=[ + "Default server time zone as an offset from UTC (from -12:00 to +12:00), " + + "a time zone name, or 'SYSTEM' to use the MySQL server default." + ], + ), + "group_concat_max_len": SpecField( + type=FieldType.integer, + description=[ + "The maximum permitted result length in bytes for the GROUP_CONCAT() function." + ], + ), + "information_schema_stats_expiry": SpecField( + type=FieldType.integer, + description=["The time, in seconds, before cached statistics expire."], + ), + "innodb_change_buffer_max_size": SpecField( + type=FieldType.integer, + description=[ + "Maximum size for the InnoDB change buffer, " + + "as a percentage of the total size of the buffer pool." + ], + ), + "innodb_flush_neighbors": SpecField( + type=FieldType.integer, + description=[ + "Specifies whether flushing a page from the InnoDB buffer pool also " + + "flushes other dirty pages in the same extent." + ], + ), + "innodb_ft_min_token_size": SpecField( + type=FieldType.integer, + description=[ + "Minimum length of words that are stored in an InnoDB FULLTEXT index." + ], + ), + "innodb_ft_server_stopword_table": SpecField( + type=FieldType.string, + description=[ + "This option is used to specify your own InnoDB FULLTEXT " + + "index stopword list for all InnoDB tables." + ], + ), + "innodb_lock_wait_timeout": SpecField( + type=FieldType.integer, + description=[ + "The length of time in seconds an InnoDB transaction waits " + + "for a row lock before giving up." + ], + ), + "innodb_log_buffer_size": SpecField( + type=FieldType.integer, + description=[ + "The size in bytes of the buffer that InnoDB uses to write to the log files on disk." + ], + ), + "innodb_online_alter_log_max_size": SpecField( + type=FieldType.integer, + description=[ + "The upper limit in bytes on the size of the temporary log files " + + "used during online DDL operations for InnoDB tables." + ], + ), + "innodb_read_io_threads": SpecField( + type=FieldType.integer, + description=[ + "The number of I/O threads for read operations in InnoDB." + ], + ), + "innodb_rollback_on_timeout": SpecField( + type=FieldType.bool, + description=[ + "When enabled a transaction timeout causes InnoDB to " + + "abort and roll back the entire transaction." + ], + ), + "innodb_thread_concurrency": SpecField( + type=FieldType.integer, + description=[ + "Defines the maximum number of threads permitted inside of InnoDB." + ], + ), + "innodb_write_io_threads": SpecField( + type=FieldType.integer, + description=[ + "The number of I/O threads for write operations in InnoDB." + ], + ), + "interactive_timeout": SpecField( + type=FieldType.integer, + description=[ + "The number of seconds the server waits for activity on an " + + "interactive connection before closing it." + ], + ), + "internal_tmp_mem_storage_engine": SpecField( + type=FieldType.string, + description=[ + "The storage engine for in-memory internal temporary tables." + ], + choices=["TempTable", "MEMORY"], + ), + "max_allowed_packet": SpecField( + type=FieldType.integer, + description=[ + "Size of the largest message in bytes that can be received by the server.", + "Default is 67108864 (64M).", + ], + ), + "max_heap_table_size": SpecField( + type=FieldType.integer, + description=[ + "Limits the size of internal in-memory tables.", + "Also set tmp_table_size.", + "Default is 16777216 (16M).", + ], + ), + "net_buffer_length": SpecField( + type=FieldType.integer, + description=[ + "Start sizes of connection buffer and result buffer.", + "Default is 16384 (16K).", + ], + ), + "net_read_timeout": SpecField( + type=FieldType.integer, + description=[ + "The number of seconds to wait for more data from a connection " + + "before aborting the read." + ], + ), + "net_write_timeout": SpecField( + type=FieldType.integer, + description=[ + "The number of seconds to wait for a block to be written " + + "to a connection before aborting the write." + ], + ), + "sort_buffer_size": SpecField( + type=FieldType.integer, + description=[ + "Sort buffer size in bytes for ORDER BY optimization.", + "Default is 262144 (256K).", + ], + ), + "sql_mode": SpecField( + type=FieldType.string, + description=[ + "Global SQL mode.", + "Set to empty to use MySQL server defaults.", + ], + ), + "sql_require_primary_key": SpecField( + type=FieldType.bool, + description=[ + "Require primary key to be defined for new tables or old tables modified " + + "with ALTER TABLE and fail if missing." + ], + ), + "tmp_table_size": SpecField( + type=FieldType.integer, + description=[ + "Limits the size of internal in-memory tables.", + "Also sets max_heap_table_size.", + "Default is 16777216 (16M).", + ], + ), + "wait_timeout": SpecField( + type=FieldType.integer, + description=[ + "The number of seconds the server waits for activity on a " + + "noninteractive connection before closing it." + ], + ), +} + +SPEC_ENGINE_CONFIG = { + "mysql": SpecField( + type=FieldType.dict, + suboptions=SPEC_ENGINE_CONFIG_MYSQL, + description=["MySQL specific configuration fields."], + ), + "binlog_retention_period": SpecField( + type=FieldType.integer, + description=[ + "The minimum amount of time in seconds to keep binlog entries before deletion.", + "This may be extended for use cases like MySQL Debezium Kafka connector.", + ], + ), +} + SPEC = { "state": SpecField( type=FieldType.string, - choices=["present", "absent"], + choices=["resume", "suspend", "present", "absent"], required=True, description=["The desired state of the Managed Database."], ), @@ -64,6 +264,16 @@ description=["The Managed Database engine in engine/version format."], editable=True, ), + "engine_config": SpecField( + type=FieldType.dict, + suboptions=SPEC_ENGINE_CONFIG, + description=[ + "Various parameters used to configure this database's underlying engine.", + "NOTE: If a configuration parameter is not current accepted by this field, " + + "configure using the linode.cloud.api_request module.", + ], + editable=True, + ), "label": SpecField( type=FieldType.string, description=["The label of the Managed Database."], @@ -172,6 +382,7 @@ def _create(self) -> MySQLDatabase: "allow_list", "cluster_size", "engine", + "engine_config", "fork", "label", "region", @@ -254,6 +465,7 @@ def _update(self, database: MySQLDatabase) -> None: "label", "allow_list", "cluster_size", + "engine_config", "updates", "type", "version", @@ -311,7 +523,7 @@ def _handle_present(self) -> None: self._populate_results(result) - def _handle_absent(self) -> None: + def _handle_else(self, state: str) -> None: params = self.module.params database = safe_find( @@ -322,18 +534,33 @@ def _handle_absent(self) -> None: if database is not None: self._populate_results(database) - database.delete() + if state == "suspend": + self._handle_suspend(database) + elif state == "resume": + self._handle_resume(database) + else: + self._handle_absent(database) + + def _handle_absent(self, database: MySQLDatabase) -> None: + database.delete() + self.register_action(f"Deleted MySQL database {database.id}") - self.register_action(f"Deleted MySQL database {database.id}") + def _handle_suspend(self, database: MySQLDatabase) -> None: + database.suspend() + self.register_action(f"Suspended MySQL database {database.id}") + + def _handle_resume(self, database: MySQLDatabase) -> None: + database.resume() + self.register_action(f"Resumed MySQL database {database.id}") def exec_module(self, **kwargs: Any) -> Optional[dict]: """Entrypoint for token module""" state = kwargs.get("state") - if state == "absent": - self._handle_absent() - else: + if state == "present": self._handle_present() + else: + self._handle_else(state) return self.results diff --git a/plugins/modules/database_postgresql_v2.py b/plugins/modules/database_postgresql_v2.py index b98bce8b..c1fd69fa 100644 --- a/plugins/modules/database_postgresql_v2.py +++ b/plugins/modules/database_postgresql_v2.py @@ -39,10 +39,361 @@ ) from linode_api4 import PostgreSQLDatabase +SPEC_ENGINE_CONFIG_PG = { + "autovacuum_analyze_scale_factor": SpecField( + type=FieldType.float, + description=[ + "Specifies a fraction of the table size to add to " + + "autovacuum_analyze_threshold when deciding " + + "whether to trigger an ANALYZE.", + "The default is 0.2 (20% of table size).", + ], + ), + "autovacuum_analyze_threshold": SpecField( + type=FieldType.integer, + description=[ + "Specifies the minimum number of inserted, updated or deleted " + + "tuples needed to trigger " + "an ANALYZE in any one table.", + "The default is 50 tuples.", + ], + ), + "autovacuum_max_workers": SpecField( + type=FieldType.integer, + description=[ + "Specifies the maximum number of autovacuum processes " + + "(other than the autovacuum launcher) " + + "that may be running at any one time.", + "The default is three.", + "This parameter can only be set at server start.", + ], + ), + "autovacuum_naptime": SpecField( + type=FieldType.integer, + description=[ + "Specifies the minimum delay between autovacuum runs on any given database.", + "The delay is measured in seconds, and the default is one minute.", + ], + ), + "autovacuum_vacuum_cost_delay": SpecField( + type=FieldType.integer, + description=[ + "Specifies the cost delay value that will be used in automatic VACUUM operations.", + "If -1 is specified, the regular vacuum_cost_delay value will be used.", + "The default value is 20 milliseconds.", + ], + ), + "autovacuum_vacuum_cost_limit": SpecField( + type=FieldType.integer, + description=[ + "Specifies the cost limit value that will be used in automatic VACUUM operations.", + "If -1 is specified (which is the default), the regular " + + "vacuum_cost_limit value will be used.", + ], + ), + "autovacuum_vacuum_scale_factor": SpecField( + type=FieldType.float, + description=[ + "Specifies a fraction of the table size to add to " + + "autovacuum_vacuum_threshold when deciding " + + "whether to trigger a VACUUM.", + "The default is 0.2 (20% of table size).", + ], + ), + "autovacuum_vacuum_threshold": SpecField( + type=FieldType.integer, + description=[ + "Specifies the minimum number of updated or deleted tuples needed to " + + "trigger a VACUUM in any one table.", + "The default is 50 tuples.", + ], + ), + "bgwriter_delay": SpecField( + type=FieldType.integer, + description=[ + "Specifies the delay between activity rounds for the " + + "background writer in milliseconds.", + "Default is 200.", + ], + ), + "bgwriter_flush_after": SpecField( + type=FieldType.integer, + description=[ + "Whenever more than bgwriter_flush_after bytes have been " + + "written by the background writer, attempt to " + + "force the OS to issue these writes to the underlying storage.", + "Specified in kilobytes, default is 512.", + "Setting of 0 disables forced writeback.", + ], + ), + "bgwriter_lru_maxpages": SpecField( + type=FieldType.integer, + description=[ + "In each round, no more than this many buffers will be " + + "written by the background writer.", + "Setting this to zero disables background writing.", + "Default is 100.", + ], + ), + "bgwriter_lru_multiplier": SpecField( + type=FieldType.float, + description=[ + "The average recent need for new buffers is multiplied by " + + "bgwriter_lru_multiplier to arrive at an estimate of the number " + + "that will be needed during the next round, (up to bgwriter_lru_maxpages).", + "1.0 represents a “just in time” policy of writing exactly the number of " + + "buffers predicted to be needed.", + "Larger values provide some cushion against spikes in demand, " + + "while smaller values intentionally leave writes " + "to be done by server processes.", + "The default is 2.0.", + ], + ), + "deadlock_timeout": SpecField( + type=FieldType.integer, + description=[ + "This is the amount of time, in milliseconds, to wait on a lock " + + "before checking to see if there is a deadlock condition." + ], + ), + "default_toast_compression": SpecField( + type=FieldType.string, + description=[ + "Specifies the default TOAST compression method for values of " + + "compressible columns (the default is lz4)." + ], + choices=["pglz", "lz4"], + ), + "idle_in_transaction_session_timeout": SpecField( + type=FieldType.integer, + description=[ + "Time out sessions with open transactions after this number of milliseconds." + ], + ), + "jit": SpecField( + type=FieldType.bool, + description=[ + "Controls system-wide use of Just-in-Time Compilation (JIT)." + ], + ), + "max_files_per_process": SpecField( + type=FieldType.integer, + description=[ + "PostgreSQL maximum number of files that can be open per process." + ], + ), + "max_locks_per_transaction": SpecField( + type=FieldType.integer, + description=["PostgreSQL maximum locks per transaction."], + ), + "max_logical_replication_workers": SpecField( + type=FieldType.integer, + description=[ + "PostgreSQL maximum logical replication workers " + + "(taken from the pool of max_parallel_workers)." + ], + ), + "max_parallel_workers": SpecField( + type=FieldType.integer, + description=[ + "Sets the maximum number of workers that the system " + + "can support for parallel queries." + ], + ), + "max_parallel_workers_per_gather": SpecField( + type=FieldType.integer, + description=[ + "Sets the maximum number of workers that can be started " + + "by a single Gather or Gather Merge node." + ], + ), + "max_pred_locks_per_transaction": SpecField( + type=FieldType.integer, + description=["PostgreSQL maximum predicate locks per transaction."], + ), + "max_replication_slots": SpecField( + type=FieldType.integer, + description=["PostgreSQL maximum replication slots."], + ), + "max_slot_wal_keep_size": SpecField( + type=FieldType.integer, + description=[ + "PostgreSQL maximum WAL size (MB) reserved for replication slots.", + "Default is -1 (unlimited).", + "wal_keep_size minimum WAL size setting takes precedence over this.", + ], + ), + "max_stack_depth": SpecField( + type=FieldType.integer, + description=["Maximum depth of the stack in bytes."], + ), + "max_standby_archive_delay": SpecField( + type=FieldType.integer, + description=["Max standby archive delay in milliseconds."], + ), + "max_standby_streaming_delay": SpecField( + type=FieldType.integer, + description=["Max standby streaming delay in milliseconds."], + ), + "max_wal_senders": SpecField( + type=FieldType.integer, + description=["PostgreSQL maximum WAL senders."], + ), + "max_worker_processes": SpecField( + type=FieldType.integer, + description=[ + "Sets the maximum number of background processes that the system can support." + ], + ), + "password_encryption": SpecField( + type=FieldType.string, + description=["Chooses the algorithm for encrypting passwords."], + choices=["md5", "scram-sha-256"], + ), + "pg_partman_bgw.interval": SpecField( + type=FieldType.integer, + description=[ + "Sets the time interval to run pg_partman's scheduled tasks." + ], + ), + "pg_partman_bgw.role": SpecField( + type=FieldType.string, + description=[ + "Controls which role to use for pg_partman's scheduled background tasks." + ], + ), + "pg_stat_monitor.pgsm_enable_query_plan": SpecField( + type=FieldType.bool, + description=["Enables or disables query plan monitoring."], + ), + "pg_stat_monitor.pgsm_max_buckets": SpecField( + type=FieldType.integer, + description=["Sets the maximum number of buckets."], + ), + "pg_stat_statements.track": SpecField( + type=FieldType.string, + description=[ + "Controls which statements are counted.", + "Specify 'top' to track top-level statements (those issued directly by clients), " + + "'all' to also track nested statements (such as statements " + + "invoked within functions), or 'none' to disable statement statistics collection.", + "The default value is 'top'.", + ], + choices=["top", "all", "none"], + ), + "temp_file_limit": SpecField( + type=FieldType.integer, + description=[ + "PostgreSQL temporary file limit in KiB, -1 for unlimited." + ], + ), + "timezone": SpecField( + type=FieldType.string, + description=["PostgreSQL service timezone."], + ), + "track_activity_query_size": SpecField( + type=FieldType.integer, + description=[ + "Specifies the number of bytes reserved to track the currently " + + "executing command for each active session." + ], + ), + "track_commit_timestamp": SpecField( + type=FieldType.string, + description=["Record commit time of transactions."], + choices=["on", "off"], + ), + "track_functions": SpecField( + type=FieldType.string, + description=["Enables tracking of function call counts and time used."], + choices=["none", "pl", "all"], + ), + "track_io_timing": SpecField( + type=FieldType.string, + description=[ + "Enables timing of database I/O calls.", + "This parameter is off by default, because it will repeatedly " + + "query the operating system for the current time, which may " + "cause significant overhead on some platforms.", + ], + ), + "wal_sender_timeout": SpecField( + type=FieldType.integer, + description=[ + "Terminate replication connections that are inactive for " + + "longer than this amount of time, in milliseconds.", + "Setting this value to zero disables the timeout.", + ], + ), + "wal_writer_delay": SpecField( + type=FieldType.integer, + description=[ + "WAL flush interval in milliseconds.", + "Note that setting this value to lower than the default 200ms " + + "may negatively impact performance.", + ], + ), +} + +SPEC_ENGINE_CONFIG_PGLOOKOUT = { + "max_failover_replication_time_lag": SpecField( + type=FieldType.integer, + description=[ + "Number of seconds of master unavailability before " + + "triggering database failover to standby." + ], + ) +} + +SPEC_ENGINE_CONFIG = { + "pg": SpecField( + type=FieldType.dict, + suboptions=SPEC_ENGINE_CONFIG_PG, + description=[ + "The configuration for PostgreSQL.", + "Contains settings and controls for database behavior.", + ], + ), + "pglookout": SpecField( + type=FieldType.dict, + suboptions=SPEC_ENGINE_CONFIG_PGLOOKOUT, + description=[ + "The configuration for pglookout.", + "Contains controls for failover and replication settings.", + ], + ), + "pg_stat_monitor_enable": SpecField( + type=FieldType.bool, + description=[ + "Enable the pg_stat_monitor extension.", + "Enabling this extension will cause the cluster to be restarted.", + "When this extension is enabled, pg_stat_statements results " + + "for utility commands are unreliable.", + ], + ), + "shared_buffers_percentage": SpecField( + type=FieldType.float, + description=[ + "Percentage of total RAM that the database server uses for shared memory buffers.", + "Valid range is 20-60 (float), which corresponds to 20% - 60%.", + "This setting adjusts the shared_buffers configuration value.", + ], + ), + "work_mem": SpecField( + type=FieldType.integer, + description=[ + "Sets the maximum amount of memory to be used by a " + + "query operation (such as a sort or hash table) " + + "before writing to temporary disk files, in MB.", + "Default is 1MB + 0.075% of total RAM (up to 32MB).", + ], + ), +} + SPEC = { "state": SpecField( type=FieldType.string, - choices=["present", "absent"], + choices=["resume", "suspend", "present", "absent"], required=True, description=["The desired state of the Managed Database."], ), @@ -66,6 +417,16 @@ description=["The Managed Database engine in engine/version format."], editable=True, ), + "engine_config": SpecField( + type=FieldType.dict, + suboptions=SPEC_ENGINE_CONFIG, + description=[ + "Various parameters used to configure this database's underlying engine.", + "NOTE: If a configuration parameter is not current accepted by this field, " + + "configure using the linode.cloud.api_request module.", + ], + editable=True, + ), "label": SpecField( type=FieldType.string, description=["The label of the Managed Database."], @@ -174,6 +535,7 @@ def _create(self) -> PostgreSQLDatabase: "allow_list", "cluster_size", "engine", + "engine_config", "fork", "label", "region", @@ -250,6 +612,7 @@ def _update(self, database: PostgreSQLDatabase) -> None: "label", "allow_list", "cluster_size", + "engine_config", "updates", "type", "version", @@ -309,7 +672,7 @@ def _handle_present(self) -> None: self._populate_results(result) - def _handle_absent(self) -> None: + def _handle_else(self, state: str) -> None: params = self.module.params database = safe_find( @@ -320,18 +683,33 @@ def _handle_absent(self) -> None: if database is not None: self._populate_results(database) - database.delete() + if state == "suspend": + self._handle_suspend(database) + elif state == "resume": + self._handle_resume(database) + else: + self._handle_absent(database) + + def _handle_absent(self, database: PostgreSQLDatabase) -> None: + database.delete() + self.register_action(f"Deleted PostgreSQL database {database.id}") + + def _handle_suspend(self, database: PostgreSQLDatabase) -> None: + database.suspend() + self.register_action(f"Suspended PostgreSQL database {database.id}") - self.register_action(f"Deleted PostgreSQL database {database.id}") + def _handle_resume(self, database: PostgreSQLDatabase) -> None: + database.resume() + self.register_action(f"Resumed PostgreSQL database {database.id}") def exec_module(self, **kwargs: Any) -> Optional[dict]: """Entrypoint for token module""" state = kwargs.get("state") - if state == "absent": - self._handle_absent() - else: + if state == "present": self._handle_present() + else: + self._handle_else(state) return self.results diff --git a/plugins/modules/instance.py b/plugins/modules/instance.py index da097020..081b9844 100644 --- a/plugins/modules/instance.py +++ b/plugins/modules/instance.py @@ -1089,7 +1089,8 @@ def _update_config( if key == "interfaces": old_value = filter_null_values_recursive( [ - drop_empty_strings(v._serialize(), recursive=True) + # v is implicitly flattened to a dict in parse_linode_types(...) + drop_empty_strings(v, recursive=True) for v in old_value ] ) diff --git a/plugins/modules/object_storage_quota_info.py b/plugins/modules/object_storage_quota_info.py new file mode 100644 index 00000000..47880da4 --- /dev/null +++ b/plugins/modules/object_storage_quota_info.py @@ -0,0 +1,65 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +"""This module contains all of the functionality for Linode Object Storage Quota info.""" + +from __future__ import absolute_import, division, print_function + +from ansible_collections.linode.cloud.plugins.module_utils.doc_fragments import ( + object_storage_quota_info as docs, +) +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 ObjectStorageQuota + +module = InfoModule( + examples=docs.specdoc_examples, + primary_result=InfoModuleResult( + display_name="Object Storage Quota", + field_name="object_storage_quota", + field_type=FieldType.dict, + docs_url="https://techdocs.akamai.com/linode-api/reference/get-object-storage-quota", + samples=docs.result_object_storage_quota_samples, + ), + secondary_results=[ + InfoModuleResult( + display_name="Quota Usage", + field_name="quota_usage", + field_type=FieldType.dict, + docs_url="https://techdocs.akamai.com/linode-api/reference" + "/get-object-storage-quota-usage", + samples=docs.result_object_storage_quota_usage_samples, + get=lambda client, object_storage_quota, params: ObjectStorageQuota( + client, object_storage_quota["quota_id"] + ) + .usage() + .dict, + ), + ], + attributes=[ + InfoModuleAttr( + name="quota_id", + display_name="Quota ID", + type=FieldType.string, + get=lambda client, params: client.load( + ObjectStorageQuota, params.get("quota_id") + )._raw_json, + ), + ], +) + +SPECDOC_META = module.spec + +DOCUMENTATION = r""" +""" +EXAMPLES = r""" +""" +RETURN = r""" +""" + +if __name__ == "__main__": + module.run() diff --git a/plugins/modules/object_storage_quota_list.py b/plugins/modules/object_storage_quota_list.py new file mode 100644 index 00000000..43f6fa3e --- /dev/null +++ b/plugins/modules/object_storage_quota_list.py @@ -0,0 +1,65 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +"""This module allows users to list Object Storage Quotas.""" + +from __future__ import absolute_import, division, print_function + +from typing import Any, Dict + +from ansible_collections.linode.cloud.plugins.module_utils.doc_fragments import ( + object_storage_quota_list as docs, +) +from ansible_collections.linode.cloud.plugins.module_utils.linode_common_list import ( + ListModule, +) + + +def custom_api_filter_constructor(params: Dict[str, Any]) -> Dict[str, Any]: + """ + Customize a filter string for listing Object Storage Quota, + because only a single basic filterable parameter can be supported currently by API. + """ + if params.get("order_by") is not None or params.get("order") is not None: + module.warn( + "order or order_by is currently not supported in listing object_storage_quotas, " + "and will be ignored if provided. " + "Please refer to the API documentation for more information." + ) + + filters = params.get("filters") + + if filters is not None: + if len(filters) == 1 and len(filters[0]["values"]) == 1: + return {filters[0]["name"]: filters[0]["values"][0]} + module.fail( + "[error] The filter is not acceptable. " + "Only a single filterable parameter can be supported currently by API. " + "The filterable fields are limited. " + "Please refer to the API documentation for more information." + ) + + return {} + + +module = ListModule( + result_display_name="Object Storage Quotas", + result_field_name="object_storage_quotas", + endpoint_template="/object-storage/quotas", + result_docs_url="https://techdocs.akamai.com/linode-api/reference/get-object-storage-quotas", + result_samples=docs.result_object_storage_quotas_samples, + examples=docs.specdoc_examples, + custom_api_filter_constructor=custom_api_filter_constructor, +) + +SPECDOC_META = module.spec + +DOCUMENTATION = r""" +""" +EXAMPLES = r""" +""" +RETURN = r""" +""" + +if __name__ == "__main__": + module.run() diff --git a/requirements.txt b/requirements.txt index a2165761..05222cc5 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,3 @@ -linode-api4>=5.29.0 +linode-api4>=5.31.0 polling==0.3.2 ansible-specdoc>=0.0.19 diff --git a/tests/integration/targets/database_config_info/tasks/main.yaml b/tests/integration/targets/database_config_info/tasks/main.yaml new file mode 100644 index 00000000..22213378 --- /dev/null +++ b/tests/integration/targets/database_config_info/tasks/main.yaml @@ -0,0 +1,96 @@ +- name: database_config_info + block: + - name: Get all available configuration fields for MySQL databases + linode.cloud.database_config_info: + engine: mysql + register: get_database_config_mysql + + - name: Assert the returned MySQL configuration fields match the expected schema + assert: + that: + - get_database_config_mysql.config.binlog_retention_period.type == "integer" + - get_database_config_mysql.config.binlog_retention_period.description != None + - get_database_config_mysql.config.mysql.innodb_flush_neighbors.type == "integer" + - get_database_config_mysql.config.mysql.innodb_flush_neighbors.description != None + + - name: Assert MySQL config structure and types + assert: + that: + - get_database_config_mysql.config.mysql.connect_timeout.type == "integer" + - get_database_config_mysql.config.mysql.default_time_zone.type == "string" + - get_database_config_mysql.config.mysql.group_concat_max_len.type == "integer" + - get_database_config_mysql.config.mysql.information_schema_stats_expiry.type == "integer" + - get_database_config_mysql.config.mysql.innodb_change_buffer_max_size.type == "integer" + - get_database_config_mysql.config.mysql.innodb_flush_neighbors.type == "integer" + - get_database_config_mysql.config.mysql.innodb_ft_min_token_size.type == "integer" + - get_database_config_mysql.config.mysql.innodb_lock_wait_timeout.type == "integer" + - get_database_config_mysql.config.mysql.innodb_log_buffer_size.type == "integer" + - get_database_config_mysql.config.mysql.innodb_online_alter_log_max_size.type == "integer" + - get_database_config_mysql.config.mysql.innodb_read_io_threads.type == "integer" + - get_database_config_mysql.config.mysql.innodb_rollback_on_timeout.type == "boolean" + - get_database_config_mysql.config.mysql.innodb_thread_concurrency.type == "integer" + - get_database_config_mysql.config.mysql.innodb_write_io_threads.type == "integer" + - get_database_config_mysql.config.mysql.interactive_timeout.type == "integer" + - get_database_config_mysql.config.mysql.max_allowed_packet.type == "integer" + - get_database_config_mysql.config.mysql.max_heap_table_size.type == "integer" + - get_database_config_mysql.config.mysql.net_buffer_length.type == "integer" + - get_database_config_mysql.config.mysql.net_read_timeout.type == "integer" + - get_database_config_mysql.config.mysql.net_write_timeout.type == "integer" + - get_database_config_mysql.config.mysql.sql_mode.type == "string" + - get_database_config_mysql.config.mysql.sql_require_primary_key.type == "boolean" + - get_database_config_mysql.config.mysql.tmp_table_size.type == "integer" + - get_database_config_mysql.config.mysql.wait_timeout.type == "integer" + + - name: Get all available configuration fields for PostgreSQL databases + linode.cloud.database_config_info: + engine: postgresql + register: get_database_config_postgresql + + - name: Assert the returned PostgreSQL configuration fields match the expected schema + assert: + that: + - get_database_config_postgresql.config.pg.bgwriter_lru_multiplier.type == "number" + - get_database_config_postgresql.config.pg.bgwriter_lru_multiplier.description != None + - get_database_config_postgresql.config.pglookout.max_failover_replication_time_lag.type == "integer" + - get_database_config_postgresql.config.pglookout.max_failover_replication_time_lag.description != None + + - name: Assert types of PostgreSQL config values + assert: + that: + - get_database_config_postgresql.config.pg.autovacuum_analyze_scale_factor.type == "number" + - get_database_config_postgresql.config.pg.autovacuum_analyze_threshold.type == "integer" + - get_database_config_postgresql.config.pg.autovacuum_max_workers.type == "integer" + - get_database_config_postgresql.config.pg.autovacuum_naptime.type == "integer" + - get_database_config_postgresql.config.pg.autovacuum_vacuum_cost_delay.type == "integer" + - get_database_config_postgresql.config.pg.autovacuum_vacuum_cost_limit.type == "integer" + - get_database_config_postgresql.config.pg.autovacuum_vacuum_scale_factor.type == "number" + - get_database_config_postgresql.config.pg.autovacuum_vacuum_threshold.type == "integer" + - get_database_config_postgresql.config.pg.bgwriter_delay.type == "integer" + - get_database_config_postgresql.config.pg.bgwriter_flush_after.type == "integer" + - get_database_config_postgresql.config.pg.bgwriter_lru_maxpages.type == "integer" + - get_database_config_postgresql.config.pg.bgwriter_lru_multiplier.type == "number" + - get_database_config_postgresql.config.pg.deadlock_timeout.type == "integer" + - get_database_config_postgresql.config.pg.default_toast_compression.type == "string" + - get_database_config_postgresql.config.pg.idle_in_transaction_session_timeout.type == "integer" + - get_database_config_postgresql.config.pg.jit.type == "boolean" + - get_database_config_postgresql.config.pg.max_files_per_process.type == "integer" + - get_database_config_postgresql.config.pg.max_locks_per_transaction.type == "integer" + - get_database_config_postgresql.config.pg.max_logical_replication_workers.type == "integer" + - get_database_config_postgresql.config.pg.max_parallel_workers.type == "integer" + - get_database_config_postgresql.config.pg.max_parallel_workers_per_gather.type == "integer" + - get_database_config_postgresql.config.pg.max_pred_locks_per_transaction.type == "integer" + - get_database_config_postgresql.config.pg.max_replication_slots.type == "integer" + - get_database_config_postgresql.config.pg.max_slot_wal_keep_size.type == "integer" + - get_database_config_postgresql.config.pg.max_stack_depth.type == "integer" + - get_database_config_postgresql.config.pg.max_standby_archive_delay.type == "integer" + - get_database_config_postgresql.config.pg.max_standby_streaming_delay.type == "integer" + - get_database_config_postgresql.config.pg.max_wal_senders.type == "integer" + - get_database_config_postgresql.config.pg.max_worker_processes.type == "integer" + - get_database_config_postgresql.config.pg.password_encryption.default == "md5" + + 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 "" }}' diff --git a/tests/integration/targets/database_mysql_v2_basic/tasks/main.yaml b/tests/integration/targets/database_mysql_v2_basic/tasks/main.yaml index f94cdde3..bf56a405 100644 --- a/tests/integration/targets/database_mysql_v2_basic/tasks/main.yaml +++ b/tests/integration/targets/database_mysql_v2_basic/tasks/main.yaml @@ -94,6 +94,28 @@ that: - db_refresh.changed == False + - name: Suspend the database + linode.cloud.database_mysql_v2: + label: "ansible-test-{{ r }}" + state: suspend + register: db_suspend + + - name: Assert database is suspended + assert: + that: + - db_suspend.changed == True + + - name: Resume the database + linode.cloud.database_mysql_v2: + label: "ansible-test-{{ r }}" + state: resume + register: db_resume + + - name: Assert database is resumed + assert: + that: + - db_resume.changed == True + always: - ignore_errors: true block: diff --git a/tests/integration/targets/database_mysql_v2_engine_config/tasks/main.yaml b/tests/integration/targets/database_mysql_v2_engine_config/tasks/main.yaml new file mode 100644 index 00000000..ea640de0 --- /dev/null +++ b/tests/integration/targets/database_mysql_v2_engine_config/tasks/main.yaml @@ -0,0 +1,277 @@ +- name: database_mysql_v2_engine_config + block: + - set_fact: + r: "{{ 1000000000 | random }}" + + - name: List regions + linode.cloud.region_list: {} + register: all_regions + + - set_fact: + target_region: '{{ (all_regions.regions | selectattr("capabilities", "search", "Databases") | list)[0]["id"] }}' + + - name: Get an available MySQL engine + linode.cloud.database_engine_list: + filters: + - name: engine + values: mysql + register: available_engines + + - name: Assert available database_engine_list + assert: + that: + - available_engines.database_engines | length >= 1 + + - set_fact: + engine_id: "{{ available_engines.database_engines[0]['id'] }}" + + - name: Create a database with an explicit engine_config + linode.cloud.database_mysql_v2: + label: "ansible-test-{{ r }}" + region: "{{ target_region }}" + engine: "{{ engine_id }}" + type: g6-nanode-1 + cluster_size: 1 + engine_config: + binlog_retention_period: 600 + mysql: + connect_timeout: 20 + default_time_zone: "+00:00" + group_concat_max_len: 1024 + information_schema_stats_expiry: 900 + innodb_change_buffer_max_size: 25 + innodb_flush_neighbors: 1 + innodb_ft_min_token_size: 3 + innodb_ft_server_stopword_table: # check if this value can be null + innodb_lock_wait_timeout: 50 + innodb_log_buffer_size: 16777216 + innodb_online_alter_log_max_size: 134217728 + innodb_read_io_threads: 4 + innodb_rollback_on_timeout: True + innodb_thread_concurrency: 8 + innodb_write_io_threads: 4 + interactive_timeout: 300 + internal_tmp_mem_storage_engine: "TempTable" + max_allowed_packet: 67108864 + max_heap_table_size: 16777216 + net_buffer_length: 16384 + net_read_timeout: 30 + net_write_timeout: 60 + sort_buffer_size: 262144 + sql_mode: "TRADITIONAL" + sql_require_primary_key: False + tmp_table_size: 16777216 + wait_timeout: 28800 + state: present + register: db_create + + - name: Assert database is created + assert: + that: + - db_create.changed + - db_create.database.status == 'active' + - db_create.database.cluster_size == 1 + - db_create.database.engine == 'mysql' + - db_create.database.region == target_region + - db_create.database.engine_config.binlog_retention_period == 600 + - db_create.database.engine_config.mysql.connect_timeout == 20 + - db_create.database.engine_config.mysql.default_time_zone == "+00:00" + - db_create.database.engine_config.mysql.group_concat_max_len == 1024 + - db_create.database.engine_config.mysql.information_schema_stats_expiry == 900 + - db_create.database.engine_config.mysql.innodb_change_buffer_max_size == 25 + - db_create.database.engine_config.mysql.innodb_flush_neighbors == 1 + - db_create.database.engine_config.mysql.innodb_ft_min_token_size == 3 + - db_create.database.engine_config.mysql.get('innodb_ft_server_stopword_table', None) is none + - db_create.database.engine_config.mysql.innodb_lock_wait_timeout == 50 + - db_create.database.engine_config.mysql.innodb_log_buffer_size == 16777216 + - db_create.database.engine_config.mysql.innodb_online_alter_log_max_size == 134217728 + - db_create.database.engine_config.mysql.innodb_read_io_threads == 4 + - db_create.database.engine_config.mysql.innodb_rollback_on_timeout == True + - db_create.database.engine_config.mysql.innodb_thread_concurrency == 8 + - db_create.database.engine_config.mysql.innodb_write_io_threads == 4 + - db_create.database.engine_config.mysql.interactive_timeout == 300 + - db_create.database.engine_config.mysql.internal_tmp_mem_storage_engine == "TempTable" + - db_create.database.engine_config.mysql.max_allowed_packet == 67108864 + - db_create.database.engine_config.mysql.max_heap_table_size == 16777216 + - db_create.database.engine_config.mysql.net_buffer_length == 16384 + - db_create.database.engine_config.mysql.net_read_timeout == 30 + - db_create.database.engine_config.mysql.net_write_timeout == 60 + - db_create.database.engine_config.mysql.sort_buffer_size == 262144 + - db_create.database.engine_config.mysql.sql_mode == "TRADITIONAL" + - db_create.database.engine_config.mysql.sql_require_primary_key == False + - db_create.database.engine_config.mysql.tmp_table_size == 16777216 + - db_create.database.engine_config.mysql.wait_timeout == 28800 + + - name: Assert nullable field safely returns null + assert: + that: + - db_create.database.engine_config.mysql.get('innodb_ft_server_stopword_table', None) is none + + - name: Update the database's engine_config + linode.cloud.database_mysql_v2: + label: "ansible-test-{{ r }}" + region: "{{ target_region }}" + engine: "{{ engine_id }}" + type: g6-nanode-1 + engine_config: + binlog_retention_period: 601 + mysql: + connect_timeout: 21 + default_time_zone: "+01:00" + group_concat_max_len: 1023 + information_schema_stats_expiry: 901 + innodb_change_buffer_max_size: 26 + innodb_flush_neighbors: 2 + innodb_ft_min_token_size: 4 + innodb_ft_server_stopword_table: "db_name/table_name" + innodb_lock_wait_timeout: 51 + innodb_log_buffer_size: 16777215 + innodb_online_alter_log_max_size: 134217721 + innodb_read_io_threads: 3 + innodb_rollback_on_timeout: False + innodb_thread_concurrency: 6 + innodb_write_io_threads: 5 + interactive_timeout: 299 + internal_tmp_mem_storage_engine: "MEMORY" + max_allowed_packet: 67108863 + max_heap_table_size: 16777211 + net_buffer_length: 8192 + net_read_timeout: 29 + net_write_timeout: 59 + sort_buffer_size: 262141 + sql_mode: "TRADITIONAL" + sql_require_primary_key: True + tmp_table_size: 16777215 + wait_timeout: 28799 + state: present + register: db_update + + - name: Assert database is updated + assert: + that: + - db_update.changed + - db_update.database.status == 'active' + - db_update.database.cluster_size == 1 + - db_update.database.engine == 'mysql' + - db_update.database.region == target_region + - db_update.database.type == 'g6-nanode-1' + - db_update.database.engine_config.binlog_retention_period == 601 + - db_update.database.engine_config.mysql.connect_timeout == 21 + - db_update.database.engine_config.mysql.default_time_zone == "+01:00" + - db_update.database.engine_config.mysql.group_concat_max_len == 1023 + - db_update.database.engine_config.mysql.information_schema_stats_expiry == 901 + - db_update.database.engine_config.mysql.innodb_change_buffer_max_size == 26 + - db_update.database.engine_config.mysql.innodb_flush_neighbors == 2 + - db_update.database.engine_config.mysql.innodb_ft_min_token_size == 4 + - db_update.database.engine_config.mysql.innodb_ft_server_stopword_table == "db_name/table_name" + - db_update.database.engine_config.mysql.innodb_lock_wait_timeout == 51 + - db_update.database.engine_config.mysql.innodb_log_buffer_size == 16777215 + - db_update.database.engine_config.mysql.innodb_online_alter_log_max_size == 134217721 + - db_update.database.engine_config.mysql.innodb_read_io_threads == 3 + - db_update.database.engine_config.mysql.innodb_rollback_on_timeout == False + - db_update.database.engine_config.mysql.innodb_thread_concurrency == 6 + - db_update.database.engine_config.mysql.innodb_write_io_threads == 5 + - db_update.database.engine_config.mysql.interactive_timeout == 299 + - db_update.database.engine_config.mysql.internal_tmp_mem_storage_engine == "MEMORY" + - db_update.database.engine_config.mysql.max_allowed_packet == 67108863 + - db_update.database.engine_config.mysql.max_heap_table_size == 16777211 + - db_update.database.engine_config.mysql.net_buffer_length == 8192 + - db_update.database.engine_config.mysql.net_read_timeout == 29 + - db_update.database.engine_config.mysql.net_write_timeout == 59 + - db_update.database.engine_config.mysql.sort_buffer_size == 262141 + - db_update.database.engine_config.mysql.sql_mode == "TRADITIONAL" + - db_update.database.engine_config.mysql.sql_require_primary_key == True + - db_update.database.engine_config.mysql.tmp_table_size == 16777215 + - db_update.database.engine_config.mysql.wait_timeout == 28799 + + - name: Refresh the database + linode.cloud.database_mysql_v2: + label: "ansible-test-{{ r }}" + region: "{{ target_region }}" + engine: "{{ engine_id }}" + type: g6-nanode-1 + engine_config: + binlog_retention_period: 601 + mysql: + connect_timeout: 21 + default_time_zone: "+01:00" + group_concat_max_len: 1023 + information_schema_stats_expiry: 901 + innodb_change_buffer_max_size: 26 + innodb_flush_neighbors: 2 + innodb_ft_min_token_size: 4 + innodb_ft_server_stopword_table: "db_name/table_name" + innodb_lock_wait_timeout: 51 + innodb_log_buffer_size: 16777215 + innodb_online_alter_log_max_size: 134217721 + innodb_read_io_threads: 3 + innodb_rollback_on_timeout: False + innodb_thread_concurrency: 6 + innodb_write_io_threads: 5 + interactive_timeout: 299 + internal_tmp_mem_storage_engine: "MEMORY" + max_allowed_packet: 67108863 + max_heap_table_size: 16777211 + net_buffer_length: 8192 + net_read_timeout: 29 + net_write_timeout: 59 + sort_buffer_size: 262141 + sql_mode: "TRADITIONAL" + sql_require_primary_key: True + tmp_table_size: 16777215 + wait_timeout: 28799 + state: present + register: db_refresh + + - name: Assert database is unchanged + assert: + that: + - not db_refresh.changed + - db_refresh.database.status == 'active' + - db_refresh.database.cluster_size == 1 + - db_refresh.database.engine == 'mysql' + - db_refresh.database.region == target_region + - db_refresh.database.type == 'g6-nanode-1' + - db_refresh.database.engine_config.binlog_retention_period == 601 + - db_refresh.database.engine_config.mysql.connect_timeout == 21 + - db_refresh.database.engine_config.mysql.default_time_zone == "+01:00" + - db_refresh.database.engine_config.mysql.group_concat_max_len == 1023 + - db_refresh.database.engine_config.mysql.information_schema_stats_expiry == 901 + - db_refresh.database.engine_config.mysql.innodb_change_buffer_max_size == 26 + - db_refresh.database.engine_config.mysql.innodb_flush_neighbors == 2 + - db_refresh.database.engine_config.mysql.innodb_ft_min_token_size == 4 + - db_refresh.database.engine_config.mysql.innodb_ft_server_stopword_table == "db_name/table_name" + - db_refresh.database.engine_config.mysql.innodb_lock_wait_timeout == 51 + - db_refresh.database.engine_config.mysql.innodb_log_buffer_size == 16777215 + - db_refresh.database.engine_config.mysql.innodb_online_alter_log_max_size == 134217721 + - db_refresh.database.engine_config.mysql.innodb_read_io_threads == 3 + - db_refresh.database.engine_config.mysql.innodb_rollback_on_timeout == False + - db_refresh.database.engine_config.mysql.innodb_thread_concurrency == 6 + - db_refresh.database.engine_config.mysql.innodb_write_io_threads == 5 + - db_refresh.database.engine_config.mysql.interactive_timeout == 299 + - db_refresh.database.engine_config.mysql.internal_tmp_mem_storage_engine == "MEMORY" + - db_refresh.database.engine_config.mysql.max_allowed_packet == 67108863 + - db_refresh.database.engine_config.mysql.max_heap_table_size == 16777211 + - db_refresh.database.engine_config.mysql.net_buffer_length == 8192 + - db_refresh.database.engine_config.mysql.net_read_timeout == 29 + - db_refresh.database.engine_config.mysql.net_write_timeout == 59 + - db_refresh.database.engine_config.mysql.sort_buffer_size == 262141 + - db_refresh.database.engine_config.mysql.sql_mode == "TRADITIONAL" + - db_refresh.database.engine_config.mysql.sql_require_primary_key == True + - db_refresh.database.engine_config.mysql.tmp_table_size == 16777215 + - db_refresh.database.engine_config.mysql.wait_timeout == 28799 + + always: + - ignore_errors: true + block: + - name: Delete the original database + linode.cloud.database_mysql_v2: + label: '{{ db_create.database.label }}' + 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 "" }}' diff --git a/tests/integration/targets/database_postgresql_v2_basic/tasks/main.yaml b/tests/integration/targets/database_postgresql_v2_basic/tasks/main.yaml index 05ec9f48..e0c5afc5 100644 --- a/tests/integration/targets/database_postgresql_v2_basic/tasks/main.yaml +++ b/tests/integration/targets/database_postgresql_v2_basic/tasks/main.yaml @@ -94,6 +94,28 @@ that: - db_refresh.changed == False + - name: Suspend the database + linode.cloud.database_postgresql_v2: + label: "ansible-test-{{ r }}" + state: suspend + register: db_suspend + + - name: Assert database is suspended + assert: + that: + - db_suspend.changed == True + + - name: Resume the database + linode.cloud.database_postgresql_v2: + label: "ansible-test-{{ r }}" + state: resume + register: db_resume + + - name: Assert database is resumed + assert: + that: + - db_resume.changed == True + always: - ignore_errors: true block: @@ -107,4 +129,4 @@ LINODE_API_TOKEN: '{{ api_token }}' LINODE_API_URL: '{{ api_url }}' LINODE_API_VERSION: '{{ api_version }}' - LINODE_CA: '{{ ca_file or "" }}' \ No newline at end of file + LINODE_CA: '{{ ca_file or "" }}' diff --git a/tests/integration/targets/database_postgresql_v2_engine_config/tasks/main.yaml b/tests/integration/targets/database_postgresql_v2_engine_config/tasks/main.yaml new file mode 100644 index 00000000..5a86d1b6 --- /dev/null +++ b/tests/integration/targets/database_postgresql_v2_engine_config/tasks/main.yaml @@ -0,0 +1,379 @@ +- name: database_postgresql_v2_engine_config + block: + - set_fact: + r: "{{ 1000000000 | random }}" + + - name: List regions + linode.cloud.region_list: {} + register: all_regions + + - set_fact: + target_region: '{{ (all_regions.regions | selectattr("capabilities", "search", "Databases") | list)[0]["id"] }}' + + - name: Get an available PostgreSQL engine + linode.cloud.database_engine_list: + filters: + - name: engine + values: postgresql + register: available_engines + + - name: Assert available database_engine_list + assert: + that: + - available_engines.database_engines | length >= 1 + + - set_fact: + engine_id: "{{ (available_engines.database_engines | sort(attribute='version', reverse=True))[0]['id'] }}" + + - name: Create a database with an explicit engine_config + linode.cloud.database_postgresql_v2: + label: "ansible-test-{{ r }}" + region: "{{ target_region }}" + engine: "{{ engine_id }}" + type: g6-nanode-1 + cluster_size: 1 + engine_config: + pg: + autovacuum_analyze_scale_factor: 0.1 + autovacuum_analyze_threshold: 50 + autovacuum_max_workers: 3 + autovacuum_naptime: 60 + autovacuum_vacuum_cost_delay: 20 + autovacuum_vacuum_cost_limit: 200 + autovacuum_vacuum_scale_factor: 0.2 + autovacuum_vacuum_threshold: 50 + bgwriter_delay: 200 + bgwriter_flush_after: 64 + bgwriter_lru_maxpages: 100 + bgwriter_lru_multiplier: 2.0 + deadlock_timeout: 1000 + default_toast_compression: "lz4" + idle_in_transaction_session_timeout: 600000 + jit: true + max_files_per_process: 1000 + max_locks_per_transaction: 64 + max_logical_replication_workers: 4 + max_parallel_workers: 4 + max_parallel_workers_per_gather: 2 + max_pred_locks_per_transaction: 64 + max_replication_slots: 10 + max_slot_wal_keep_size: 2048 + max_stack_depth: 6291456 + max_standby_archive_delay: 30000 + max_standby_streaming_delay: 30000 + max_wal_senders: 20 + max_worker_processes: 8 + password_encryption: "scram-sha-256" + temp_file_limit: 1 + timezone: "UTC" + track_activity_query_size: 2048 + track_functions: "all" + wal_sender_timeout: 60000 + wal_writer_delay: 200 + pg_partman_bgw.interval: 3600 + pg_partman_bgw.role: "myrolename" + pg_stat_monitor.pgsm_enable_query_plan: true + pg_stat_monitor.pgsm_max_buckets: 2 + pg_stat_statements.track: "top" + pglookout: + max_failover_replication_time_lag: 10 + pg_stat_monitor_enable: true + shared_buffers_percentage: 25.0 + work_mem: 1024 + state: present + register: db_create + + - name: Assert database is created + assert: + that: + - db_create.changed + - db_create.database.status == 'active' + - db_create.database.cluster_size == 1 + - db_create.database.engine == 'postgresql' + - db_create.database.region == target_region + - db_create.database.engine_config.pg.autovacuum_analyze_scale_factor == 0.1 + - db_create.database.engine_config.pg.autovacuum_analyze_threshold == 50 + - db_create.database.engine_config.pg.autovacuum_max_workers == 3 + - db_create.database.engine_config.pg.autovacuum_naptime == 60 + - db_create.database.engine_config.pg.autovacuum_vacuum_cost_delay == 20 + - db_create.database.engine_config.pg.autovacuum_vacuum_cost_limit == 200 + - db_create.database.engine_config.pg.autovacuum_vacuum_scale_factor == 0.2 + - db_create.database.engine_config.pg.autovacuum_vacuum_threshold == 50 + - db_create.database.engine_config.pg.bgwriter_delay == 200 + - db_create.database.engine_config.pg.bgwriter_flush_after == 64 + - db_create.database.engine_config.pg.bgwriter_lru_maxpages == 100 + - db_create.database.engine_config.pg.bgwriter_lru_multiplier == 2.0 + - db_create.database.engine_config.pg.deadlock_timeout == 1000 + - db_create.database.engine_config.pg.default_toast_compression == "lz4" + - db_create.database.engine_config.pg.idle_in_transaction_session_timeout == 600000 + - db_create.database.engine_config.pg.jit == true + - db_create.database.engine_config.pg.max_files_per_process == 1000 + - db_create.database.engine_config.pg.max_locks_per_transaction == 64 + - db_create.database.engine_config.pg.max_logical_replication_workers == 4 + - db_create.database.engine_config.pg.max_parallel_workers == 4 + - db_create.database.engine_config.pg.max_parallel_workers_per_gather == 2 + - db_create.database.engine_config.pg.max_pred_locks_per_transaction == 64 + - db_create.database.engine_config.pg.max_replication_slots == 10 + - db_create.database.engine_config.pg.max_slot_wal_keep_size == 2048 + - db_create.database.engine_config.pg.max_stack_depth == 6291456 + - db_create.database.engine_config.pg.max_standby_archive_delay == 30000 + - db_create.database.engine_config.pg.max_standby_streaming_delay == 30000 + - db_create.database.engine_config.pg.max_wal_senders == 20 + - db_create.database.engine_config.pg.max_worker_processes == 8 + - db_create.database.engine_config.pg.password_encryption == "scram-sha-256" + - db_create.database.engine_config.pg.temp_file_limit == 1 + - db_create.database.engine_config.pg.timezone == "UTC" + - db_create.database.engine_config.pg.track_activity_query_size == 2048 + - db_create.database.engine_config.pg.track_functions == "all" + - db_create.database.engine_config.pg.wal_sender_timeout == 60000 + - db_create.database.engine_config.pg.wal_writer_delay == 200 + - db_create.database.engine_config.pg["pg_partman_bgw.interval"] == 3600 + - db_create.database.engine_config.pg["pg_partman_bgw.role"] == "myrolename" + - db_create.database.engine_config.pg["pg_stat_monitor.pgsm_enable_query_plan"] == true + - db_create.database.engine_config.pg["pg_stat_monitor.pgsm_max_buckets"] == 2 + - db_create.database.engine_config.pg["pg_stat_statements.track"] == "top" + - db_create.database.engine_config.pglookout.max_failover_replication_time_lag == 10 + - db_create.database.engine_config.pg_stat_monitor_enable == true + - db_create.database.engine_config.shared_buffers_percentage == 25.0 + - db_create.database.engine_config.work_mem == 1024 + + - name: Update the database's engine_config + linode.cloud.database_postgresql_v2: + label: "ansible-test-{{ r }}" + region: "{{ target_region }}" + engine: "{{ engine_id }}" + type: g6-nanode-1 + cluster_size: 1 + engine_config: + pg: + autovacuum_analyze_scale_factor: 0.2 + autovacuum_analyze_threshold: 51 + autovacuum_max_workers: 2 + autovacuum_naptime: 61 + autovacuum_vacuum_cost_delay: 21 + autovacuum_vacuum_cost_limit: 201 + autovacuum_vacuum_scale_factor: 0.3 + autovacuum_vacuum_threshold: 51 + bgwriter_delay: 201 + bgwriter_flush_after: 63 + bgwriter_lru_maxpages: 99 + bgwriter_lru_multiplier: 1.0 + deadlock_timeout: 999 + default_toast_compression: "lz4" + idle_in_transaction_session_timeout: 600001 + jit: false + max_files_per_process: 1001 + max_locks_per_transaction: 65 + max_logical_replication_workers: 6 + max_parallel_workers: 3 + max_parallel_workers_per_gather: 4 + max_pred_locks_per_transaction: 67 + max_replication_slots: 9 + max_slot_wal_keep_size: 1024 + max_stack_depth: 6291455 + max_standby_archive_delay: 30001 + max_standby_streaming_delay: 30001 + max_wal_senders: 21 + max_worker_processes: 10 + password_encryption: "md5" + temp_file_limit: 2 + timezone: "America/New_York" + track_activity_query_size: 1024 + track_functions: "pl" + wal_sender_timeout: 60001 + wal_writer_delay: 199 + pg_partman_bgw.interval: 3601 + pg_partman_bgw.role: "myupdatedrolename" + pg_stat_monitor.pgsm_enable_query_plan: false + pg_stat_monitor.pgsm_max_buckets: 3 + pg_stat_statements.track: "none" + pglookout: + max_failover_replication_time_lag: 13 + pg_stat_monitor_enable: false + shared_buffers_percentage: 24.0 + work_mem: 1023 + state: present + register: db_update + + - name: Assert database is updated + assert: + that: + - db_update.database.cluster_size == 1 + - db_update.database.engine == 'postgresql' + - db_update.database.region == target_region + - db_update.database.status == 'active' + - db_update.database.engine_config.pg.autovacuum_analyze_scale_factor == 0.2 + - db_update.database.engine_config.pg.autovacuum_analyze_threshold == 51 + - db_update.database.engine_config.pg.autovacuum_max_workers == 2 + - db_update.database.engine_config.pg.autovacuum_naptime == 61 + - db_update.database.engine_config.pg.autovacuum_vacuum_cost_delay == 21 + - db_update.database.engine_config.pg.autovacuum_vacuum_cost_limit == 201 + - db_update.database.engine_config.pg.autovacuum_vacuum_scale_factor == 0.3 + - db_update.database.engine_config.pg.autovacuum_vacuum_threshold == 51 + - db_update.database.engine_config.pg.bgwriter_delay == 201 + - db_update.database.engine_config.pg.bgwriter_flush_after == 63 + - db_update.database.engine_config.pg.bgwriter_lru_maxpages == 99 + - db_update.database.engine_config.pg.bgwriter_lru_multiplier == 1.0 + - db_update.database.engine_config.pg.deadlock_timeout == 999 + - db_update.database.engine_config.pg.default_toast_compression == "lz4" + - db_update.database.engine_config.pg.idle_in_transaction_session_timeout == 600001 + - db_update.database.engine_config.pg.jit == false + - db_update.database.engine_config.pg.max_files_per_process == 1001 + - db_update.database.engine_config.pg.max_locks_per_transaction == 65 + - db_update.database.engine_config.pg.max_logical_replication_workers == 6 + - db_update.database.engine_config.pg.max_parallel_workers == 3 + - db_update.database.engine_config.pg.max_parallel_workers_per_gather == 4 + - db_update.database.engine_config.pg.max_pred_locks_per_transaction == 67 + - db_update.database.engine_config.pg.max_replication_slots == 9 + - db_update.database.engine_config.pg.max_slot_wal_keep_size == 1024 + - db_update.database.engine_config.pg.max_stack_depth == 6291455 + - db_update.database.engine_config.pg.max_standby_archive_delay == 30001 + - db_update.database.engine_config.pg.max_standby_streaming_delay == 30001 + - db_update.database.engine_config.pg.max_wal_senders == 21 + - db_update.database.engine_config.pg.max_worker_processes == 10 + - db_update.database.engine_config.pg.password_encryption == "md5" + - db_update.database.engine_config.pg.temp_file_limit == 2 + - db_update.database.engine_config.pg.timezone == "America/New_York" + - db_update.database.engine_config.pg.track_activity_query_size == 1024 + - db_update.database.engine_config.pg.track_functions == "pl" + - db_update.database.engine_config.pg.wal_sender_timeout == 60001 + - db_update.database.engine_config.pg.wal_writer_delay == 199 + - db_update.database.engine_config.pg["pg_partman_bgw.interval"] == 3601 + - db_update.database.engine_config.pg["pg_partman_bgw.role"] == "myupdatedrolename" + - db_update.database.engine_config.pg["pg_stat_monitor.pgsm_enable_query_plan"] == false + - db_update.database.engine_config.pg["pg_stat_monitor.pgsm_max_buckets"] == 3 + - db_update.database.engine_config.pg["pg_stat_statements.track"] == "none" + - db_update.database.engine_config.pglookout.max_failover_replication_time_lag == 13 + - db_update.database.engine_config.pg_stat_monitor_enable == false + - db_update.database.engine_config.shared_buffers_percentage == 24.0 + - db_update.database.engine_config.work_mem == 1023 + + - name: Refresh the database + linode.cloud.database_postgresql_v2: + label: "ansible-test-{{ r }}" + region: "{{ target_region }}" + engine: "{{ engine_id }}" + type: g6-nanode-1 + cluster_size: 1 + engine_config: + pg: + autovacuum_analyze_scale_factor: 0.2 + autovacuum_analyze_threshold: 51 + autovacuum_max_workers: 2 + autovacuum_naptime: 61 + autovacuum_vacuum_cost_delay: 21 + autovacuum_vacuum_cost_limit: 201 + autovacuum_vacuum_scale_factor: 0.3 + autovacuum_vacuum_threshold: 51 + bgwriter_delay: 201 + bgwriter_flush_after: 63 + bgwriter_lru_maxpages: 99 + bgwriter_lru_multiplier: 1.0 + deadlock_timeout: 999 + default_toast_compression: "lz4" + idle_in_transaction_session_timeout: 600001 + jit: false + max_files_per_process: 1001 + max_locks_per_transaction: 65 + max_logical_replication_workers: 6 + max_parallel_workers: 3 + max_parallel_workers_per_gather: 4 + max_pred_locks_per_transaction: 67 + max_replication_slots: 9 + max_slot_wal_keep_size: 1024 + max_stack_depth: 6291455 + max_standby_archive_delay: 30001 + max_standby_streaming_delay: 30001 + max_wal_senders: 21 + max_worker_processes: 10 + password_encryption: "md5" + temp_file_limit: 2 + timezone: "America/New_York" + track_activity_query_size: 1024 + track_functions: "pl" + wal_sender_timeout: 60001 + wal_writer_delay: 199 + pg_partman_bgw.interval: 3601 + pg_partman_bgw.role: "myupdatedrolename" + pg_stat_monitor.pgsm_enable_query_plan: false + pg_stat_monitor.pgsm_max_buckets: 3 + pg_stat_statements.track: "none" + pglookout: + max_failover_replication_time_lag: 13 + pg_stat_monitor_enable: false + shared_buffers_percentage: 24.0 + work_mem: 1023 + state: present + register: db_refresh + + - name: Assert database is refreshed + assert: + that: + - not db_refresh.changed + - db_refresh.database.cluster_size == 1 + - db_refresh.database.engine == 'postgresql' + - db_refresh.database.region == target_region + - db_refresh.database.status == 'active' + - db_refresh.database.engine_config.pg.autovacuum_analyze_scale_factor == 0.2 + - db_refresh.database.engine_config.pg.autovacuum_analyze_threshold == 51 + - db_refresh.database.engine_config.pg.autovacuum_max_workers == 2 + - db_refresh.database.engine_config.pg.autovacuum_naptime == 61 + - db_refresh.database.engine_config.pg.autovacuum_vacuum_cost_delay == 21 + - db_refresh.database.engine_config.pg.autovacuum_vacuum_cost_limit == 201 + - db_refresh.database.engine_config.pg.autovacuum_vacuum_scale_factor == 0.3 + - db_refresh.database.engine_config.pg.autovacuum_vacuum_threshold == 51 + - db_refresh.database.engine_config.pg.bgwriter_delay == 201 + - db_refresh.database.engine_config.pg.bgwriter_flush_after == 63 + - db_refresh.database.engine_config.pg.bgwriter_lru_maxpages == 99 + - db_refresh.database.engine_config.pg.bgwriter_lru_multiplier == 1.0 + - db_refresh.database.engine_config.pg.deadlock_timeout == 999 + - db_refresh.database.engine_config.pg.default_toast_compression == "lz4" + - db_refresh.database.engine_config.pg.idle_in_transaction_session_timeout == 600001 + - db_refresh.database.engine_config.pg.jit == false + - db_refresh.database.engine_config.pg.max_files_per_process == 1001 + - db_refresh.database.engine_config.pg.max_locks_per_transaction == 65 + - db_refresh.database.engine_config.pg.max_logical_replication_workers == 6 + - db_refresh.database.engine_config.pg.max_parallel_workers == 3 + - db_refresh.database.engine_config.pg.max_parallel_workers_per_gather == 4 + - db_refresh.database.engine_config.pg.max_pred_locks_per_transaction == 67 + - db_refresh.database.engine_config.pg.max_replication_slots == 9 + - db_refresh.database.engine_config.pg.max_slot_wal_keep_size == 1024 + - db_refresh.database.engine_config.pg.max_stack_depth == 6291455 + - db_refresh.database.engine_config.pg.max_standby_archive_delay == 30001 + - db_refresh.database.engine_config.pg.max_standby_streaming_delay == 30001 + - db_refresh.database.engine_config.pg.max_wal_senders == 21 + - db_refresh.database.engine_config.pg.max_worker_processes == 10 + - db_refresh.database.engine_config.pg.password_encryption == "md5" + - db_refresh.database.engine_config.pg.temp_file_limit == 2 + - db_refresh.database.engine_config.pg.timezone == "America/New_York" + - db_refresh.database.engine_config.pg.track_activity_query_size == 1024 + - db_refresh.database.engine_config.pg.track_functions == "pl" + - db_refresh.database.engine_config.pg.wal_sender_timeout == 60001 + - db_refresh.database.engine_config.pg.wal_writer_delay == 199 + - db_refresh.database.engine_config.pg["pg_partman_bgw.interval"] == 3601 + - db_refresh.database.engine_config.pg["pg_partman_bgw.role"] == "myupdatedrolename" + - db_refresh.database.engine_config.pg["pg_stat_monitor.pgsm_enable_query_plan"] == false + - db_refresh.database.engine_config.pg["pg_stat_monitor.pgsm_max_buckets"] == 3 + - db_refresh.database.engine_config.pg["pg_stat_statements.track"] == "none" + - db_refresh.database.engine_config.pglookout.max_failover_replication_time_lag == 13 + - db_refresh.database.engine_config.pg_stat_monitor_enable == false + - db_refresh.database.engine_config.shared_buffers_percentage == 24.0 + - db_refresh.database.engine_config.work_mem == 1023 + + + + + always: + - ignore_errors: true + block: + - name: Delete the original database + linode.cloud.database_postgresql_v2: + label: '{{ db_create.database.label }}' + 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 "" }}' diff --git a/tests/integration/targets/lke_cluster_basic/tasks/main.yaml b/tests/integration/targets/lke_cluster_basic/tasks/main.yaml index 08865c7c..49669453 100644 --- a/tests/integration/targets/lke_cluster_basic/tasks/main.yaml +++ b/tests/integration/targets/lke_cluster_basic/tasks/main.yaml @@ -179,7 +179,7 @@ - info_by_label.node_pools[0].count == 1 - info_by_label.node_pools[0].id == create_cluster.node_pools[0].id - - name: Create a Linode LKE cluster with a pool with disk encryption enabled + - name: Create a Linode LKE cluster with a pool has disk encryption explicitly set linode.cloud.lke_cluster: label: 'ansible-test-de-{{ r }}' region: '{{ lde_region }}' @@ -194,7 +194,7 @@ - name: Assert LKE cluster is created assert: that: - - create_cluster_disk_encryption.node_pools[0].disk_encryption == 'disabled' + - create_cluster_disk_encryption.node_pools[0].disk_encryption in ['enabled', 'disabled'] always: - ignore_errors: yes diff --git a/tests/integration/targets/lke_node_pool_basic/tasks/main.yaml b/tests/integration/targets/lke_node_pool_basic/tasks/main.yaml index ed170c8e..f6f32da1 100644 --- a/tests/integration/targets/lke_node_pool_basic/tasks/main.yaml +++ b/tests/integration/targets/lke_node_pool_basic/tasks/main.yaml @@ -148,7 +148,7 @@ that: - new_pool_de.node_pool.count == 2 - new_pool_de.node_pool.type == 'g6-standard-1' - - new_pool_de.node_pool.disk_encryption == 'disabled' + - new_pool_de.node_pool.disk_encryption in ['enabled', 'disabled'] - new_pool_de.node_pool.nodes[0].status == 'ready' - new_pool_de.node_pool.nodes[1].status == 'ready' diff --git a/tests/integration/targets/object_storage_quota_info/tasks/main.yaml b/tests/integration/targets/object_storage_quota_info/tasks/main.yaml new file mode 100644 index 00000000..51ab8d04 --- /dev/null +++ b/tests/integration/targets/object_storage_quota_info/tasks/main.yaml @@ -0,0 +1,28 @@ +- name: object_storage_quota_info + block: + - name: List Object Storage Quotas + linode.cloud.object_storage_quota_list: + register: obj_quota_list + + - name: Assert at least one quota returned for the following test + assert: + that: + - obj_quota_list.object_storage_quotas | length > 0 + + - name: Get info about an Object Storage Quota + linode.cloud.object_storage_quota_info: + quota_id: '{{ obj_quota_list.object_storage_quotas[0].quota_id }}' + register: obj_quota + + - name: Assert GET Object Storage quota response + assert: + that: + - obj_quota.object_storage_quota.quota_id == obj_quota_list.object_storage_quotas[0].quota_id + - obj_quota.quota_usage.quota_limit + + 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 "" }}' diff --git a/tests/integration/targets/object_storage_quota_list/tasks/main.yaml b/tests/integration/targets/object_storage_quota_list/tasks/main.yaml new file mode 100644 index 00000000..a246a0f1 --- /dev/null +++ b/tests/integration/targets/object_storage_quota_list/tasks/main.yaml @@ -0,0 +1,22 @@ +- name: object_storage_quota_info + block: + - name: List and filter Object Storage Quotas by s3_endpoint + linode.cloud.object_storage_quota_list: + filters: + - name: s3_endpoint + values: + - es-mad-1.linodeobjects.com + register: obj_quota_list + + - name: Assert the quotas are listed and filtered correctly + assert: + that: + - obj_quota_list.object_storage_quotas | length > 0 + - obj_quota_list.object_storage_quotas[0].s3_endpoint == "es-mad-1.linodeobjects.com" + + 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 "" }}' diff --git a/tests/integration/targets/vpc_ip_list/tasks/main.yaml b/tests/integration/targets/vpc_ip_list/tasks/main.yaml index de023e06..17847963 100644 --- a/tests/integration/targets/vpc_ip_list/tasks/main.yaml +++ b/tests/integration/targets/vpc_ip_list/tasks/main.yaml @@ -80,22 +80,21 @@ linode.cloud.vpcs_ip_list: register: all_vpc_ips - - name: Assert VPC IPs were returned + - name: Assert at least one VPC IP belongs to the created VPC assert: that: - - all_vpc_ips.vpcs_ips[0].vpc_id == create_vpc.vpc.id - - all_vpc_ips.vpcs_ips[1].vpc_id == create_vpc.vpc.id + - create_vpc.vpc.id in all_vpc_ips.vpcs_ips | map(attribute='vpc_id') | list - name: List VPC IPs for a specific VPC linode.cloud.vpc_ip_list: vpc_id: '{{ create_vpc.vpc.id }}' register: vpcs_ips - - name: Assert VPC IPs were returned + - name: Assert all returned VPC IPs belong to the created VPC assert: that: - - vpcs_ips.vpcs_ips[0].vpc_id == create_vpc.vpc.id - - vpcs_ips.vpcs_ips[1].vpc_id == create_vpc.vpc.id + - vpcs_ips.vpcs_ips | length > 0 + - vpcs_ips.vpcs_ips | selectattr('vpc_id', 'equalto', create_vpc.vpc.id) | list | length == vpcs_ips.vpcs_ips | length always: - ignore_errors: true