From b75e8d19beb215fd58f3db44fcbec2a52401ac48 Mon Sep 17 00:00:00 2001 From: The Magician Date: Fri, 19 Jul 2019 11:32:05 -0700 Subject: [PATCH] Bug fixes for GCP (as of 2019-07-09T06:06:53Z) (#59132) * Bug fixes for GCP modules * ignore syntax --- .../google/gcp_resourcemanager_project.py | 8 +++- .../cloud/google/gcp_sourcerepo_repository.py | 1 + .../cloud/google/gcp_spanner_database.py | 48 ++++++++++++++++--- .../google/gcp_spanner_database_facts.py | 1 + .../cloud/google/gcp_spanner_instance.py | 9 +++- .../modules/cloud/google/gcp_sql_database.py | 4 ++ .../cloud/google/gcp_sql_database_facts.py | 1 + .../modules/cloud/google/gcp_sql_instance.py | 37 ++++++++++++++ .../modules/cloud/google/gcp_sql_user.py | 4 ++ .../cloud/google/gcp_sql_user_facts.py | 1 + .../cloud/google/gcp_storage_bucket.py | 43 +++++++++++++++++ .../gcp_storage_bucket_access_control.py | 7 +++ .../cloud/google/gcp_storage_object.py | 4 ++ .../modules/cloud/google/gcp_tpu_node.py | 11 ++++- .../cloud/google/gcp_tpu_node_facts.py | 1 + .../gcp_spanner_database/tasks/main.yml | 4 +- .../gcp_spanner_instance/tasks/main.yml | 4 +- test/sanity/validate-modules/ignore.txt | 4 -- 18 files changed, 174 insertions(+), 18 deletions(-) diff --git a/lib/ansible/modules/cloud/google/gcp_resourcemanager_project.py b/lib/ansible/modules/cloud/google/gcp_resourcemanager_project.py index 5418514d314..bf9c2556203 100644 --- a/lib/ansible/modules/cloud/google/gcp_resourcemanager_project.py +++ b/lib/ansible/modules/cloud/google/gcp_resourcemanager_project.py @@ -54,6 +54,7 @@ options: Allowed characters are: lowercase and uppercase letters, numbers, hyphen, single-quote, double-quote, space, and exclamation point.' required: false + type: str labels: description: - The labels associated with this Project. @@ -65,25 +66,30 @@ options: - Clients should store labels in a representation such as JSON that does not depend on specific characters being disallowed . required: false + type: dict parent: description: - A parent organization. required: false + type: dict suboptions: type: description: - Must be organization. required: false + type: str id: description: - Id of the organization. required: false + type: str id: description: - The unique, user-assigned ID of the Project. It must be 6 to 30 lowercase letters, digits, or hyphens. It must start with a letter. - Trailing hyphens are prohibited. required: true + type: str extends_documentation_fragment: gcp ''' @@ -329,7 +335,7 @@ def wait_for_operation(module, response): return {} status = navigate_hash(op_result, ['done']) wait_done = wait_for_completion(status, op_result, module) - raise_if_errors(op_result, ['error'], module) + raise_if_errors(wait_done, ['error'], module) return navigate_hash(wait_done, ['response']) diff --git a/lib/ansible/modules/cloud/google/gcp_sourcerepo_repository.py b/lib/ansible/modules/cloud/google/gcp_sourcerepo_repository.py index 3e0d482a9db..cb690e9bae1 100644 --- a/lib/ansible/modules/cloud/google/gcp_sourcerepo_repository.py +++ b/lib/ansible/modules/cloud/google/gcp_sourcerepo_repository.py @@ -53,6 +53,7 @@ options: - The repo name may contain slashes. eg, projects/myproject/repos/name/with/slash . required: true + type: str extends_documentation_fragment: gcp notes: - 'API Reference: U(https://cloud.google.com/source-repositories/docs/reference/rest/v1/projects.repos)' diff --git a/lib/ansible/modules/cloud/google/gcp_spanner_database.py b/lib/ansible/modules/cloud/google/gcp_spanner_database.py index fe585a05e82..e59d4c950e7 100644 --- a/lib/ansible/modules/cloud/google/gcp_spanner_database.py +++ b/lib/ansible/modules/cloud/google/gcp_spanner_database.py @@ -52,6 +52,7 @@ options: - A unique identifier for the database, which cannot be changed after the instance is created. Values are of the form [a-z][-a-z0-9]*[a-z0-9]. required: true + type: str extra_statements: description: - 'An optional list of DDL statements to run inside the newly created database. @@ -59,6 +60,7 @@ options: with the creation of the database: if there is an error in any statement, the database is not created.' required: false + type: list instance: description: - The instance to create the database on. @@ -68,6 +70,7 @@ options: to a gcp_spanner_instance task and then set this instance field to "{{ name-of-resource }}"' required: true + type: dict extends_documentation_fragment: gcp notes: - 'API Reference: U(https://cloud.google.com/spanner/docs/reference/rest/v1/projects.instances.databases)' @@ -127,6 +130,7 @@ instance: from ansible.module_utils.gcp_utils import navigate_hash, GcpSession, GcpModule, GcpRequest, replace_resource_dict import json +import time ################################################################################ # Main @@ -177,7 +181,7 @@ def main(): def create(module, link): auth = GcpSession(module, 'spanner') - return return_if_object(module, auth.post(link, resource_to_request(module))) + return wait_for_operation(module, auth.post(link, resource_to_request(module))) def update(module, link): @@ -191,11 +195,7 @@ def delete(module, link): def resource_to_request(module): - request = { - u'instance': replace_resource_dict(module.params.get(u'instance', {}), 'name'), - u'name': module.params.get('name'), - u'extraStatements': module.params.get('extra_statements'), - } + request = {u'name': module.params.get('name'), u'extraStatements': module.params.get('extra_statements')} request = encode_request(request, module) return_vals = {} for k, v in request.items(): @@ -268,6 +268,42 @@ def response_to_hash(module, response): return {u'name': module.params.get('name'), u'extraStatements': module.params.get('extra_statements')} +def async_op_url(module, extra_data=None): + if extra_data is None: + extra_data = {} + url = "https://spanner.googleapis.com/v1/{op_id}" + combined = extra_data.copy() + combined.update(module.params) + return url.format(**combined) + + +def wait_for_operation(module, response): + op_result = return_if_object(module, response) + if op_result is None: + return {} + status = navigate_hash(op_result, ['done']) + wait_done = wait_for_completion(status, op_result, module) + raise_if_errors(wait_done, ['error'], module) + return navigate_hash(wait_done, ['response']) + + +def wait_for_completion(status, op_result, module): + op_id = navigate_hash(op_result, ['name']) + op_uri = async_op_url(module, {'op_id': op_id}) + while not status: + raise_if_errors(op_result, ['error'], module) + time.sleep(1.0) + op_result = fetch_resource(module, op_uri, False) + status = navigate_hash(op_result, ['done']) + return op_result + + +def raise_if_errors(response, err_path, module): + errors = navigate_hash(response, err_path) + if errors is not None: + module.fail_json(msg=errors) + + def decode_response(response, module): if not response: return response diff --git a/lib/ansible/modules/cloud/google/gcp_spanner_database_facts.py b/lib/ansible/modules/cloud/google/gcp_spanner_database_facts.py index d3e0c5795d1..90130dd5f82 100644 --- a/lib/ansible/modules/cloud/google/gcp_spanner_database_facts.py +++ b/lib/ansible/modules/cloud/google/gcp_spanner_database_facts.py @@ -49,6 +49,7 @@ options: to a gcp_spanner_instance task and then set this instance field to "{{ name-of-resource }}"' required: true + type: dict extends_documentation_fragment: gcp ''' diff --git a/lib/ansible/modules/cloud/google/gcp_spanner_instance.py b/lib/ansible/modules/cloud/google/gcp_spanner_instance.py index 588a594a242..8b7dd74bd5f 100644 --- a/lib/ansible/modules/cloud/google/gcp_spanner_instance.py +++ b/lib/ansible/modules/cloud/google/gcp_spanner_instance.py @@ -52,6 +52,7 @@ options: - A unique identifier for the instance, which cannot be changed after the instance is created. The name must be between 6 and 30 characters in length. required: true + type: str config: description: - The name of the instance's configuration (similar but not quite the same as @@ -61,21 +62,25 @@ options: - In order to obtain a valid list please consult the [Configuration section of the docs](U(https://cloud.google.com/spanner/docs/instances)). required: true + type: str display_name: description: - The descriptive name for this instance as it appears in UIs. Must be unique per project and between 4 and 30 characters in length. required: true + type: str node_count: description: - The number of nodes allocated to this instance. required: false default: '1' + type: int labels: description: - 'An object containing a list of "key": value pairs.' - 'Example: { "name": "wrench", "mass": "1.3kg", "count": "3" }.' required: false + type: dict extends_documentation_fragment: gcp notes: - 'API Reference: U(https://cloud.google.com/spanner/docs/reference/rest/v1/projects.instances)' @@ -202,7 +207,7 @@ def update(module, link): def delete(module, link): auth = GcpSession(module, 'spanner') - return wait_for_operation(module, auth.delete(link)) + return return_if_object(module, auth.delete(link)) def resource_to_request(module): @@ -303,7 +308,7 @@ def wait_for_operation(module, response): return {} status = navigate_hash(op_result, ['done']) wait_done = wait_for_completion(status, op_result, module) - raise_if_errors(op_result, ['error'], module) + raise_if_errors(wait_done, ['error'], module) return navigate_hash(wait_done, ['response']) diff --git a/lib/ansible/modules/cloud/google/gcp_sql_database.py b/lib/ansible/modules/cloud/google/gcp_sql_database.py index 608cb2a6eb5..523ea834db2 100644 --- a/lib/ansible/modules/cloud/google/gcp_sql_database.py +++ b/lib/ansible/modules/cloud/google/gcp_sql_database.py @@ -51,19 +51,23 @@ options: description: - The MySQL charset value. required: false + type: str collation: description: - The MySQL collation value. required: false + type: str name: description: - The name of the database in the Cloud SQL instance. - This does not include the project ID or instance name. required: true + type: str instance: description: - The name of the Cloud SQL instance. This does not include the project ID. required: true + type: str extends_documentation_fragment: gcp ''' diff --git a/lib/ansible/modules/cloud/google/gcp_sql_database_facts.py b/lib/ansible/modules/cloud/google/gcp_sql_database_facts.py index 41d96b1e091..017f5d3161d 100644 --- a/lib/ansible/modules/cloud/google/gcp_sql_database_facts.py +++ b/lib/ansible/modules/cloud/google/gcp_sql_database_facts.py @@ -44,6 +44,7 @@ options: description: - The name of the Cloud SQL instance. This does not include the project ID. required: true + type: str extends_documentation_fragment: gcp ''' diff --git a/lib/ansible/modules/cloud/google/gcp_sql_instance.py b/lib/ansible/modules/cloud/google/gcp_sql_instance.py index 536a7b643bf..a3c5284c1c1 100644 --- a/lib/ansible/modules/cloud/google/gcp_sql_instance.py +++ b/lib/ansible/modules/cloud/google/gcp_sql_instance.py @@ -56,10 +56,12 @@ options: - "* EXTERNAL: A database server that is not managed by Google." - 'Some valid choices include: "FIRST_GEN", "SECOND_GEN", "EXTERNAL"' required: false + type: str connection_name: description: - Connection name of the Cloud SQL instance used in connection strings. required: false + type: str database_version: description: - The database engine type and version. For First Generation instances, can be @@ -69,11 +71,13 @@ options: changed after instance creation.' - 'Some valid choices include: "MYSQL_5_5", "MYSQL_5_6", "MYSQL_5_7", "POSTGRES_9_6"' required: false + type: str failover_replica: description: - The name and status of the failover replica. This property is applicable only to Second Generation instances. required: false + type: dict suboptions: name: description: @@ -81,6 +85,7 @@ options: replica is created for the instance. The name doesn't include the project ID. This property is applicable only to Second Generation instances. required: false + type: str instance_type: description: - The instance type. This can be one of the following. @@ -89,32 +94,39 @@ options: - "* READ_REPLICA_INSTANCE: A Cloud SQL instance configured as a read-replica." - 'Some valid choices include: "CLOUD_SQL_INSTANCE", "ON_PREMISES_INSTANCE", "READ_REPLICA_INSTANCE"' required: false + type: str ipv6_address: description: - The IPv6 address assigned to the instance. This property is applicable only to First Generation instances. required: false + type: str master_instance_name: description: - The name of the instance which will act as master in the replication setup. required: false + type: str max_disk_size: description: - The maximum disk size of the instance in bytes. required: false + type: int name: description: - Name of the Cloud SQL instance. This does not include the project ID. required: true + type: str region: description: - The geographical region. Defaults to us-central or us-central1 depending on the instance type (First Generation or Second Generation/PostgreSQL). required: false + type: str replica_configuration: description: - Configuration specific to failover replicas and read replicas. required: false + type: dict suboptions: failover_target: description: @@ -134,24 +146,29 @@ options: is used only to set up the replication connection and is stored by MySQL in a file named master.info in the data directory. required: false + type: dict suboptions: ca_certificate: description: - PEM representation of the trusted CA's x509 certificate. required: false + type: str client_certificate: description: - PEM representation of the slave's x509 certificate . required: false + type: str client_key: description: - PEM representation of the slave's private key. The corresponding public key is encoded in the client's certificate. required: false + type: str connect_retry_interval: description: - Seconds to wait between connect retries. MySQL's default is 60 seconds. required: false + type: int dump_file_path: description: - Path to a SQL dump file in Google Cloud Storage from which the slave @@ -160,22 +177,27 @@ options: binlog co-ordinates from which replication should begin. This can be accomplished by setting --master-data to 1 when using mysqldump. required: false + type: str master_heartbeat_period: description: - Interval in milliseconds between replication heartbeats. required: false + type: int password: description: - The password for the replication connection. required: false + type: str ssl_cipher: description: - A list of permissible ciphers to use for SSL encryption. required: false + type: str username: description: - The username for the replication connection. required: false + type: str verify_server_certificate: description: - Whether or not to check the master's Common Name value in the certificate @@ -186,20 +208,24 @@ options: description: - The replicas of the instance. required: false + type: list service_account_email_address: description: - The service account email address assigned to the instance. This property is applicable only to Second Generation instances. required: false + type: str settings: description: - The user settings. required: false + type: dict suboptions: database_flags: description: - The database flags passed to the instance at startup. required: false + type: list version_added: 2.9 suboptions: name: @@ -208,17 +234,20 @@ options: include both server options and system variables for MySQL. Flags should be specified with underscores, not hyphens. required: false + type: str value: description: - The value of the flag. Booleans should be set to on for true and off for false. This field must be omitted if the flag doesn't take a value. required: false + type: str ip_configuration: description: - The settings for IP Management. This allows to enable or disable the instance IP and manage which external networks can connect to the instance. The IPv4 address cannot be disabled for Second Generation instances. required: false + type: dict suboptions: ipv4_enabled: description: @@ -231,22 +260,26 @@ options: using the IP. In CIDR notation, also known as 'slash' notation (e.g. 192.168.100.0/24). required: false + type: list suboptions: expiration_time: description: - The time when this access control entry expires in RFC 3339 format, for example 2012-11-15T16:19:00.094Z. required: false + type: str name: description: - An optional label to identify this entry. required: false + type: str value: description: - The whitelisted value for the access control list. For example, to grant access to a client from an external IP (IPv4 or IPv6) address or subnet, use that address or subnet here. required: false + type: str require_ssl: description: - Whether the mysqld should default to 'REQUIRE X509' for users connecting @@ -259,15 +292,18 @@ options: For MySQL instances, this field determines whether the instance is Second Generation (recommended) or First Generation. required: false + type: str availability_type: description: - The availabilityType define if your postgres instance is run zonal or regional. - 'Some valid choices include: "ZONAL", "REGIONAL"' required: false + type: str backup_configuration: description: - The daily backup configuration for the instance. required: false + type: dict suboptions: enabled: description: @@ -284,6 +320,7 @@ options: description: - Define the backup start time in UTC (HH:MM) . required: false + type: str extends_documentation_fragment: gcp ''' diff --git a/lib/ansible/modules/cloud/google/gcp_sql_user.py b/lib/ansible/modules/cloud/google/gcp_sql_user.py index 6428e7f3416..0c52ef27d6c 100644 --- a/lib/ansible/modules/cloud/google/gcp_sql_user.py +++ b/lib/ansible/modules/cloud/google/gcp_sql_user.py @@ -53,10 +53,12 @@ options: to an empty string. For update operations, host is specified as part of the request URL. The host name cannot be updated after insertion. required: true + type: str name: description: - The name of the user in the Cloud SQL instance. required: true + type: str instance: description: - The name of the Cloud SQL instance. This does not include the project ID. @@ -66,10 +68,12 @@ options: to a gcp_sql_instance task and then set this instance field to "{{ name-of-resource }}"' required: true + type: dict password: description: - The password for the user. required: false + type: str extends_documentation_fragment: gcp ''' diff --git a/lib/ansible/modules/cloud/google/gcp_sql_user_facts.py b/lib/ansible/modules/cloud/google/gcp_sql_user_facts.py index 5b151ef59e6..989652cbce7 100644 --- a/lib/ansible/modules/cloud/google/gcp_sql_user_facts.py +++ b/lib/ansible/modules/cloud/google/gcp_sql_user_facts.py @@ -49,6 +49,7 @@ options: to a gcp_sql_instance task and then set this instance field to "{{ name-of-resource }}"' required: true + type: dict extends_documentation_fragment: gcp ''' diff --git a/lib/ansible/modules/cloud/google/gcp_storage_bucket.py b/lib/ansible/modules/cloud/google/gcp_storage_bucket.py index 3c483eff404..58ac095b85c 100644 --- a/lib/ansible/modules/cloud/google/gcp_storage_bucket.py +++ b/lib/ansible/modules/cloud/google/gcp_storage_bucket.py @@ -56,6 +56,7 @@ options: description: - Access controls on the bucket. required: false + type: list suboptions: bucket: description: @@ -66,6 +67,7 @@ options: to a gcp_storage_bucket task and then set this bucket field to "{{ name-of-resource }}"' required: true + type: dict entity: description: - 'The entity holding the permission, in one of the following forms: user-userId @@ -76,59 +78,71 @@ options: - To refer to all members of the Google Apps for Business domain example.com, the entity would be domain-example.com. required: true + type: str entity_id: description: - The ID for the entity. required: false + type: str project_team: description: - The project team associated with the entity. required: false + type: dict suboptions: project_number: description: - The project team associated with the entity. required: false + type: str team: description: - The team. - 'Some valid choices include: "editors", "owners", "viewers"' required: false + type: str role: description: - The access permission for the entity. - 'Some valid choices include: "OWNER", "READER", "WRITER"' required: false + type: str cors: description: - The bucket's Cross-Origin Resource Sharing (CORS) configuration. required: false + type: list suboptions: max_age_seconds: description: - The value, in seconds, to return in the Access-Control-Max-Age header used in preflight responses. required: false + type: int method: description: - 'The list of HTTP methods on which to include CORS response headers, (GET, OPTIONS, POST, etc) Note: "*" is permitted in the list of methods, and means "any method".' required: false + type: list origin: description: - The list of Origins eligible to receive CORS response headers. - 'Note: "*" is permitted in the list of origins, and means "any Origin".' required: false + type: list response_header: description: - The list of HTTP headers other than the simple response headers to give permission for the user-agent to share across domains. required: false + type: list default_object_acl: description: - Default access controls to apply to new objects when no ACL is provided. required: false + type: list version_added: 2.7 suboptions: bucket: @@ -140,6 +154,7 @@ options: to a gcp_storage_bucket task and then set this bucket field to "{{ name-of-resource }}"' required: true + type: dict entity: description: - 'The entity holding the permission, in one of the following forms: * user-{{userId}} @@ -148,58 +163,69 @@ options: (such as "domain-example.com") * project-team-{{projectId}} * allUsers * allAuthenticatedUsers .' required: true + type: str object: description: - The name of the object, if applied to an object. required: false + type: str role: description: - The access permission for the entity. - 'Some valid choices include: "OWNER", "READER"' required: true + type: str lifecycle: description: - The bucket's lifecycle configuration. - See U(https://developers.google.com/storage/docs/lifecycle) for more information. required: false + type: dict suboptions: rule: description: - A lifecycle management rule, which is made of an action to take and the condition(s) under which the action will be taken. required: false + type: list suboptions: action: description: - The action to take. required: false + type: dict suboptions: storage_class: description: - Target storage class. Required iff the type of the action is SetStorageClass. required: false + type: str type: description: - Type of the action. Currently, only Delete and SetStorageClass are supported. - 'Some valid choices include: "Delete", "SetStorageClass"' required: false + type: str condition: description: - The condition(s) under which the action will be taken. required: false + type: dict suboptions: age_days: description: - Age of an object (in days). This condition is satisfied when an object reaches the specified age. required: false + type: int created_before: description: - A date in RFC 3339 format with only the date part (for instance, "2013-01-15"). This condition is satisfied when an object is created before midnight of the specified date in UTC. required: false + type: str is_live: description: - Relevant only for versioned objects. If the value is true, this @@ -213,49 +239,59 @@ options: will be matched. Values include MULTI_REGIONAL, REGIONAL, NEARLINE, COLDLINE, STANDARD, and DURABLE_REDUCED_AVAILABILITY. required: false + type: list num_newer_versions: description: - Relevant only for versioned objects. If the value is N, this condition is satisfied when there are at least N versions (including the live version) newer than this version of the object. required: false + type: int location: description: - The location of the bucket. Object data for objects in the bucket resides in physical storage within this region. Defaults to US. See the developer's guide for the authoritative list. required: false + type: str logging: description: - The bucket's logging configuration, which defines the destination bucket and optional name prefix for the current bucket's logs. required: false + type: dict suboptions: log_bucket: description: - The destination bucket where the current bucket's logs should be placed. required: false + type: str log_object_prefix: description: - A prefix for log object names. required: false + type: str metageneration: description: - The metadata generation of this bucket. required: false + type: int name: description: - The name of the bucket. required: false + type: str owner: description: - The owner of the bucket. This is always the project team's owner group. required: false + type: dict suboptions: entity: description: - The entity, in the form project-owner-projectId. required: false + type: str storage_class: description: - The bucket's default storage class, used whenever no storageClass is specified @@ -267,10 +303,12 @@ options: - 'Some valid choices include: "MULTI_REGIONAL", "REGIONAL", "STANDARD", "NEARLINE", "COLDLINE", "DURABLE_REDUCED_AVAILABILITY"' required: false + type: str versioning: description: - The bucket's versioning configuration. required: false + type: dict suboptions: enabled: description: @@ -283,6 +321,7 @@ options: accessing bucket contents as a web site. See the Static Website Examples for more information. required: false + type: dict suboptions: main_page_suffix: description: @@ -291,16 +330,19 @@ options: object. This allows the creation of index.html objects to represent directory pages. required: false + type: str not_found_page: description: - If the requested object path is missing, and any mainPageSuffix object is missing, if applicable, the service will return the named object from this bucket as the content for a 404 Not Found result. required: false + type: str project: description: - A valid API project identifier. required: false + type: str predefined_default_object_acl: description: - Apply a predefined set of default object access controls to this bucket. @@ -317,6 +359,7 @@ options: - 'Some valid choices include: "authenticatedRead", "bucketOwnerFullControl", "bucketOwnerRead", "private", "projectPrivate", "publicRead"' required: false + type: str extends_documentation_fragment: gcp ''' diff --git a/lib/ansible/modules/cloud/google/gcp_storage_bucket_access_control.py b/lib/ansible/modules/cloud/google/gcp_storage_bucket_access_control.py index a91068cb32b..4dac53b42db 100644 --- a/lib/ansible/modules/cloud/google/gcp_storage_bucket_access_control.py +++ b/lib/ansible/modules/cloud/google/gcp_storage_bucket_access_control.py @@ -65,6 +65,7 @@ options: to a gcp_storage_bucket task and then set this bucket field to "{{ name-of-resource }}"' required: true + type: dict entity: description: - 'The entity holding the permission, in one of the following forms: user-userId @@ -74,29 +75,35 @@ options: - To refer to all members of the Google Apps for Business domain example.com, the entity would be domain-example.com. required: true + type: str entity_id: description: - The ID for the entity. required: false + type: str project_team: description: - The project team associated with the entity. required: false + type: dict suboptions: project_number: description: - The project team associated with the entity. required: false + type: str team: description: - The team. - 'Some valid choices include: "editors", "owners", "viewers"' required: false + type: str role: description: - The access permission for the entity. - 'Some valid choices include: "OWNER", "READER", "WRITER"' required: false + type: str extends_documentation_fragment: gcp ''' diff --git a/lib/ansible/modules/cloud/google/gcp_storage_object.py b/lib/ansible/modules/cloud/google/gcp_storage_object.py index f373c6b7af5..99b5c464f40 100644 --- a/lib/ansible/modules/cloud/google/gcp_storage_object.py +++ b/lib/ansible/modules/cloud/google/gcp_storage_object.py @@ -52,6 +52,7 @@ options: - Upload or download from the bucket. - 'Some valid choices include: "download", "upload"' required: false + type: str overwrite: description: - "'Overwrite the file on the bucket/local machine. If overwrite is false and @@ -62,14 +63,17 @@ options: description: - Source location of file (may be local machine or cloud depending on action). required: false + type: path dest: description: - Destination location of file (may be local machine or cloud depending on action). required: false + type: path bucket: description: - The name of the bucket. required: false + type: str extends_documentation_fragment: gcp ''' diff --git a/lib/ansible/modules/cloud/google/gcp_tpu_node.py b/lib/ansible/modules/cloud/google/gcp_tpu_node.py index d0b815c27f5..afd00aceb0d 100644 --- a/lib/ansible/modules/cloud/google/gcp_tpu_node.py +++ b/lib/ansible/modules/cloud/google/gcp_tpu_node.py @@ -51,24 +51,29 @@ options: description: - The immutable name of the TPU. required: true + type: str description: description: - The user-supplied description of the TPU. Maximum of 512 characters. required: false + type: str accelerator_type: description: - The type of hardware accelerators associated with this node. required: true + type: str tensorflow_version: description: - The version of Tensorflow running in the Node. required: true + type: str network: description: - The name of a network to peer the TPU node to. It must be a preexisting Compute Engine network inside of the project on which this API has been activated. If none is provided, "default" will be used. required: false + type: str cidr_block: description: - The CIDR block that the TPU node will use when selecting an IP address. This @@ -80,10 +85,12 @@ options: network, or the provided network is peered with another network that is using that CIDR block. required: true + type: str scheduling_config: description: - Sets the scheduling options for this TPU instance. required: false + type: dict suboptions: preemptible: description: @@ -95,10 +102,12 @@ options: description: - Resource labels to represent user provided metadata. required: false + type: dict zone: description: - The GCP location for the TPU. required: true + type: str extends_documentation_fragment: gcp notes: - 'API Reference: U(https://cloud.google.com/tpu/docs/reference/rest/)' @@ -402,7 +411,7 @@ def wait_for_operation(module, response): return {} status = navigate_hash(op_result, ['done']) wait_done = wait_for_completion(status, op_result, module) - raise_if_errors(op_result, ['error'], module) + raise_if_errors(wait_done, ['error'], module) return navigate_hash(wait_done, ['response']) diff --git a/lib/ansible/modules/cloud/google/gcp_tpu_node_facts.py b/lib/ansible/modules/cloud/google/gcp_tpu_node_facts.py index f11e6ae1db1..ab4bd8c9c47 100644 --- a/lib/ansible/modules/cloud/google/gcp_tpu_node_facts.py +++ b/lib/ansible/modules/cloud/google/gcp_tpu_node_facts.py @@ -44,6 +44,7 @@ options: description: - The GCP location for the TPU. required: true + type: str extends_documentation_fragment: gcp ''' diff --git a/test/integration/targets/gcp_spanner_database/tasks/main.yml b/test/integration/targets/gcp_spanner_database/tasks/main.yml index 25b399d72c5..693c6d59d43 100644 --- a/test/integration/targets/gcp_spanner_database/tasks/main.yml +++ b/test/integration/targets/gcp_spanner_database/tasks/main.yml @@ -60,7 +60,7 @@ - name: verify that command succeeded assert: that: - - "'webstore' in \"{{ results['resources'] | map(attribute='name') | list }}\"" + - results['resources'] | map(attribute='name') | select("match", ".*webstore.*") | list | length == 1 # ---------------------------------------------------------------------------- - name: create a database that already exists gcp_spanner_database: @@ -101,7 +101,7 @@ - name: verify that command succeeded assert: that: - - "'webstore' not in \"{{ results['resources'] | map(attribute='name') | list }}\"" + - results['resources'] | map(attribute='name') | select("match", ".*webstore.*") | list | length == 0 # ---------------------------------------------------------------------------- - name: delete a database that does not exist gcp_spanner_database: diff --git a/test/integration/targets/gcp_spanner_instance/tasks/main.yml b/test/integration/targets/gcp_spanner_instance/tasks/main.yml index 41b1d78bee8..0dd460fa5f3 100644 --- a/test/integration/targets/gcp_spanner_instance/tasks/main.yml +++ b/test/integration/targets/gcp_spanner_instance/tasks/main.yml @@ -54,7 +54,7 @@ - name: verify that command succeeded assert: that: - - "\"{{resource_name}}\" in \"{{ results['resources'] | map(attribute='name') | list }}\"" + - results['resources'] | map(attribute='name') | select("match", ".*testinstance.*") | list | length == 1 # ---------------------------------------------------------------------------- - name: create a instance that already exists gcp_spanner_instance: @@ -102,7 +102,7 @@ - name: verify that command succeeded assert: that: - - "\"{{resource_name}}\" not in \"{{ results['resources'] | map(attribute='name') | list }}\"" + - results['resources'] | map(attribute='name') | select("match", ".*testinstance.*") | list | length == 0 # ---------------------------------------------------------------------------- - name: delete a instance that does not exist gcp_spanner_instance: diff --git a/test/sanity/validate-modules/ignore.txt b/test/sanity/validate-modules/ignore.txt index 367fda7b211..41f5db8785e 100644 --- a/test/sanity/validate-modules/ignore.txt +++ b/test/sanity/validate-modules/ignore.txt @@ -743,13 +743,10 @@ lib/ansible/modules/cloud/google/gcp_redis_instance_facts.py E337 lib/ansible/modules/cloud/google/gcp_redis_instance.py E337 lib/ansible/modules/cloud/google/gcp_resourcemanager_project.py E337 lib/ansible/modules/cloud/google/gcp_sourcerepo_repository.py E337 -lib/ansible/modules/cloud/google/gcp_spanner_database_facts.py E337 lib/ansible/modules/cloud/google/gcp_spanner_database.py E337 lib/ansible/modules/cloud/google/gcp_spanner_instance.py E337 -lib/ansible/modules/cloud/google/gcp_sql_database_facts.py E337 lib/ansible/modules/cloud/google/gcp_sql_database.py E337 lib/ansible/modules/cloud/google/gcp_sql_instance.py E337 -lib/ansible/modules/cloud/google/gcp_sql_user_facts.py E337 lib/ansible/modules/cloud/google/gcp_sql_user.py E337 lib/ansible/modules/cloud/google/gcp_storage_bucket_access_control.py E337 lib/ansible/modules/cloud/google/gcp_storage_bucket.py E337 @@ -758,7 +755,6 @@ lib/ansible/modules/cloud/google/_gcp_target_proxy.py E322 lib/ansible/modules/cloud/google/_gcp_target_proxy.py E326 lib/ansible/modules/cloud/google/_gcp_target_proxy.py E337 lib/ansible/modules/cloud/google/_gcp_target_proxy.py E338 -lib/ansible/modules/cloud/google/gcp_tpu_node_facts.py E337 lib/ansible/modules/cloud/google/gcp_tpu_node.py E337 lib/ansible/modules/cloud/google/gcpubsub_facts.py E322 lib/ansible/modules/cloud/google/gcpubsub_facts.py E324