diff --git a/lib/ansible/modules/cloud/google/gcp_spanner_instance.py b/lib/ansible/modules/cloud/google/gcp_spanner_instance.py index f13778a92482a2..c6d607ec9fcdae 100644 --- a/lib/ansible/modules/cloud/google/gcp_spanner_instance.py +++ b/lib/ansible/modules/cloud/google/gcp_spanner_instance.py @@ -50,13 +50,17 @@ name: description: - A unique identifier for the instance, which cannot be changed after the instance - is created. Values are of the form projects//instances/[a-z][-a-z0-9]*[a-z0-9]. - The final segment of the name must be between 6 and 30 characters in length. - required: false + is created. The name must be between 6 and 30 characters in length. + required: true config: description: - - A reference to the instance configuration. - required: false + - The name of the instance's configuration (similar but not quite the same as + a region) which defines defines the geographic placement and replication of + your databases in this instance. It determines where your data is stored. Values + are typically of the form `regional-europe-west1` , `us-central` etc. + - 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 display_name: description: - The descriptive name for this instance as it appears in UIs. Must be unique @@ -66,28 +70,16 @@ description: - The number of nodes allocated to this instance. required: false + default: '1' labels: description: - - Cloud Labels are a flexible and lightweight mechanism for organizing cloud resources - into groups that reflect a customer's organizational needs and deployment strategies. - Cloud Labels can be used to filter collections of resources. They can be used - to control how resource metrics are aggregated. And they can be used as arguments - to policy management rules (e.g. route, firewall, load balancing, etc.). - - 'Label keys must be between 1 and 63 characters long and must conform to the - following regular expression: `[a-z]([-a-z0-9]*[a-z0-9])?`.' - - Label values must be between 0 and 63 characters long and must conform to the - regular expression `([a-z]([-a-z0-9]*[a-z0-9])?)?`. - - No more than 64 labels can be associated with a given resource. - - See U(https://goo.gl/xmQnxf) for more information on and examples of labels. - - 'If you plan to use labels in your own code, please note that additional characters - may be allowed in the future. And so you are advised to use an internal label - representation, such as JSON, which doesn''t rely upon specific characters being - disallowed. For example, representing labels as the string: name + "_" + value - would prove problematic if we were to allow "_" in a future release.' - 'An object containing a list of "key": value pairs.' - 'Example: { "name": "wrench", "mass": "1.3kg", "count": "3" }.' required: false extends_documentation_fragment: gcp +notes: +- 'API Reference: U(https://cloud.google.com/spanner/docs/reference/rest/v1/projects.instances)' +- 'Official Documentation: U(https://cloud.google.com/spanner/)' ''' EXAMPLES = ''' @@ -109,13 +101,17 @@ name: description: - A unique identifier for the instance, which cannot be changed after the instance - is created. Values are of the form projects//instances/[a-z][-a-z0-9]*[a-z0-9]. - The final segment of the name must be between 6 and 30 characters in length. + is created. The name must be between 6 and 30 characters in length. returned: success type: str config: description: - - A reference to the instance configuration. + - The name of the instance's configuration (similar but not quite the same as a + region) which defines defines the geographic placement and replication of your + databases in this instance. It determines where your data is stored. Values are + typically of the form `regional-europe-west1` , `us-central` etc. + - In order to obtain a valid list please consult the [Configuration section of the + docs](U(https://cloud.google.com/spanner/docs/instances).) returned: success type: str displayName: @@ -131,22 +127,6 @@ type: int labels: description: - - Cloud Labels are a flexible and lightweight mechanism for organizing cloud resources - into groups that reflect a customer's organizational needs and deployment strategies. - Cloud Labels can be used to filter collections of resources. They can be used - to control how resource metrics are aggregated. And they can be used as arguments - to policy management rules (e.g. route, firewall, load balancing, etc.). - - 'Label keys must be between 1 and 63 characters long and must conform to the following - regular expression: `[a-z]([-a-z0-9]*[a-z0-9])?`.' - - Label values must be between 0 and 63 characters long and must conform to the - regular expression `([a-z]([-a-z0-9]*[a-z0-9])?)?`. - - No more than 64 labels can be associated with a given resource. - - See U(https://goo.gl/xmQnxf) for more information on and examples of labels. - - 'If you plan to use labels in your own code, please note that additional characters - may be allowed in the future. And so you are advised to use an internal label - representation, such as JSON, which doesn''t rely upon specific characters being - disallowed. For example, representing labels as the string: name + "_" + value - would prove problematic if we were to allow "_" in a future release.' - 'An object containing a list of "key": value pairs.' - 'Example: { "name": "wrench", "mass": "1.3kg", "count": "3" }.' returned: success @@ -159,6 +139,7 @@ from ansible.module_utils.gcp_utils import navigate_hash, GcpSession, GcpModule, GcpRequest, replace_resource_dict import json +import time ################################################################################ # Main @@ -171,10 +152,10 @@ def main(): module = GcpModule( argument_spec=dict( state=dict(default='present', choices=['present', 'absent'], type='str'), - name=dict(type='str'), - config=dict(type='str'), + name=dict(required=True, type='str'), + config=dict(required=True, type='str'), display_name=dict(required=True, type='str'), - node_count=dict(type='int'), + node_count=dict(default=1, type='int'), labels=dict(type='dict'), ) ) @@ -211,17 +192,17 @@ def main(): def create(module, link): auth = GcpSession(module, 'spanner') - return return_if_object(module, auth.post(link, resource_to_create(module))) + return wait_for_operation(module, auth.post(link, resource_to_create(module))) def update(module, link): auth = GcpSession(module, 'spanner') - return return_if_object(module, auth.patch(link, resource_to_update(module))) + return wait_for_operation(module, auth.patch(link, resource_to_update(module))) def delete(module, link): auth = GcpSession(module, 'spanner') - return return_if_object(module, auth.delete(link)) + return wait_for_operation(module, auth.delete(link)) def resource_to_request(module): @@ -299,7 +280,7 @@ def is_different(module, response): # This is for doing comparisons with Ansible's current parameters. def response_to_hash(module, response): return { - u'name': response.get(u'name'), + u'name': module.params.get('name'), u'config': response.get(u'config'), u'displayName': response.get(u'displayName'), u'nodeCount': response.get(u'nodeCount'), @@ -307,6 +288,41 @@ def response_to_hash(module, response): } +def async_op_url(module, extra_data=None): + if extra_data is None: + extra_data = {} + url = "https://spanner.googleapis.com/v1/projects/{project}/global/operations/{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, ['status']) + wait_done = wait_for_completion(status, op_result, module) + return fetch_resource(module, navigate_hash(wait_done, ['targetLink'])) + + +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 status != 'DONE': + raise_if_errors(op_result, ['error', 'errors'], module) + time.sleep(1.0) + op_result = fetch_resource(module, op_uri) + status = navigate_hash(op_result, ['status']) + 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 resource_to_create(module): instance = resource_to_request(module) instance['name'] = "projects/{0}/instances/{1}".format(module.params['project'], module.params['name']) diff --git a/lib/ansible/modules/cloud/google/gcp_spanner_instance_facts.py b/lib/ansible/modules/cloud/google/gcp_spanner_instance_facts.py index 07af4a459d7510..918bfae2b1caba 100644 --- a/lib/ansible/modules/cloud/google/gcp_spanner_instance_facts.py +++ b/lib/ansible/modules/cloud/google/gcp_spanner_instance_facts.py @@ -60,13 +60,17 @@ name: description: - A unique identifier for the instance, which cannot be changed after the instance - is created. Values are of the form projects//instances/[a-z][-a-z0-9]*[a-z0-9]. - The final segment of the name must be between 6 and 30 characters in length. + is created. The name must be between 6 and 30 characters in length. returned: success type: str config: description: - - A reference to the instance configuration. + - The name of the instance's configuration (similar but not quite the same as + a region) which defines defines the geographic placement and replication of + your databases in this instance. It determines where your data is stored. + Values are typically of the form `regional-europe-west1` , `us-central` etc. + - In order to obtain a valid list please consult the [Configuration section + of the docs](U(https://cloud.google.com/spanner/docs/instances).) returned: success type: str displayName: @@ -82,23 +86,6 @@ type: int labels: description: - - Cloud Labels are a flexible and lightweight mechanism for organizing cloud - resources into groups that reflect a customer's organizational needs and deployment - strategies. Cloud Labels can be used to filter collections of resources. They - can be used to control how resource metrics are aggregated. And they can be - used as arguments to policy management rules (e.g. route, firewall, load balancing, - etc.). - - 'Label keys must be between 1 and 63 characters long and must conform to the - following regular expression: `[a-z]([-a-z0-9]*[a-z0-9])?`.' - - Label values must be between 0 and 63 characters long and must conform to - the regular expression `([a-z]([-a-z0-9]*[a-z0-9])?)?`. - - No more than 64 labels can be associated with a given resource. - - See U(https://goo.gl/xmQnxf) for more information on and examples of labels. - - 'If you plan to use labels in your own code, please note that additional characters - may be allowed in the future. And so you are advised to use an internal label - representation, such as JSON, which doesn''t rely upon specific characters - being disallowed. For example, representing labels as the string: name + "_" - + value would prove problematic if we were to allow "_" in a future release.' - 'An object containing a list of "key": value pairs.' - 'Example: { "name": "wrench", "mass": "1.3kg", "count": "3" }.' returned: success