diff --git a/lib/ansible/modules/cloud/google/gcp_compute_address.py b/lib/ansible/modules/cloud/google/gcp_compute_address.py index b5b8726b47b..d4295108465 100644 --- a/lib/ansible/modules/cloud/google/gcp_compute_address.py +++ b/lib/ansible/modules/cloud/google/gcp_compute_address.py @@ -283,7 +283,7 @@ def resource_to_request(module): } return_vals = {} for k, v in request.items(): - if v: + if v or v is False: return_vals[k] = v return return_vals diff --git a/lib/ansible/modules/cloud/google/gcp_compute_backend_bucket.py b/lib/ansible/modules/cloud/google/gcp_compute_backend_bucket.py index 3cbc235d42e..711baac99e8 100644 --- a/lib/ansible/modules/cloud/google/gcp_compute_backend_bucket.py +++ b/lib/ansible/modules/cloud/google/gcp_compute_backend_bucket.py @@ -224,7 +224,7 @@ def resource_to_request(module): } return_vals = {} for k, v in request.items(): - if v: + if v or v is False: return_vals[k] = v return return_vals diff --git a/lib/ansible/modules/cloud/google/gcp_compute_backend_service.py b/lib/ansible/modules/cloud/google/gcp_compute_backend_service.py index 6f69be8da63..4716e96fcea 100644 --- a/lib/ansible/modules/cloud/google/gcp_compute_backend_service.py +++ b/lib/ansible/modules/cloud/google/gcp_compute_backend_service.py @@ -731,7 +731,7 @@ def resource_to_request(module): } return_vals = {} for k, v in request.items(): - if v: + if v or v is False: return_vals[k] = v return return_vals diff --git a/lib/ansible/modules/cloud/google/gcp_compute_disk.py b/lib/ansible/modules/cloud/google/gcp_compute_disk.py index c8156e2db4f..327313991a7 100644 --- a/lib/ansible/modules/cloud/google/gcp_compute_disk.py +++ b/lib/ansible/modules/cloud/google/gcp_compute_disk.py @@ -523,7 +523,7 @@ def resource_to_request(module): } return_vals = {} for k, v in request.items(): - if v: + if v or v is False: return_vals[k] = v return return_vals diff --git a/lib/ansible/modules/cloud/google/gcp_compute_firewall.py b/lib/ansible/modules/cloud/google/gcp_compute_firewall.py index f75f16bdf33..0a91375152f 100644 --- a/lib/ansible/modules/cloud/google/gcp_compute_firewall.py +++ b/lib/ansible/modules/cloud/google/gcp_compute_firewall.py @@ -151,7 +151,9 @@ options: task and then set this network field to "{{ name-of-resource }}" Alternatively, you can set this network to a dictionary with the selfLink key where the value is the selfLink of your Network' - required: true + required: false + default: + selfLink: global/networks/default priority: description: - Priority for this rule. This is an integer between 0 and 65535, both inclusive. @@ -412,6 +414,7 @@ targetTags: from ansible.module_utils.gcp_utils import navigate_hash, GcpSession, GcpModule, GcpRequest, remove_nones_from_dict, replace_resource_dict import json +import re import time ################################################################################ @@ -438,14 +441,21 @@ def main(): direction=dict(type='str', choices=['INGRESS', 'EGRESS']), disabled=dict(type='bool'), name=dict(required=True, type='str'), - network=dict(required=True, type='dict'), + network=dict(default={'selfLink': 'global/networks/default'}, type='dict'), priority=dict(default=1000, type='int'), source_ranges=dict(type='list', elements='str'), source_service_accounts=dict(type='list', elements='str'), source_tags=dict(type='list', elements='str'), target_service_accounts=dict(type='list', elements='str'), target_tags=dict(type='list', elements='str') - ) + ), + mutually_exclusive=[['allowed', 'denied'], + ['destination_ranges', 'source_ranges', 'source_tags'], + ['destination_ranges', 'source_ranges'], + ['source_service_accounts', 'source_tags', 'target_tags'], + ['destination_ranges', 'source_service_accounts', 'source_tags', 'target_service_accounts'], + ['source_tags', 'target_service_accounts', 'target_tags'], + ['source_service_accounts', 'target_service_accounts', 'target_tags']] ) if not module.params['scopes']: @@ -512,9 +522,10 @@ def resource_to_request(module): u'targetServiceAccounts': module.params.get('target_service_accounts'), u'targetTags': module.params.get('target_tags') } + request = encode_request(request, module) return_vals = {} for k, v in request.items(): - if v: + if v or v is False: return_vals[k] = v return return_vals @@ -630,6 +641,15 @@ def raise_if_errors(response, err_path, module): module.fail_json(msg=errors) +def encode_request(request, module): + if 'network' in request and request['network'] is not None: + if not re.match(r'https://www.googleapis.com/compute/v1/projects/.*', request['network']): + request['network'] = 'https://www.googleapis.com/compute/v1/projects/{project}/{network}'.format(project=module.params['project'], + network=request['network']) + + return request + + class FirewallAllowedArray(object): def __init__(self, request, module): self.module = module diff --git a/lib/ansible/modules/cloud/google/gcp_compute_forwarding_rule.py b/lib/ansible/modules/cloud/google/gcp_compute_forwarding_rule.py index 9ba834304a7..192c73160b4 100644 --- a/lib/ansible/modules/cloud/google/gcp_compute_forwarding_rule.py +++ b/lib/ansible/modules/cloud/google/gcp_compute_forwarding_rule.py @@ -513,7 +513,7 @@ def resource_to_request(module): } return_vals = {} for k, v in request.items(): - if v: + if v or v is False: return_vals[k] = v return return_vals diff --git a/lib/ansible/modules/cloud/google/gcp_compute_global_address.py b/lib/ansible/modules/cloud/google/gcp_compute_global_address.py index 88283797388..4d6861a90fe 100644 --- a/lib/ansible/modules/cloud/google/gcp_compute_global_address.py +++ b/lib/ansible/modules/cloud/google/gcp_compute_global_address.py @@ -232,7 +232,7 @@ def resource_to_request(module): } return_vals = {} for k, v in request.items(): - if v: + if v or v is False: return_vals[k] = v return return_vals diff --git a/lib/ansible/modules/cloud/google/gcp_compute_global_forwarding_rule.py b/lib/ansible/modules/cloud/google/gcp_compute_global_forwarding_rule.py index bf43943e43d..21acb0c69ff 100644 --- a/lib/ansible/modules/cloud/google/gcp_compute_global_forwarding_rule.py +++ b/lib/ansible/modules/cloud/google/gcp_compute_global_forwarding_rule.py @@ -501,7 +501,7 @@ def resource_to_request(module): } return_vals = {} for k, v in request.items(): - if v: + if v or v is False: return_vals[k] = v return return_vals diff --git a/lib/ansible/modules/cloud/google/gcp_compute_health_check.py b/lib/ansible/modules/cloud/google/gcp_compute_health_check.py index 232dc92f785..7d957db291a 100644 --- a/lib/ansible/modules/cloud/google/gcp_compute_health_check.py +++ b/lib/ansible/modules/cloud/google/gcp_compute_health_check.py @@ -124,6 +124,12 @@ options: - The default value is /. required: false default: "/" + response: + description: + - The bytes to match against the beginning of the response data. If left empty + (the default value), any response will indicate health. The response data + can only be ASCII. + required: false port: description: - The TCP port number for the HTTP health check request. @@ -160,6 +166,12 @@ options: - The default value is /. required: false default: "/" + response: + description: + - The bytes to match against the beginning of the response data. If left empty + (the default value), any response will indicate health. The response data + can only be ASCII. + required: false port: description: - The TCP port number for the HTTPS health check request. @@ -352,6 +364,13 @@ httpHealthCheck: - The default value is /. returned: success type: str + response: + description: + - The bytes to match against the beginning of the response data. If left empty + (the default value), any response will indicate health. The response data + can only be ASCII. + returned: success + type: str port: description: - The TCP port number for the HTTP health check request. @@ -389,6 +408,13 @@ httpsHealthCheck: - The default value is /. returned: success type: str + response: + description: + - The bytes to match against the beginning of the response data. If left empty + (the default value), any response will indicate health. The response data + can only be ASCII. + returned: success + type: str port: description: - The TCP port number for the HTTPS health check request. @@ -514,6 +540,7 @@ def main(): http_health_check=dict(type='dict', options=dict( host=dict(type='str'), request_path=dict(default='/', type='str'), + response=dict(type='str'), port=dict(type='int'), port_name=dict(type='str'), proxy_header=dict(default='NONE', type='str', choices=['NONE', 'PROXY_V1']) @@ -521,6 +548,7 @@ def main(): https_health_check=dict(type='dict', options=dict( host=dict(type='str'), request_path=dict(default='/', type='str'), + response=dict(type='str'), port=dict(type='int'), port_name=dict(type='str'), proxy_header=dict(default='NONE', type='str', choices=['NONE', 'PROXY_V1']) @@ -539,7 +567,8 @@ def main(): port_name=dict(type='str'), proxy_header=dict(default='NONE', type='str', choices=['NONE', 'PROXY_V1']) )) - ) + ), + mutually_exclusive=[['http_health_check', 'https_health_check', 'ssl_health_check', 'tcp_health_check']] ) if not module.params['scopes']: @@ -605,7 +634,7 @@ def resource_to_request(module): } return_vals = {} for k, v in request.items(): - if v: + if v or v is False: return_vals[k] = v return return_vals @@ -730,6 +759,7 @@ class HealthCheckHttphealthcheck(object): return remove_nones_from_dict({ u'host': self.request.get('host'), u'requestPath': self.request.get('request_path'), + u'response': self.request.get('response'), u'port': self.request.get('port'), u'portName': self.request.get('port_name'), u'proxyHeader': self.request.get('proxy_header') @@ -739,6 +769,7 @@ class HealthCheckHttphealthcheck(object): return remove_nones_from_dict({ u'host': self.request.get(u'host'), u'requestPath': self.request.get(u'requestPath'), + u'response': self.request.get(u'response'), u'port': self.request.get(u'port'), u'portName': self.request.get(u'portName'), u'proxyHeader': self.request.get(u'proxyHeader') @@ -757,6 +788,7 @@ class HealthCheckHttpshealthcheck(object): return remove_nones_from_dict({ u'host': self.request.get('host'), u'requestPath': self.request.get('request_path'), + u'response': self.request.get('response'), u'port': self.request.get('port'), u'portName': self.request.get('port_name'), u'proxyHeader': self.request.get('proxy_header') @@ -766,6 +798,7 @@ class HealthCheckHttpshealthcheck(object): return remove_nones_from_dict({ u'host': self.request.get(u'host'), u'requestPath': self.request.get(u'requestPath'), + u'response': self.request.get(u'response'), u'port': self.request.get(u'port'), u'portName': self.request.get(u'portName'), u'proxyHeader': self.request.get(u'proxyHeader') diff --git a/lib/ansible/modules/cloud/google/gcp_compute_health_check_facts.py b/lib/ansible/modules/cloud/google/gcp_compute_health_check_facts.py index a35592f7a81..41dbf5735d1 100644 --- a/lib/ansible/modules/cloud/google/gcp_compute_health_check_facts.py +++ b/lib/ansible/modules/cloud/google/gcp_compute_health_check_facts.py @@ -142,6 +142,13 @@ items: - The default value is /. returned: success type: str + response: + description: + - The bytes to match against the beginning of the response data. If left + empty (the default value), any response will indicate health. The response + data can only be ASCII. + returned: success + type: str port: description: - The TCP port number for the HTTP health check request. @@ -179,6 +186,13 @@ items: - The default value is /. returned: success type: str + response: + description: + - The bytes to match against the beginning of the response data. If left + empty (the default value), any response will indicate health. The response + data can only be ASCII. + returned: success + type: str port: description: - The TCP port number for the HTTPS health check request. diff --git a/lib/ansible/modules/cloud/google/gcp_compute_http_health_check.py b/lib/ansible/modules/cloud/google/gcp_compute_http_health_check.py index 75d259ef92f..bb6ca8b2322 100644 --- a/lib/ansible/modules/cloud/google/gcp_compute_http_health_check.py +++ b/lib/ansible/modules/cloud/google/gcp_compute_http_health_check.py @@ -288,7 +288,7 @@ def resource_to_request(module): } return_vals = {} for k, v in request.items(): - if v: + if v or v is False: return_vals[k] = v return return_vals diff --git a/lib/ansible/modules/cloud/google/gcp_compute_https_health_check.py b/lib/ansible/modules/cloud/google/gcp_compute_https_health_check.py index be515ce034b..84054f37a61 100644 --- a/lib/ansible/modules/cloud/google/gcp_compute_https_health_check.py +++ b/lib/ansible/modules/cloud/google/gcp_compute_https_health_check.py @@ -285,7 +285,7 @@ def resource_to_request(module): } return_vals = {} for k, v in request.items(): - if v: + if v or v is False: return_vals[k] = v return return_vals diff --git a/lib/ansible/modules/cloud/google/gcp_compute_image.py b/lib/ansible/modules/cloud/google/gcp_compute_image.py index 80356c9b264..51385be5352 100644 --- a/lib/ansible/modules/cloud/google/gcp_compute_image.py +++ b/lib/ansible/modules/cloud/google/gcp_compute_image.py @@ -520,7 +520,7 @@ def resource_to_request(module): } return_vals = {} for k, v in request.items(): - if v: + if v or v is False: return_vals[k] = v return return_vals diff --git a/lib/ansible/modules/cloud/google/gcp_compute_instance.py b/lib/ansible/modules/cloud/google/gcp_compute_instance.py index b71b0d7173e..8d000083467 100644 --- a/lib/ansible/modules/cloud/google/gcp_compute_instance.py +++ b/lib/ansible/modules/cloud/google/gcp_compute_instance.py @@ -375,6 +375,22 @@ options: description: - The list of scopes to be made available for this service account. required: false + status: + description: + - 'The status of the instance. One of the following values: PROVISIONING, STAGING, + RUNNING, STOPPING, SUSPENDING, SUSPENDED, and TERMINATED.' + - As a user, use RUNNING to keep a machine "on" and TERMINATED to turn a machine + off . + required: false + version_added: 2.8 + choices: + - PROVISIONING + - STAGING + - RUNNING + - STOPPING + - SUSPENDING + - SUSPENDED + - TERMINATED tags: description: - A list of tags to apply to this instance. Tags are used to identify valid sources @@ -817,6 +833,8 @@ status: description: - 'The status of the instance. One of the following values: PROVISIONING, STAGING, RUNNING, STOPPING, SUSPENDING, SUSPENDED, and TERMINATED.' + - As a user, use RUNNING to keep a machine "on" and TERMINATED to turn a machine + off . returned: success type: str statusMessage: @@ -933,6 +951,7 @@ def main(): email=dict(type='str'), scopes=dict(type='list', elements='str') )), + status=dict(type='str', choices=['PROVISIONING', 'STAGING', 'RUNNING', 'STOPPING', 'SUSPENDING', 'SUSPENDED', 'TERMINATED']), tags=dict(type='dict', options=dict( fingerprint=dict(type='str'), items=dict(type='list', elements='str') @@ -967,6 +986,11 @@ def main(): else: fetch = {} + if fetch: + instance = InstancePower(module, fetch.get('status')) + instance.run() + if module.params.get('status'): + fetch.update({'status': module.params['status']}) fetch.update({'changed': changed}) module.exit_json(**fetch) @@ -993,7 +1017,7 @@ def machine_type_update(module, request, response): auth.post( ''.join([ "https://www.googleapis.com/compute/v1/", - "projdcts/{project}/zones/{zone}/instances/{name}/setMachineType" + "projects/{project}/zones/{zone}/instances/{name}/setMachineType" ]).format(**module.params), { u'machineType': machine_type_selflink(module.params.get('machine_type'), module.params) @@ -1020,12 +1044,13 @@ def resource_to_request(module): u'networkInterfaces': InstanceNetworkinterfacesArray(module.params.get('network_interfaces', []), module).to_request(), u'scheduling': InstanceScheduling(module.params.get('scheduling', {}), module).to_request(), u'serviceAccounts': InstanceServiceaccountsArray(module.params.get('service_accounts', []), module).to_request(), + u'status': module.params.get('status'), u'tags': InstanceTags(module.params.get('tags', {}), module).to_request() } request = encode_request(request, module) return_vals = {} for k, v in request.items(): - if v: + if v or v is False: return_vals[k] = v return return_vals @@ -1214,6 +1239,38 @@ def metadata_decoder(metadata): return items +class InstancePower(object): + def __init__(self, module, current_status): + self.module = module + self.current_status = current_status + self.desired_status = self.module.params.get('status') + + def run(self): + # GcpRequest handles unicode text handling + if GcpRequest({'status': self.current_status}) == GcpRequest({'status': self.desired_status}): + return + elif self.desired_status == 'RUNNING': + self.start() + elif self.desired_status == 'TERMINATED': + self.stop() + elif self.desired_status == 'SUSPENDED': + self.module.fail_json(msg="Instances cannot be suspended using Ansible") + + def start(self): + auth = GcpSession(self.module, 'compute') + wait_for_operation(self.module, auth.post(self._start_url())) + + def stop(self): + auth = GcpSession(self.module, 'compute') + wait_for_operation(self.module, auth.post(self._stop_url())) + + def _start_url(self): + return "https://www.googleapis.com/compute/v1/projects/{project}/zones/{zone}/instances/{name}/start".format(**self.module.params) + + def _stop_url(self): + return "https://www.googleapis.com/compute/v1/projects/{project}/zones/{zone}/instances/{name}/stop".format(**self.module.params) + + class InstanceDisksArray(object): def __init__(self, request, module): self.module = module diff --git a/lib/ansible/modules/cloud/google/gcp_compute_instance_facts.py b/lib/ansible/modules/cloud/google/gcp_compute_instance_facts.py index 6c029571a80..9b6002698ca 100644 --- a/lib/ansible/modules/cloud/google/gcp_compute_instance_facts.py +++ b/lib/ansible/modules/cloud/google/gcp_compute_instance_facts.py @@ -432,6 +432,8 @@ items: description: - 'The status of the instance. One of the following values: PROVISIONING, STAGING, RUNNING, STOPPING, SUSPENDING, SUSPENDED, and TERMINATED.' + - As a user, use RUNNING to keep a machine "on" and TERMINATED to turn a machine + off . returned: success type: str statusMessage: diff --git a/lib/ansible/modules/cloud/google/gcp_compute_instance_group.py b/lib/ansible/modules/cloud/google/gcp_compute_instance_group.py index 63da353dcc0..fb10003a3dd 100644 --- a/lib/ansible/modules/cloud/google/gcp_compute_instance_group.py +++ b/lib/ansible/modules/cloud/google/gcp_compute_instance_group.py @@ -314,7 +314,7 @@ def resource_to_request(module): } return_vals = {} for k, v in request.items(): - if v: + if v or v is False: return_vals[k] = v return return_vals diff --git a/lib/ansible/modules/cloud/google/gcp_compute_instance_group_manager.py b/lib/ansible/modules/cloud/google/gcp_compute_instance_group_manager.py index a84d86aac75..d2b05b93dc5 100644 --- a/lib/ansible/modules/cloud/google/gcp_compute_instance_group_manager.py +++ b/lib/ansible/modules/cloud/google/gcp_compute_instance_group_manager.py @@ -411,7 +411,7 @@ def resource_to_request(module): } return_vals = {} for k, v in request.items(): - if v: + if v or v is False: return_vals[k] = v return return_vals diff --git a/lib/ansible/modules/cloud/google/gcp_compute_instance_template.py b/lib/ansible/modules/cloud/google/gcp_compute_instance_template.py index 2a7ac854fcf..e4ed9770dd7 100644 --- a/lib/ansible/modules/cloud/google/gcp_compute_instance_template.py +++ b/lib/ansible/modules/cloud/google/gcp_compute_instance_template.py @@ -991,7 +991,7 @@ def resource_to_request(module): request = encode_request(request, module) return_vals = {} for k, v in request.items(): - if v: + if v or v is False: return_vals[k] = v return return_vals diff --git a/lib/ansible/modules/cloud/google/gcp_compute_network.py b/lib/ansible/modules/cloud/google/gcp_compute_network.py index ba5407e43a6..e48b798b80d 100644 --- a/lib/ansible/modules/cloud/google/gcp_compute_network.py +++ b/lib/ansible/modules/cloud/google/gcp_compute_network.py @@ -216,10 +216,11 @@ def main(): ipv4_range=dict(type='str'), name=dict(required=True, type='str'), auto_create_subnetworks=dict(type='bool'), - routing_config=dict(type='list', elements='dict', options=dict( + routing_config=dict(type='dict', options=dict( routing_mode=dict(required=True, type='str', choices=['REGIONAL', 'GLOBAL']) )) - ) + ), + mutually_exclusive=[['auto_create_subnetworks', 'ipv4_range']] ) if not module.params['scopes']: @@ -234,7 +235,7 @@ def main(): if fetch: if state == 'present': if is_different(module, fetch): - update(module, self_link(module), kind, fetch) + update(module, self_link(module), kind) fetch = fetch_resource(module, self_link(module), kind) changed = True else: @@ -258,31 +259,11 @@ def create(module, link, kind): return wait_for_operation(module, auth.post(link, resource_to_request(module))) -def update(module, link, kind, fetch): - update_fields(module, resource_to_request(module), - response_to_hash(module, fetch)) +def update(module, link, kind): auth = GcpSession(module, 'compute') return wait_for_operation(module, auth.patch(link, resource_to_request(module))) -def update_fields(module, request, response): - if response.get('routingConfig') != request.get('routingConfig'): - routing_config_update(module, request, response) - - -def routing_config_update(module, request, response): - auth = GcpSession(module, 'compute') - auth.patch( - ''.join([ - "https://www.googleapis.com/compute/v1/", - "projects/{project}/regions/{region}/subnetworks/{name}" - ]).format(**module.params), - { - u'routingConfig': NetworkRoutingconfigArray(module.params.get('routing_config', []), module).to_request() - } - ) - - def delete(module, link, kind): auth = GcpSession(module, 'compute') return wait_for_operation(module, auth.delete(link)) @@ -295,11 +276,11 @@ def resource_to_request(module): u'IPv4Range': module.params.get('ipv4_range'), u'name': module.params.get('name'), u'autoCreateSubnetworks': module.params.get('auto_create_subnetworks'), - u'routingConfig': NetworkRoutingconfigArray(module.params.get('routing_config', []), module).to_request() + u'routingConfig': NetworkRoutingconfig(module.params.get('routing_config', {}), module).to_request() } return_vals = {} for k, v in request.items(): - if v: + if v or v is False: return_vals[k] = v return return_vals @@ -369,7 +350,7 @@ def response_to_hash(module, response): u'subnetworks': response.get(u'subnetworks'), u'autoCreateSubnetworks': module.params.get('auto_create_subnetworks'), u'creationTimestamp': response.get(u'creationTimestamp'), - u'routingConfig': NetworkRoutingconfigArray(response.get(u'routingConfig', []), module).from_response() + u'routingConfig': NetworkRoutingconfig(response.get(u'routingConfig', {}), module).from_response() } @@ -408,34 +389,22 @@ def raise_if_errors(response, err_path, module): module.fail_json(msg=errors) -class NetworkRoutingconfigArray(object): +class NetworkRoutingconfig(object): def __init__(self, request, module): self.module = module if request: self.request = request else: - self.request = [] + self.request = {} def to_request(self): - items = [] - for item in self.request: - items.append(self._request_for_item(item)) - return items - - def from_response(self): - items = [] - for item in self.request: - items.append(self._response_from_item(item)) - return items - - def _request_for_item(self, item): return remove_nones_from_dict({ - u'routingMode': item.get('routing_mode') + u'routingMode': self.request.get('routing_mode') }) - def _response_from_item(self, item): + def from_response(self): return remove_nones_from_dict({ - u'routingMode': item.get(u'routingMode') + u'routingMode': self.request.get(u'routingMode') }) diff --git a/lib/ansible/modules/cloud/google/gcp_compute_region_disk.py b/lib/ansible/modules/cloud/google/gcp_compute_region_disk.py index d13b3f73913..900d638e261 100644 --- a/lib/ansible/modules/cloud/google/gcp_compute_region_disk.py +++ b/lib/ansible/modules/cloud/google/gcp_compute_region_disk.py @@ -455,7 +455,7 @@ def resource_to_request(module): } return_vals = {} for k, v in request.items(): - if v: + if v or v is False: return_vals[k] = v return return_vals diff --git a/lib/ansible/modules/cloud/google/gcp_compute_route.py b/lib/ansible/modules/cloud/google/gcp_compute_route.py index 546b0dfd35e..703bd66ccc8 100644 --- a/lib/ansible/modules/cloud/google/gcp_compute_route.py +++ b/lib/ansible/modules/cloud/google/gcp_compute_route.py @@ -327,7 +327,7 @@ def resource_to_request(module): } return_vals = {} for k, v in request.items(): - if v: + if v or v is False: return_vals[k] = v return return_vals diff --git a/lib/ansible/modules/cloud/google/gcp_compute_router.py b/lib/ansible/modules/cloud/google/gcp_compute_router.py index be8bf03f37e..460371fb527 100644 --- a/lib/ansible/modules/cloud/google/gcp_compute_router.py +++ b/lib/ansible/modules/cloud/google/gcp_compute_router.py @@ -331,7 +331,7 @@ def resource_to_request(module): } return_vals = {} for k, v in request.items(): - if v: + if v or v is False: return_vals[k] = v return return_vals diff --git a/lib/ansible/modules/cloud/google/gcp_compute_ssl_certificate.py b/lib/ansible/modules/cloud/google/gcp_compute_ssl_certificate.py index 1626e85c4de..f5faf874c24 100644 --- a/lib/ansible/modules/cloud/google/gcp_compute_ssl_certificate.py +++ b/lib/ansible/modules/cloud/google/gcp_compute_ssl_certificate.py @@ -235,7 +235,7 @@ def resource_to_request(module): } return_vals = {} for k, v in request.items(): - if v: + if v or v is False: return_vals[k] = v return return_vals diff --git a/lib/ansible/modules/cloud/google/gcp_compute_ssl_policy.py b/lib/ansible/modules/cloud/google/gcp_compute_ssl_policy.py index d1336036856..6425b0564b5 100644 --- a/lib/ansible/modules/cloud/google/gcp_compute_ssl_policy.py +++ b/lib/ansible/modules/cloud/google/gcp_compute_ssl_policy.py @@ -273,7 +273,7 @@ def resource_to_request(module): } return_vals = {} for k, v in request.items(): - if v: + if v or v is False: return_vals[k] = v return return_vals diff --git a/lib/ansible/modules/cloud/google/gcp_compute_subnetwork.py b/lib/ansible/modules/cloud/google/gcp_compute_subnetwork.py index d8e29465951..b56c5b69b91 100644 --- a/lib/ansible/modules/cloud/google/gcp_compute_subnetwork.py +++ b/lib/ansible/modules/cloud/google/gcp_compute_subnetwork.py @@ -400,7 +400,7 @@ def resource_to_request(module): } return_vals = {} for k, v in request.items(): - if v: + if v or v is False: return_vals[k] = v return return_vals diff --git a/lib/ansible/modules/cloud/google/gcp_compute_target_http_proxy.py b/lib/ansible/modules/cloud/google/gcp_compute_target_http_proxy.py index 5fc0ec61a22..5dcd1864506 100644 --- a/lib/ansible/modules/cloud/google/gcp_compute_target_http_proxy.py +++ b/lib/ansible/modules/cloud/google/gcp_compute_target_http_proxy.py @@ -268,7 +268,7 @@ def resource_to_request(module): } return_vals = {} for k, v in request.items(): - if v: + if v or v is False: return_vals[k] = v return return_vals diff --git a/lib/ansible/modules/cloud/google/gcp_compute_target_https_proxy.py b/lib/ansible/modules/cloud/google/gcp_compute_target_https_proxy.py index d2e2eed5a64..87bba07fd7d 100644 --- a/lib/ansible/modules/cloud/google/gcp_compute_target_https_proxy.py +++ b/lib/ansible/modules/cloud/google/gcp_compute_target_https_proxy.py @@ -372,7 +372,7 @@ def resource_to_request(module): } return_vals = {} for k, v in request.items(): - if v: + if v or v is False: return_vals[k] = v return return_vals diff --git a/lib/ansible/modules/cloud/google/gcp_compute_target_pool.py b/lib/ansible/modules/cloud/google/gcp_compute_target_pool.py index 012a2de9436..ddb94fccd25 100644 --- a/lib/ansible/modules/cloud/google/gcp_compute_target_pool.py +++ b/lib/ansible/modules/cloud/google/gcp_compute_target_pool.py @@ -322,7 +322,7 @@ def resource_to_request(module): request = encode_request(request, module) return_vals = {} for k, v in request.items(): - if v: + if v or v is False: return_vals[k] = v return return_vals diff --git a/lib/ansible/modules/cloud/google/gcp_compute_target_ssl_proxy.py b/lib/ansible/modules/cloud/google/gcp_compute_target_ssl_proxy.py index 2a59d7d0622..44c7e6d2fec 100644 --- a/lib/ansible/modules/cloud/google/gcp_compute_target_ssl_proxy.py +++ b/lib/ansible/modules/cloud/google/gcp_compute_target_ssl_proxy.py @@ -357,7 +357,7 @@ def resource_to_request(module): } return_vals = {} for k, v in request.items(): - if v: + if v or v is False: return_vals[k] = v return return_vals diff --git a/lib/ansible/modules/cloud/google/gcp_compute_target_tcp_proxy.py b/lib/ansible/modules/cloud/google/gcp_compute_target_tcp_proxy.py index d3146293999..41dcf2a5dde 100644 --- a/lib/ansible/modules/cloud/google/gcp_compute_target_tcp_proxy.py +++ b/lib/ansible/modules/cloud/google/gcp_compute_target_tcp_proxy.py @@ -293,7 +293,7 @@ def resource_to_request(module): } return_vals = {} for k, v in request.items(): - if v: + if v or v is False: return_vals[k] = v return return_vals diff --git a/lib/ansible/modules/cloud/google/gcp_compute_target_vpn_gateway.py b/lib/ansible/modules/cloud/google/gcp_compute_target_vpn_gateway.py index d01d144acbb..68721994a15 100644 --- a/lib/ansible/modules/cloud/google/gcp_compute_target_vpn_gateway.py +++ b/lib/ansible/modules/cloud/google/gcp_compute_target_vpn_gateway.py @@ -239,7 +239,7 @@ def resource_to_request(module): } return_vals = {} for k, v in request.items(): - if v: + if v or v is False: return_vals[k] = v return return_vals diff --git a/lib/ansible/modules/cloud/google/gcp_compute_url_map.py b/lib/ansible/modules/cloud/google/gcp_compute_url_map.py index 25a549cc0ab..fb557206db0 100644 --- a/lib/ansible/modules/cloud/google/gcp_compute_url_map.py +++ b/lib/ansible/modules/cloud/google/gcp_compute_url_map.py @@ -455,7 +455,7 @@ def resource_to_request(module): } return_vals = {} for k, v in request.items(): - if v: + if v or v is False: return_vals[k] = v return return_vals diff --git a/lib/ansible/modules/cloud/google/gcp_compute_vpn_tunnel.py b/lib/ansible/modules/cloud/google/gcp_compute_vpn_tunnel.py index b5ae722db11..53cf6505ca0 100644 --- a/lib/ansible/modules/cloud/google/gcp_compute_vpn_tunnel.py +++ b/lib/ansible/modules/cloud/google/gcp_compute_vpn_tunnel.py @@ -377,7 +377,7 @@ def resource_to_request(module): } return_vals = {} for k, v in request.items(): - if v: + if v or v is False: return_vals[k] = v return return_vals diff --git a/lib/ansible/modules/cloud/google/gcp_container_cluster.py b/lib/ansible/modules/cloud/google/gcp_container_cluster.py index 5555ea5880e..4e71d4363e3 100644 --- a/lib/ansible/modules/cloud/google/gcp_container_cluster.py +++ b/lib/ansible/modules/cloud/google/gcp_container_cluster.py @@ -701,7 +701,7 @@ def resource_to_request(module): request = encode_request(request, module) return_vals = {} for k, v in request.items(): - if v: + if v or v is False: return_vals[k] = v return return_vals diff --git a/lib/ansible/modules/cloud/google/gcp_container_node_pool.py b/lib/ansible/modules/cloud/google/gcp_container_node_pool.py index d3196ff18ae..adaac831d57 100644 --- a/lib/ansible/modules/cloud/google/gcp_container_node_pool.py +++ b/lib/ansible/modules/cloud/google/gcp_container_node_pool.py @@ -531,7 +531,7 @@ def resource_to_request(module): request = encode_request(request, module) return_vals = {} for k, v in request.items(): - if v: + if v or v is False: return_vals[k] = v return return_vals diff --git a/lib/ansible/modules/cloud/google/gcp_dns_managed_zone.py b/lib/ansible/modules/cloud/google/gcp_dns_managed_zone.py index 6a8ed21bf35..841a07c19cd 100644 --- a/lib/ansible/modules/cloud/google/gcp_dns_managed_zone.py +++ b/lib/ansible/modules/cloud/google/gcp_dns_managed_zone.py @@ -53,11 +53,11 @@ options: description: - A mutable string of at most 1024 characters associated with this resource for the user's convenience. Has no effect on the managed zone's function. - required: false + required: true dns_name: description: - The DNS name of this managed zone, for instance "example.com.". - required: false + required: true name: description: - User assigned name for this resource. @@ -69,7 +69,15 @@ options: is a set of DNS name servers that all host the same ManagedZones. Most users will leave this field unset. required: false + labels: + description: + - A set of key/value label pairs to assign to this ManagedZone. + required: false + version_added: 2.8 extends_documentation_fragment: gcp +notes: +- 'API Reference: U(https://cloud.google.com/dns/api/v1/managedZones)' +- 'Managing Zones: U(https://cloud.google.com/dns/zones/)' ''' EXAMPLES = ''' @@ -126,6 +134,11 @@ creationTime: - This is in RFC3339 text format. returned: success type: str +labels: + description: + - A set of key/value label pairs to assign to this ManagedZone. + returned: success + type: dict ''' ################################################################################ @@ -146,10 +159,11 @@ def main(): module = GcpModule( argument_spec=dict( state=dict(default='present', choices=['present', 'absent'], type='str'), - description=dict(type='str'), - dns_name=dict(type='str'), + description=dict(required=True, type='str'), + dns_name=dict(required=True, type='str'), name=dict(required=True, type='str'), - name_server_set=dict(type='list', elements='str') + name_server_set=dict(type='list', elements='str'), + labels=dict(type='dict') ) ) @@ -165,7 +179,7 @@ def main(): if fetch: if state == 'present': if is_different(module, fetch): - update(module, self_link(module), kind) + update(module, self_link(module), kind, fetch) fetch = fetch_resource(module, self_link(module), kind) changed = True else: @@ -189,8 +203,29 @@ def create(module, link, kind): return return_if_object(module, auth.post(link, resource_to_request(module)), kind) -def update(module, link, kind): - module.fail_json(msg="ManagedZone cannot be edited") +def update(module, link, kind, fetch): + update_fields(module, resource_to_request(module), + response_to_hash(module, fetch)) + return fetch_resource(module, self_link(module), kind) + + +def update_fields(module, request, response): + if response.get('description') != request.get('description') or response.get('labels') != request.get('labels'): + description_update(module, request, response) + + +def description_update(module, request, response): + auth = GcpSession(module, 'dns') + auth.patch( + ''.join([ + "https://www.googleapis.com/dns/v1/", + "projects/{project}/managedZones/{name}" + ]).format(**module.params), + { + u'description': module.params.get('description'), + u'labels': module.params.get('labels') + } + ) def delete(module, link, kind): @@ -204,11 +239,12 @@ def resource_to_request(module): u'description': module.params.get('description'), u'dnsName': module.params.get('dns_name'), u'name': module.params.get('name'), - u'nameServerSet': module.params.get('name_server_set') + u'nameServerSet': module.params.get('name_server_set'), + u'labels': module.params.get('labels') } return_vals = {} for k, v in request.items(): - if v: + if v or v is False: return_vals[k] = v return return_vals @@ -276,7 +312,8 @@ def response_to_hash(module, response): u'name': response.get(u'name'), u'nameServers': response.get(u'nameServers'), u'nameServerSet': response.get(u'nameServerSet'), - u'creationTime': response.get(u'creationTime') + u'creationTime': response.get(u'creationTime'), + u'labels': response.get(u'labels') } diff --git a/lib/ansible/modules/cloud/google/gcp_dns_managed_zone_facts.py b/lib/ansible/modules/cloud/google/gcp_dns_managed_zone_facts.py index 6a7e8205f11..164f0245e0b 100644 --- a/lib/ansible/modules/cloud/google/gcp_dns_managed_zone_facts.py +++ b/lib/ansible/modules/cloud/google/gcp_dns_managed_zone_facts.py @@ -103,6 +103,11 @@ items: - This is in RFC3339 text format. returned: success type: str + labels: + description: + - A set of key/value label pairs to assign to this ManagedZone. + returned: success + type: dict ''' ################################################################################ diff --git a/lib/ansible/modules/cloud/google/gcp_dns_resource_record_set.py b/lib/ansible/modules/cloud/google/gcp_dns_resource_record_set.py index 936bbd361d0..fd933ed6aae 100644 --- a/lib/ansible/modules/cloud/google/gcp_dns_resource_record_set.py +++ b/lib/ansible/modules/cloud/google/gcp_dns_resource_record_set.py @@ -252,7 +252,7 @@ def resource_to_request(module): } return_vals = {} for k, v in request.items(): - if v: + if v or v is False: return_vals[k] = v return return_vals diff --git a/lib/ansible/modules/cloud/google/gcp_pubsub_subscription.py b/lib/ansible/modules/cloud/google/gcp_pubsub_subscription.py index dea237fef1f..fd9fbd221de 100644 --- a/lib/ansible/modules/cloud/google/gcp_pubsub_subscription.py +++ b/lib/ansible/modules/cloud/google/gcp_pubsub_subscription.py @@ -243,7 +243,7 @@ def resource_to_request(module): request = encode_request(request, module) return_vals = {} for k, v in request.items(): - if v: + if v or v is False: return_vals[k] = v return return_vals diff --git a/lib/ansible/modules/cloud/google/gcp_pubsub_topic.py b/lib/ansible/modules/cloud/google/gcp_pubsub_topic.py index a5d6027cbfd..c70e22edb50 100644 --- a/lib/ansible/modules/cloud/google/gcp_pubsub_topic.py +++ b/lib/ansible/modules/cloud/google/gcp_pubsub_topic.py @@ -147,7 +147,7 @@ def resource_to_request(module): request = encode_request(request, module) return_vals = {} for k, v in request.items(): - if v: + if v or v is False: return_vals[k] = v return return_vals diff --git a/lib/ansible/modules/cloud/google/gcp_spanner_database.py b/lib/ansible/modules/cloud/google/gcp_spanner_database.py index f3f84f411d2..00bf487c43c 100644 --- a/lib/ansible/modules/cloud/google/gcp_spanner_database.py +++ b/lib/ansible/modules/cloud/google/gcp_spanner_database.py @@ -198,7 +198,7 @@ def resource_to_request(module): request = encode_request(request, module) return_vals = {} for k, v in request.items(): - if v: + if v or v is False: return_vals[k] = v return return_vals diff --git a/lib/ansible/modules/cloud/google/gcp_spanner_instance.py b/lib/ansible/modules/cloud/google/gcp_spanner_instance.py index 1d4fe334d78..4aa2fbb0149 100644 --- a/lib/ansible/modules/cloud/google/gcp_spanner_instance.py +++ b/lib/ansible/modules/cloud/google/gcp_spanner_instance.py @@ -235,7 +235,7 @@ def resource_to_request(module): } return_vals = {} for k, v in request.items(): - if v: + if v or v is False: return_vals[k] = v return return_vals diff --git a/lib/ansible/modules/cloud/google/gcp_sql_database.py b/lib/ansible/modules/cloud/google/gcp_sql_database.py index e1d0832edc7..e0d110632ce 100644 --- a/lib/ansible/modules/cloud/google/gcp_sql_database.py +++ b/lib/ansible/modules/cloud/google/gcp_sql_database.py @@ -206,7 +206,7 @@ def resource_to_request(module): } return_vals = {} for k, v in request.items(): - if v: + if v or v is False: return_vals[k] = v return return_vals diff --git a/lib/ansible/modules/cloud/google/gcp_sql_instance.py b/lib/ansible/modules/cloud/google/gcp_sql_instance.py index 2a9938f3a35..161aa889762 100644 --- a/lib/ansible/modules/cloud/google/gcp_sql_instance.py +++ b/lib/ansible/modules/cloud/google/gcp_sql_instance.py @@ -678,7 +678,7 @@ def resource_to_request(module): } return_vals = {} for k, v in request.items(): - if v: + if v or v is False: return_vals[k] = v return return_vals diff --git a/lib/ansible/modules/cloud/google/gcp_sql_user.py b/lib/ansible/modules/cloud/google/gcp_sql_user.py index 566352420f2..4e6f2c5c85c 100644 --- a/lib/ansible/modules/cloud/google/gcp_sql_user.py +++ b/lib/ansible/modules/cloud/google/gcp_sql_user.py @@ -211,7 +211,7 @@ def resource_to_request(module): } return_vals = {} for k, v in request.items(): - if v: + if v or v is False: return_vals[k] = v return return_vals diff --git a/lib/ansible/modules/cloud/google/gcp_storage_bucket.py b/lib/ansible/modules/cloud/google/gcp_storage_bucket.py index f26361ef9a6..3c00e92ad11 100644 --- a/lib/ansible/modules/cloud/google/gcp_storage_bucket.py +++ b/lib/ansible/modules/cloud/google/gcp_storage_bucket.py @@ -936,7 +936,7 @@ def resource_to_request(module): } return_vals = {} for k, v in request.items(): - if v: + if v or v is False: return_vals[k] = v return return_vals 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 d075f43d175..09e141f4bc0 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 @@ -273,7 +273,7 @@ def resource_to_request(module): } return_vals = {} for k, v in request.items(): - if v: + if v or v is False: return_vals[k] = v return return_vals