Ryan Brown 6 years ago committed by GitHub
parent 3b5471a734
commit 18a088c64e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -81,11 +81,24 @@ options:
letter, and all following characters must be a dash, lowercase letter, or digit, letter, and all following characters must be a dash, lowercase letter, or digit,
except the last character, which cannot be a dash. except the last character, which cannot be a dash.
required: true required: true
network_tier:
description:
- 'The networking tier used for configuring this address. This field can take the
following values: PREMIUM or STANDARD. If this field is not specified, it is assumed
to be PREMIUM.'
required: false
version_added: 2.8
choices: ['PREMIUM', 'STANDARD']
subnetwork: subnetwork:
description: description:
- The URL of the subnetwork in which to reserve the address. If an IP address is specified, - The URL of the subnetwork in which to reserve the address. If an IP address is specified,
it must be within the subnetwork's IP range. it must be within the subnetwork's IP range.
- This field can only be used with INTERNAL type with GCE_ENDPOINT/DNS_RESOLVER purposes. - This field can only be used with INTERNAL type with GCE_ENDPOINT/DNS_RESOLVER purposes.
- 'This field represents a link to a Subnetwork resource in GCP. It can be specified
in two ways. You can add `register: name-of-resource` to a gcp_compute_subnetwork
task and then set this subnetwork field to "{{ name-of-resource }}" Alternatively,
you can set this subnetwork to a dictionary with the selfLink key where the value
is the selfLink of your Subnetwork.'
required: false required: false
version_added: 2.7 version_added: 2.7
region: region:
@ -106,7 +119,7 @@ EXAMPLES = '''
name: test-address1 name: test-address1
region: us-west1 region: us-west1
project: "test_project" project: "test_project"
auth_kind: "service_account" auth_kind: "serviceaccount"
service_account_file: "/tmp/auth.pem" service_account_file: "/tmp/auth.pem"
state: present state: present
''' '''
@ -119,13 +132,13 @@ RETURN = '''
be inside the specified subnetwork, if any. be inside the specified subnetwork, if any.
returned: success returned: success
type: str type: str
address_type: addressType:
description: description:
- The type of address to reserve, either INTERNAL or EXTERNAL. - The type of address to reserve, either INTERNAL or EXTERNAL.
- If unspecified, defaults to EXTERNAL. - If unspecified, defaults to EXTERNAL.
returned: success returned: success
type: str type: str
creation_timestamp: creationTimestamp:
description: description:
- Creation timestamp in RFC3339 text format. - Creation timestamp in RFC3339 text format.
returned: success returned: success
@ -149,6 +162,13 @@ RETURN = '''
except the last character, which cannot be a dash. except the last character, which cannot be a dash.
returned: success returned: success
type: str type: str
networkTier:
description:
- 'The networking tier used for configuring this address. This field can take the
following values: PREMIUM or STANDARD. If this field is not specified, it is assumed
to be PREMIUM.'
returned: success
type: str
subnetwork: subnetwork:
description: description:
- The URL of the subnetwork in which to reserve the address. If an IP address is specified, - The URL of the subnetwork in which to reserve the address. If an IP address is specified,
@ -192,6 +212,7 @@ def main():
address_type=dict(default='EXTERNAL', type='str', choices=['INTERNAL', 'EXTERNAL']), address_type=dict(default='EXTERNAL', type='str', choices=['INTERNAL', 'EXTERNAL']),
description=dict(type='str'), description=dict(type='str'),
name=dict(required=True, type='str'), name=dict(required=True, type='str'),
network_tier=dict(type='str', choices=['PREMIUM', 'STANDARD']),
subnetwork=dict(type='dict'), subnetwork=dict(type='dict'),
region=dict(required=True, type='str') region=dict(required=True, type='str')
) )
@ -209,7 +230,8 @@ def main():
if fetch: if fetch:
if state == 'present': if state == 'present':
if is_different(module, fetch): if is_different(module, fetch):
fetch = update(module, self_link(module), kind) update(module, self_link(module), kind)
fetch = fetch_resource(module, self_link(module), kind)
changed = True changed = True
else: else:
delete(module, self_link(module), kind) delete(module, self_link(module), kind)
@ -233,8 +255,7 @@ def create(module, link, kind):
def update(module, link, kind): def update(module, link, kind):
auth = GcpSession(module, 'compute') module.fail_json(msg="Address cannot be edited")
return wait_for_operation(module, auth.put(link, resource_to_request(module)))
def delete(module, link, kind): def delete(module, link, kind):
@ -249,6 +270,7 @@ def resource_to_request(module):
u'addressType': module.params.get('address_type'), u'addressType': module.params.get('address_type'),
u'description': module.params.get('description'), u'description': module.params.get('description'),
u'name': module.params.get('name'), u'name': module.params.get('name'),
u'networkTier': module.params.get('network_tier'),
u'subnetwork': replace_resource_dict(module.params.get(u'subnetwork', {}), 'selfLink') u'subnetwork': replace_resource_dict(module.params.get(u'subnetwork', {}), 'selfLink')
} }
return_vals = {} return_vals = {}
@ -259,9 +281,9 @@ def resource_to_request(module):
return return_vals return return_vals
def fetch_resource(module, link, kind): def fetch_resource(module, link, kind, allow_not_found=True):
auth = GcpSession(module, 'compute') auth = GcpSession(module, 'compute')
return return_if_object(module, auth.get(link), kind) return return_if_object(module, auth.get(link), kind, allow_not_found)
def self_link(module): def self_link(module):
@ -272,9 +294,9 @@ def collection(module):
return "https://www.googleapis.com/compute/v1/projects/{project}/regions/{region}/addresses".format(**module.params) return "https://www.googleapis.com/compute/v1/projects/{project}/regions/{region}/addresses".format(**module.params)
def return_if_object(module, response, kind): def return_if_object(module, response, kind, allow_not_found=False):
# If not found, return nothing. # If not found, return nothing.
if response.status_code == 404: if allow_not_found and response.status_code == 404:
return None return None
# If no content, return nothing. # If no content, return nothing.
@ -289,8 +311,6 @@ def return_if_object(module, response, kind):
if navigate_hash(result, ['error', 'errors']): if navigate_hash(result, ['error', 'errors']):
module.fail_json(msg=navigate_hash(result, ['error', 'errors'])) module.fail_json(msg=navigate_hash(result, ['error', 'errors']))
if result['kind'] != kind:
module.fail_json(msg="Incorrect result: {kind}".format(**result))
return result return result
@ -323,6 +343,7 @@ def response_to_hash(module, response):
u'description': response.get(u'description'), u'description': response.get(u'description'),
u'id': response.get(u'id'), u'id': response.get(u'id'),
u'name': response.get(u'name'), u'name': response.get(u'name'),
u'networkTier': response.get(u'networkTier'),
u'subnetwork': response.get(u'subnetwork'), u'subnetwork': response.get(u'subnetwork'),
u'users': response.get(u'users') u'users': response.get(u'users')
} }

@ -62,7 +62,7 @@ EXAMPLES = '''
filters: filters:
- name = test_object - name = test_object
project: test_project project: test_project
auth_kind: service_account auth_kind: serviceaccount
service_account_file: "/tmp/auth.pem" service_account_file: "/tmp/auth.pem"
''' '''
@ -79,13 +79,13 @@ items:
be inside the specified subnetwork, if any. be inside the specified subnetwork, if any.
returned: success returned: success
type: str type: str
address_type: addressType:
description: description:
- The type of address to reserve, either INTERNAL or EXTERNAL. - The type of address to reserve, either INTERNAL or EXTERNAL.
- If unspecified, defaults to EXTERNAL. - If unspecified, defaults to EXTERNAL.
returned: success returned: success
type: str type: str
creation_timestamp: creationTimestamp:
description: description:
- Creation timestamp in RFC3339 text format. - Creation timestamp in RFC3339 text format.
returned: success returned: success
@ -109,6 +109,13 @@ items:
except the last character, which cannot be a dash. except the last character, which cannot be a dash.
returned: success returned: success
type: str type: str
networkTier:
description:
- 'The networking tier used for configuring this address. This field can take the
following values: PREMIUM or STANDARD. If this field is not specified, it is assumed
to be PREMIUM.'
returned: success
type: str
subnetwork: subnetwork:
description: description:
- The URL of the subnetwork in which to reserve the address. If an IP address is specified, - The URL of the subnetwork in which to reserve the address. If an IP address is specified,

@ -96,18 +96,18 @@ EXAMPLES = '''
description: A BackendBucket to connect LNB w/ Storage Bucket description: A BackendBucket to connect LNB w/ Storage Bucket
enable_cdn: true enable_cdn: true
project: "test_project" project: "test_project"
auth_kind: "service_account" auth_kind: "serviceaccount"
service_account_file: "/tmp/auth.pem" service_account_file: "/tmp/auth.pem"
state: present state: present
''' '''
RETURN = ''' RETURN = '''
bucket_name: bucketName:
description: description:
- Cloud Storage bucket name. - Cloud Storage bucket name.
returned: success returned: success
type: str type: str
creation_timestamp: creationTimestamp:
description: description:
- Creation timestamp in RFC3339 text format. - Creation timestamp in RFC3339 text format.
returned: success returned: success
@ -118,7 +118,7 @@ RETURN = '''
resource is created. resource is created.
returned: success returned: success
type: str type: str
enable_cdn: enableCdn:
description: description:
- If true, enable Cloud CDN for this BackendBucket. - If true, enable Cloud CDN for this BackendBucket.
returned: success returned: success
@ -178,7 +178,8 @@ def main():
if fetch: if fetch:
if state == 'present': if state == 'present':
if is_different(module, fetch): if is_different(module, fetch):
fetch = update(module, self_link(module), kind) update(module, self_link(module), kind)
fetch = fetch_resource(module, self_link(module), kind)
changed = True changed = True
else: else:
delete(module, self_link(module), kind) delete(module, self_link(module), kind)
@ -227,9 +228,9 @@ def resource_to_request(module):
return return_vals return return_vals
def fetch_resource(module, link, kind): def fetch_resource(module, link, kind, allow_not_found=True):
auth = GcpSession(module, 'compute') auth = GcpSession(module, 'compute')
return return_if_object(module, auth.get(link), kind) return return_if_object(module, auth.get(link), kind, allow_not_found)
def self_link(module): def self_link(module):
@ -240,9 +241,9 @@ def collection(module):
return "https://www.googleapis.com/compute/v1/projects/{project}/global/backendBuckets".format(**module.params) return "https://www.googleapis.com/compute/v1/projects/{project}/global/backendBuckets".format(**module.params)
def return_if_object(module, response, kind): def return_if_object(module, response, kind, allow_not_found=False):
# If not found, return nothing. # If not found, return nothing.
if response.status_code == 404: if allow_not_found and response.status_code == 404:
return None return None
# If no content, return nothing. # If no content, return nothing.
@ -257,8 +258,6 @@ def return_if_object(module, response, kind):
if navigate_hash(result, ['error', 'errors']): if navigate_hash(result, ['error', 'errors']):
module.fail_json(msg=navigate_hash(result, ['error', 'errors'])) module.fail_json(msg=navigate_hash(result, ['error', 'errors']))
if result['kind'] != kind:
module.fail_json(msg="Incorrect result: {kind}".format(**result))
return result return result

@ -56,7 +56,7 @@ EXAMPLES = '''
filters: filters:
- name = test_object - name = test_object
project: test_project project: test_project
auth_kind: service_account auth_kind: serviceaccount
service_account_file: "/tmp/auth.pem" service_account_file: "/tmp/auth.pem"
''' '''
@ -66,12 +66,12 @@ items:
returned: always returned: always
type: complex type: complex
contains: contains:
bucket_name: bucketName:
description: description:
- Cloud Storage bucket name. - Cloud Storage bucket name.
returned: success returned: success
type: str type: str
creation_timestamp: creationTimestamp:
description: description:
- Creation timestamp in RFC3339 text format. - Creation timestamp in RFC3339 text format.
returned: success returned: success
@ -82,7 +82,7 @@ items:
resource is created. resource is created.
returned: success returned: success
type: str type: str
enable_cdn: enableCdn:
description: description:
- If true, enable Cloud CDN for this BackendBucket. - If true, enable Cloud CDN for this BackendBucket.
returned: success returned: success
@ -118,7 +118,7 @@ import json
def main(): def main():
module = GcpModule( module = GcpModule(
argument_spec=dict( argument_spec=dict(
filters=dict(type='list', elements='str'), filters=dict(type='list', elements='str')
) )
) )

@ -89,6 +89,11 @@ options:
- No two backends in a backend service are allowed to use same Instance Group resource. - No two backends in a backend service are allowed to use same Instance Group resource.
- When the BackendService has load balancing scheme INTERNAL, the instance group must - When the BackendService has load balancing scheme INTERNAL, the instance group must
be in a zone within the same region as the BackendService. be in a zone within the same region as the BackendService.
- 'This field represents a link to a InstanceGroup resource in GCP. It can be specified
in two ways. You can add `register: name-of-resource` to a gcp_compute_instance_group
task and then set this group field to "{{ name-of-resource }}" Alternatively, you
can set this group to a dictionary with the selfLink key where the value is the
selfLink of your InstanceGroup.'
required: false required: false
max_connections: max_connections:
description: description:
@ -305,13 +310,13 @@ EXAMPLES = '''
- "{{ healthcheck.selfLink }}" - "{{ healthcheck.selfLink }}"
enable_cdn: true enable_cdn: true
project: "test_project" project: "test_project"
auth_kind: "service_account" auth_kind: "serviceaccount"
service_account_file: "/tmp/auth.pem" service_account_file: "/tmp/auth.pem"
state: present state: present
''' '''
RETURN = ''' RETURN = '''
affinity_cookie_ttl_sec: affinityCookieTtlSec:
description: description:
- Lifetime of cookies in seconds if session_affinity is GENERATED_COOKIE. If set to - Lifetime of cookies in seconds if session_affinity is GENERATED_COOKIE. If set to
0, the cookie is non-persistent and lasts only until the end of the browser session 0, the cookie is non-persistent and lasts only until the end of the browser session
@ -325,7 +330,7 @@ RETURN = '''
returned: success returned: success
type: complex type: complex
contains: contains:
balancing_mode: balancingMode:
description: description:
- Specifies the balancing mode for this backend. - Specifies the balancing mode for this backend.
- For global HTTP(S) or TCP/SSL load balancing, the default is UTILIZATION. Valid - For global HTTP(S) or TCP/SSL load balancing, the default is UTILIZATION. Valid
@ -333,7 +338,7 @@ RETURN = '''
- This cannot be used for internal load balancing. - This cannot be used for internal load balancing.
returned: success returned: success
type: str type: str
capacity_scaler: capacityScaler:
description: description:
- A multiplier applied to the group's maximum servicing capacity (based on UTILIZATION, - A multiplier applied to the group's maximum servicing capacity (based on UTILIZATION,
RATE or CONNECTION). RATE or CONNECTION).
@ -359,7 +364,7 @@ RETURN = '''
be in a zone within the same region as the BackendService. be in a zone within the same region as the BackendService.
returned: success returned: success
type: dict type: dict
max_connections: maxConnections:
description: description:
- The max number of simultaneous connections for the group. Can be used with either - The max number of simultaneous connections for the group. Can be used with either
CONNECTION or UTILIZATION balancing modes. CONNECTION or UTILIZATION balancing modes.
@ -368,7 +373,7 @@ RETURN = '''
- This cannot be used for internal load balancing. - This cannot be used for internal load balancing.
returned: success returned: success
type: int type: int
max_connections_per_instance: maxConnectionsPerInstance:
description: description:
- The max number of simultaneous connections that a single backend instance can handle. - The max number of simultaneous connections that a single backend instance can handle.
This is used to calculate the capacity of the group. Can be used in either CONNECTION This is used to calculate the capacity of the group. Can be used in either CONNECTION
@ -378,7 +383,7 @@ RETURN = '''
- This cannot be used for internal load balancing. - This cannot be used for internal load balancing.
returned: success returned: success
type: int type: int
max_rate: maxRate:
description: description:
- The max requests per second (RPS) of the group. - The max requests per second (RPS) of the group.
- Can be used with either RATE or UTILIZATION balancing modes, but required if RATE - Can be used with either RATE or UTILIZATION balancing modes, but required if RATE
@ -386,7 +391,7 @@ RETURN = '''
- This cannot be used for internal load balancing. - This cannot be used for internal load balancing.
returned: success returned: success
type: int type: int
max_rate_per_instance: maxRatePerInstance:
description: description:
- The max requests per second (RPS) that a single backend instance can handle. This - The max requests per second (RPS) that a single backend instance can handle. This
is used to calculate the capacity of the group. Can be used in either balancing is used to calculate the capacity of the group. Can be used in either balancing
@ -394,43 +399,43 @@ RETURN = '''
- This cannot be used for internal load balancing. - This cannot be used for internal load balancing.
returned: success returned: success
type: str type: str
max_utilization: maxUtilization:
description: description:
- Used when balancingMode is UTILIZATION. This ratio defines the CPU utilization target - Used when balancingMode is UTILIZATION. This ratio defines the CPU utilization target
for the group. The default is 0.8. Valid range is [0.0, 1.0]. for the group. The default is 0.8. Valid range is [0.0, 1.0].
- This cannot be used for internal load balancing. - This cannot be used for internal load balancing.
returned: success returned: success
type: str type: str
cdn_policy: cdnPolicy:
description: description:
- Cloud CDN configuration for this BackendService. - Cloud CDN configuration for this BackendService.
returned: success returned: success
type: complex type: complex
contains: contains:
cache_key_policy: cacheKeyPolicy:
description: description:
- The CacheKeyPolicy for this CdnPolicy. - The CacheKeyPolicy for this CdnPolicy.
returned: success returned: success
type: complex type: complex
contains: contains:
include_host: includeHost:
description: description:
- If true requests to different hosts will be cached separately. - If true requests to different hosts will be cached separately.
returned: success returned: success
type: bool type: bool
include_protocol: includeProtocol:
description: description:
- If true, http and https requests will be cached separately. - If true, http and https requests will be cached separately.
returned: success returned: success
type: bool type: bool
include_query_string: includeQueryString:
description: description:
- If true, include query string parameters in the cache key according to query_string_whitelist - If true, include query string parameters in the cache key according to query_string_whitelist
and query_string_blacklist. If neither is set, the entire query string will be included. and query_string_blacklist. If neither is set, the entire query string will be included.
- If false, the query string will be excluded from the cache key entirely. - If false, the query string will be excluded from the cache key entirely.
returned: success returned: success
type: bool type: bool
query_string_blacklist: queryStringBlacklist:
description: description:
- Names of query string parameters to exclude in cache keys. - Names of query string parameters to exclude in cache keys.
- All other parameters will be included. Either specify query_string_whitelist or - All other parameters will be included. Either specify query_string_whitelist or
@ -438,7 +443,7 @@ RETURN = '''
- "'&' and '=' will be percent encoded and not treated as delimiters." - "'&' and '=' will be percent encoded and not treated as delimiters."
returned: success returned: success
type: list type: list
query_string_whitelist: queryStringWhitelist:
description: description:
- Names of query string parameters to include in cache keys. - Names of query string parameters to include in cache keys.
- All other parameters will be excluded. Either specify query_string_whitelist or - All other parameters will be excluded. Either specify query_string_whitelist or
@ -446,19 +451,19 @@ RETURN = '''
- "'&' and '=' will be percent encoded and not treated as delimiters." - "'&' and '=' will be percent encoded and not treated as delimiters."
returned: success returned: success
type: list type: list
connection_draining: connectionDraining:
description: description:
- Settings for connection draining. - Settings for connection draining.
returned: success returned: success
type: complex type: complex
contains: contains:
draining_timeout_sec: drainingTimeoutSec:
description: description:
- Time for which instance will be drained (not accept new connections, but still work - Time for which instance will be drained (not accept new connections, but still work
to finish started). to finish started).
returned: success returned: success
type: int type: int
creation_timestamp: creationTimestamp:
description: description:
- Creation timestamp in RFC3339 text format. - Creation timestamp in RFC3339 text format.
returned: success returned: success
@ -468,13 +473,13 @@ RETURN = '''
- An optional description of this resource. - An optional description of this resource.
returned: success returned: success
type: str type: str
enable_cdn: enableCDN:
description: description:
- If true, enable Cloud CDN for this BackendService. - If true, enable Cloud CDN for this BackendService.
- When the load balancing scheme is INTERNAL, this field is not used. - When the load balancing scheme is INTERNAL, this field is not used.
returned: success returned: success
type: bool type: bool
health_checks: healthChecks:
description: description:
- The list of URLs to the HttpHealthCheck or HttpsHealthCheck resource for health - The list of URLs to the HttpHealthCheck or HttpsHealthCheck resource for health
checking this BackendService. Currently at most one health check can be specified, checking this BackendService. Currently at most one health check can be specified,
@ -498,22 +503,22 @@ RETURN = '''
- Enables IAP. - Enables IAP.
returned: success returned: success
type: bool type: bool
oauth2_client_id: oauth2ClientId:
description: description:
- OAuth2 Client ID for IAP. - OAuth2 Client ID for IAP.
returned: success returned: success
type: str type: str
oauth2_client_secret: oauth2ClientSecret:
description: description:
- OAuth2 Client Secret for IAP. - OAuth2 Client Secret for IAP.
returned: success returned: success
type: str type: str
oauth2_client_secret_sha256: oauth2ClientSecretSha256:
description: description:
- OAuth2 Client Secret SHA-256 for IAP. - OAuth2 Client Secret SHA-256 for IAP.
returned: success returned: success
type: str type: str
load_balancing_scheme: loadBalancingScheme:
description: description:
- Indicates whether the backend service will be used with internal or external load - Indicates whether the backend service will be used with internal or external load
balancing. A backend service created for one type of load balancing cannot be used balancing. A backend service created for one type of load balancing cannot be used
@ -530,7 +535,7 @@ RETURN = '''
be a dash. be a dash.
returned: success returned: success
type: str type: str
port_name: portName:
description: description:
- Name of backend port. The same name should appear in the instance groups referenced - Name of backend port. The same name should appear in the instance groups referenced
by this service. Required when the load balancing scheme is EXTERNAL. by this service. Required when the load balancing scheme is EXTERNAL.
@ -551,7 +556,7 @@ RETURN = '''
- This field is not applicable to global backend services. - This field is not applicable to global backend services.
returned: success returned: success
type: str type: str
session_affinity: sessionAffinity:
description: description:
- Type of session affinity to use. The default is NONE. - Type of session affinity to use. The default is NONE.
- When the load balancing scheme is EXTERNAL, can be NONE, CLIENT_IP, or GENERATED_COOKIE. - When the load balancing scheme is EXTERNAL, can be NONE, CLIENT_IP, or GENERATED_COOKIE.
@ -560,7 +565,7 @@ RETURN = '''
- When the protocol is UDP, this field is not used. - When the protocol is UDP, this field is not used.
returned: success returned: success
type: str type: str
timeout_sec: timeoutSec:
description: description:
- How many seconds to wait for the backend before considering it a failed request. - How many seconds to wait for the backend before considering it a failed request.
Default is 30 seconds. Valid range is [1, 86400]. Default is 30 seconds. Valid range is [1, 86400].
@ -643,7 +648,8 @@ def main():
if fetch: if fetch:
if state == 'present': if state == 'present':
if is_different(module, fetch): if is_different(module, fetch):
fetch = update(module, self_link(module), kind) update(module, self_link(module), kind)
fetch = fetch_resource(module, self_link(module), kind)
changed = True changed = True
else: else:
delete(module, self_link(module), kind) delete(module, self_link(module), kind)
@ -703,9 +709,9 @@ def resource_to_request(module):
return return_vals return return_vals
def fetch_resource(module, link, kind): def fetch_resource(module, link, kind, allow_not_found=True):
auth = GcpSession(module, 'compute') auth = GcpSession(module, 'compute')
return return_if_object(module, auth.get(link), kind) return return_if_object(module, auth.get(link), kind, allow_not_found)
def self_link(module): def self_link(module):
@ -716,9 +722,9 @@ def collection(module):
return "https://www.googleapis.com/compute/v1/projects/{project}/global/backendServices".format(**module.params) return "https://www.googleapis.com/compute/v1/projects/{project}/global/backendServices".format(**module.params)
def return_if_object(module, response, kind): def return_if_object(module, response, kind, allow_not_found=False):
# If not found, return nothing. # If not found, return nothing.
if response.status_code == 404: if allow_not_found and response.status_code == 404:
return None return None
# If no content, return nothing. # If no content, return nothing.

@ -56,7 +56,7 @@ EXAMPLES = '''
filters: filters:
- name = test_object - name = test_object
project: test_project project: test_project
auth_kind: service_account auth_kind: serviceaccount
service_account_file: "/tmp/auth.pem" service_account_file: "/tmp/auth.pem"
''' '''
@ -66,7 +66,7 @@ items:
returned: always returned: always
type: complex type: complex
contains: contains:
affinity_cookie_ttl_sec: affinityCookieTtlSec:
description: description:
- Lifetime of cookies in seconds if session_affinity is GENERATED_COOKIE. If set to - Lifetime of cookies in seconds if session_affinity is GENERATED_COOKIE. If set to
0, the cookie is non-persistent and lasts only until the end of the browser session 0, the cookie is non-persistent and lasts only until the end of the browser session
@ -80,7 +80,7 @@ items:
returned: success returned: success
type: complex type: complex
contains: contains:
balancing_mode: balancingMode:
description: description:
- Specifies the balancing mode for this backend. - Specifies the balancing mode for this backend.
- For global HTTP(S) or TCP/SSL load balancing, the default is UTILIZATION. Valid - For global HTTP(S) or TCP/SSL load balancing, the default is UTILIZATION. Valid
@ -88,7 +88,7 @@ items:
- This cannot be used for internal load balancing. - This cannot be used for internal load balancing.
returned: success returned: success
type: str type: str
capacity_scaler: capacityScaler:
description: description:
- A multiplier applied to the group's maximum servicing capacity (based on UTILIZATION, - A multiplier applied to the group's maximum servicing capacity (based on UTILIZATION,
RATE or CONNECTION). RATE or CONNECTION).
@ -114,7 +114,7 @@ items:
be in a zone within the same region as the BackendService. be in a zone within the same region as the BackendService.
returned: success returned: success
type: dict type: dict
max_connections: maxConnections:
description: description:
- The max number of simultaneous connections for the group. Can be used with either - The max number of simultaneous connections for the group. Can be used with either
CONNECTION or UTILIZATION balancing modes. CONNECTION or UTILIZATION balancing modes.
@ -123,7 +123,7 @@ items:
- This cannot be used for internal load balancing. - This cannot be used for internal load balancing.
returned: success returned: success
type: int type: int
max_connections_per_instance: maxConnectionsPerInstance:
description: description:
- The max number of simultaneous connections that a single backend instance can handle. - The max number of simultaneous connections that a single backend instance can handle.
This is used to calculate the capacity of the group. Can be used in either CONNECTION This is used to calculate the capacity of the group. Can be used in either CONNECTION
@ -133,7 +133,7 @@ items:
- This cannot be used for internal load balancing. - This cannot be used for internal load balancing.
returned: success returned: success
type: int type: int
max_rate: maxRate:
description: description:
- The max requests per second (RPS) of the group. - The max requests per second (RPS) of the group.
- Can be used with either RATE or UTILIZATION balancing modes, but required if RATE - Can be used with either RATE or UTILIZATION balancing modes, but required if RATE
@ -141,7 +141,7 @@ items:
- This cannot be used for internal load balancing. - This cannot be used for internal load balancing.
returned: success returned: success
type: int type: int
max_rate_per_instance: maxRatePerInstance:
description: description:
- The max requests per second (RPS) that a single backend instance can handle. This - The max requests per second (RPS) that a single backend instance can handle. This
is used to calculate the capacity of the group. Can be used in either balancing is used to calculate the capacity of the group. Can be used in either balancing
@ -149,43 +149,43 @@ items:
- This cannot be used for internal load balancing. - This cannot be used for internal load balancing.
returned: success returned: success
type: str type: str
max_utilization: maxUtilization:
description: description:
- Used when balancingMode is UTILIZATION. This ratio defines the CPU utilization target - Used when balancingMode is UTILIZATION. This ratio defines the CPU utilization target
for the group. The default is 0.8. Valid range is [0.0, 1.0]. for the group. The default is 0.8. Valid range is [0.0, 1.0].
- This cannot be used for internal load balancing. - This cannot be used for internal load balancing.
returned: success returned: success
type: str type: str
cdn_policy: cdnPolicy:
description: description:
- Cloud CDN configuration for this BackendService. - Cloud CDN configuration for this BackendService.
returned: success returned: success
type: complex type: complex
contains: contains:
cache_key_policy: cacheKeyPolicy:
description: description:
- The CacheKeyPolicy for this CdnPolicy. - The CacheKeyPolicy for this CdnPolicy.
returned: success returned: success
type: complex type: complex
contains: contains:
include_host: includeHost:
description: description:
- If true requests to different hosts will be cached separately. - If true requests to different hosts will be cached separately.
returned: success returned: success
type: bool type: bool
include_protocol: includeProtocol:
description: description:
- If true, http and https requests will be cached separately. - If true, http and https requests will be cached separately.
returned: success returned: success
type: bool type: bool
include_query_string: includeQueryString:
description: description:
- If true, include query string parameters in the cache key according to query_string_whitelist - If true, include query string parameters in the cache key according to query_string_whitelist
and query_string_blacklist. If neither is set, the entire query string will be included. and query_string_blacklist. If neither is set, the entire query string will be included.
- If false, the query string will be excluded from the cache key entirely. - If false, the query string will be excluded from the cache key entirely.
returned: success returned: success
type: bool type: bool
query_string_blacklist: queryStringBlacklist:
description: description:
- Names of query string parameters to exclude in cache keys. - Names of query string parameters to exclude in cache keys.
- All other parameters will be included. Either specify query_string_whitelist or - All other parameters will be included. Either specify query_string_whitelist or
@ -193,7 +193,7 @@ items:
- "'&' and '=' will be percent encoded and not treated as delimiters." - "'&' and '=' will be percent encoded and not treated as delimiters."
returned: success returned: success
type: list type: list
query_string_whitelist: queryStringWhitelist:
description: description:
- Names of query string parameters to include in cache keys. - Names of query string parameters to include in cache keys.
- All other parameters will be excluded. Either specify query_string_whitelist or - All other parameters will be excluded. Either specify query_string_whitelist or
@ -201,19 +201,19 @@ items:
- "'&' and '=' will be percent encoded and not treated as delimiters." - "'&' and '=' will be percent encoded and not treated as delimiters."
returned: success returned: success
type: list type: list
connection_draining: connectionDraining:
description: description:
- Settings for connection draining. - Settings for connection draining.
returned: success returned: success
type: complex type: complex
contains: contains:
draining_timeout_sec: drainingTimeoutSec:
description: description:
- Time for which instance will be drained (not accept new connections, but still work - Time for which instance will be drained (not accept new connections, but still work
to finish started). to finish started).
returned: success returned: success
type: int type: int
creation_timestamp: creationTimestamp:
description: description:
- Creation timestamp in RFC3339 text format. - Creation timestamp in RFC3339 text format.
returned: success returned: success
@ -223,13 +223,13 @@ items:
- An optional description of this resource. - An optional description of this resource.
returned: success returned: success
type: str type: str
enable_cdn: enableCDN:
description: description:
- If true, enable Cloud CDN for this BackendService. - If true, enable Cloud CDN for this BackendService.
- When the load balancing scheme is INTERNAL, this field is not used. - When the load balancing scheme is INTERNAL, this field is not used.
returned: success returned: success
type: bool type: bool
health_checks: healthChecks:
description: description:
- The list of URLs to the HttpHealthCheck or HttpsHealthCheck resource for health - The list of URLs to the HttpHealthCheck or HttpsHealthCheck resource for health
checking this BackendService. Currently at most one health check can be specified, checking this BackendService. Currently at most one health check can be specified,
@ -242,6 +242,39 @@ items:
- The unique identifier for the resource. - The unique identifier for the resource.
returned: success returned: success
type: int type: int
iap:
description:
- Settings for enabling Cloud Identity Aware Proxy.
returned: success
type: complex
contains:
enabled:
description:
- Enables IAP.
returned: success
type: bool
oauth2ClientId:
description:
- OAuth2 Client ID for IAP.
returned: success
type: str
oauth2ClientSecret:
description:
- OAuth2 Client Secret for IAP.
returned: success
type: str
oauth2ClientSecretSha256:
description:
- OAuth2 Client Secret SHA-256 for IAP.
returned: success
type: str
loadBalancingScheme:
description:
- Indicates whether the backend service will be used with internal or external load
balancing. A backend service created for one type of load balancing cannot be used
with the other.
returned: success
type: str
name: name:
description: description:
- Name of the resource. Provided by the client when the resource is created. The name - Name of the resource. Provided by the client when the resource is created. The name
@ -252,7 +285,7 @@ items:
be a dash. be a dash.
returned: success returned: success
type: str type: str
port_name: portName:
description: description:
- Name of backend port. The same name should appear in the instance groups referenced - Name of backend port. The same name should appear in the instance groups referenced
by this service. Required when the load balancing scheme is EXTERNAL. by this service. Required when the load balancing scheme is EXTERNAL.
@ -273,7 +306,7 @@ items:
- This field is not applicable to global backend services. - This field is not applicable to global backend services.
returned: success returned: success
type: str type: str
session_affinity: sessionAffinity:
description: description:
- Type of session affinity to use. The default is NONE. - Type of session affinity to use. The default is NONE.
- When the load balancing scheme is EXTERNAL, can be NONE, CLIENT_IP, or GENERATED_COOKIE. - When the load balancing scheme is EXTERNAL, can be NONE, CLIENT_IP, or GENERATED_COOKIE.
@ -282,7 +315,7 @@ items:
- When the protocol is UDP, this field is not used. - When the protocol is UDP, this field is not used.
returned: success returned: success
type: str type: str
timeout_sec: timeoutSec:
description: description:
- How many seconds to wait for the backend before considering it a failed request. - How many seconds to wait for the backend before considering it a failed request.
Default is 30 seconds. Valid range is [1, 86400]. Default is 30 seconds. Valid range is [1, 86400].
@ -304,7 +337,7 @@ import json
def main(): def main():
module = GcpModule( module = GcpModule(
argument_spec=dict( argument_spec=dict(
filters=dict(type='list', elements='str'), filters=dict(type='list', elements='str')
) )
) )

@ -155,6 +155,11 @@ options:
full URL to the resource. For example, the following are valid values: * full URL to the resource. For example, the following are valid values: *
`U(https://www.googleapis.com/compute/v1/projects/project/global/snapshots/snapshot`) `U(https://www.googleapis.com/compute/v1/projects/project/global/snapshots/snapshot`)
* `projects/project/global/snapshots/snapshot` * `global/snapshots/snapshot` .' * `projects/project/global/snapshots/snapshot` * `global/snapshots/snapshot` .'
- 'This field represents a link to a Snapshot resource in GCP. It can be specified
in two ways. You can add `register: name-of-resource` to a gcp_compute_snapshot
task and then set this source_snapshot field to "{{ name-of-resource }}" Alternatively,
you can set this source_snapshot to a dictionary with the selfLink key where the
value is the selfLink of your Snapshot.'
required: false required: false
source_snapshot_encryption_key: source_snapshot_encryption_key:
description: description:
@ -187,13 +192,19 @@ EXAMPLES = '''
raw_key: SGVsbG8gZnJvbSBHb29nbGUgQ2xvdWQgUGxhdGZvcm0= raw_key: SGVsbG8gZnJvbSBHb29nbGUgQ2xvdWQgUGxhdGZvcm0=
zone: us-central1-a zone: us-central1-a
project: "test_project" project: "test_project"
auth_kind: "service_account" auth_kind: "serviceaccount"
service_account_file: "/tmp/auth.pem" service_account_file: "/tmp/auth.pem"
state: present state: present
''' '''
RETURN = ''' RETURN = '''
creation_timestamp: labelFingerprint:
description:
- The fingerprint used for optimistic locking of this resource. Used internally during
updates.
returned: success
type: str
creationTimestamp:
description: description:
- Creation timestamp in RFC3339 text format. - Creation timestamp in RFC3339 text format.
returned: success returned: success
@ -209,12 +220,12 @@ RETURN = '''
- The unique identifier for the resource. - The unique identifier for the resource.
returned: success returned: success
type: int type: int
last_attach_timestamp: lastAttachTimestamp:
description: description:
- Last attach timestamp in RFC3339 text format. - Last attach timestamp in RFC3339 text format.
returned: success returned: success
type: str type: str
last_detach_timestamp: lastDetachTimestamp:
description: description:
- Last dettach timestamp in RFC3339 text format. - Last dettach timestamp in RFC3339 text format.
returned: success returned: success
@ -239,7 +250,7 @@ RETURN = '''
be a dash. be a dash.
returned: success returned: success
type: str type: str
size_gb: sizeGb:
description: description:
- Size of the persistent disk, specified in GB. You can specify this field when creating - Size of the persistent disk, specified in GB. You can specify this field when creating
a persistent disk using the sourceImage or sourceSnapshot parameter, or specify a persistent disk using the sourceImage or sourceSnapshot parameter, or specify
@ -248,19 +259,19 @@ RETURN = '''
sizeGb must not be less than the size of the sourceImage or the size of the snapshot. sizeGb must not be less than the size of the sourceImage or the size of the snapshot.
returned: success returned: success
type: int type: int
type:
description:
- URL of the disk type resource describing which disk type to use to create the disk.
Provide this when creating the disk.
returned: success
type: str
users: users:
description: description:
- 'Links to the users of the disk (attached instances) in form: project/zones/zone/instances/instance - 'Links to the users of the disk (attached instances) in form: project/zones/zone/instances/instance
.' .'
returned: success returned: success
type: list type: list
source_image: type:
description:
- URL of the disk type resource describing which disk type to use to create the disk.
Provide this when creating the disk.
returned: success
type: str
sourceImage:
description: description:
- The source image used to create this disk. If the source image is deleted, this - The source image used to create this disk. If the source image is deleted, this
field will not be set. field will not be set.
@ -280,14 +291,14 @@ RETURN = '''
- A reference to the zone where the disk resides. - A reference to the zone where the disk resides.
returned: success returned: success
type: str type: str
source_image_encryption_key: sourceImageEncryptionKey:
description: description:
- The customer-supplied encryption key of the source image. Required if the source - The customer-supplied encryption key of the source image. Required if the source
image is protected by a customer-supplied encryption key. image is protected by a customer-supplied encryption key.
returned: success returned: success
type: complex type: complex
contains: contains:
raw_key: rawKey:
description: description:
- Specifies a 256-bit customer-supplied encryption key, encoded in RFC 4648 base64 - Specifies a 256-bit customer-supplied encryption key, encoded in RFC 4648 base64
to either encrypt or decrypt this resource. to either encrypt or decrypt this resource.
@ -299,7 +310,7 @@ RETURN = '''
that protects this resource. that protects this resource.
returned: success returned: success
type: str type: str
source_image_id: sourceImageId:
description: description:
- The ID value of the image used to create this disk. This value identifies the exact - The ID value of the image used to create this disk. This value identifies the exact
image that was used to create this persistent disk. For example, if you created image that was used to create this persistent disk. For example, if you created
@ -308,7 +319,7 @@ RETURN = '''
was used. was used.
returned: success returned: success
type: str type: str
disk_encryption_key: diskEncryptionKey:
description: description:
- Encrypts the disk using a customer-supplied encryption key. - Encrypts the disk using a customer-supplied encryption key.
- After you encrypt a disk with a customer-supplied key, you must provide the same - After you encrypt a disk with a customer-supplied key, you must provide the same
@ -321,7 +332,7 @@ RETURN = '''
returned: success returned: success
type: complex type: complex
contains: contains:
raw_key: rawKey:
description: description:
- Specifies a 256-bit customer-supplied encryption key, encoded in RFC 4648 base64 - Specifies a 256-bit customer-supplied encryption key, encoded in RFC 4648 base64
to either encrypt or decrypt this resource. to either encrypt or decrypt this resource.
@ -333,7 +344,7 @@ RETURN = '''
that protects this resource. that protects this resource.
returned: success returned: success
type: str type: str
source_snapshot: sourceSnapshot:
description: description:
- 'The source snapshot used to create this disk. You can provide this as a partial or - 'The source snapshot used to create this disk. You can provide this as a partial or
full URL to the resource. For example, the following are valid values: * full URL to the resource. For example, the following are valid values: *
@ -341,14 +352,14 @@ RETURN = '''
* `projects/project/global/snapshots/snapshot` * `global/snapshots/snapshot` .' * `projects/project/global/snapshots/snapshot` * `global/snapshots/snapshot` .'
returned: success returned: success
type: dict type: dict
source_snapshot_encryption_key: sourceSnapshotEncryptionKey:
description: description:
- The customer-supplied encryption key of the source snapshot. Required if the source - The customer-supplied encryption key of the source snapshot. Required if the source
snapshot is protected by a customer-supplied encryption key. snapshot is protected by a customer-supplied encryption key.
returned: success returned: success
type: complex type: complex
contains: contains:
raw_key: rawKey:
description: description:
- Specifies a 256-bit customer-supplied encryption key, encoded in RFC 4648 base64 - Specifies a 256-bit customer-supplied encryption key, encoded in RFC 4648 base64
to either encrypt or decrypt this resource. to either encrypt or decrypt this resource.
@ -360,7 +371,7 @@ RETURN = '''
that protects this resource. that protects this resource.
returned: success returned: success
type: str type: str
source_snapshot_id: sourceSnapshotId:
description: description:
- The unique ID of the snapshot used to create this disk. This value identifies the - The unique ID of the snapshot used to create this disk. This value identifies the
exact snapshot that was used to create this persistent disk. For example, if you exact snapshot that was used to create this persistent disk. For example, if you
@ -427,7 +438,8 @@ def main():
if fetch: if fetch:
if state == 'present': if state == 'present':
if is_different(module, fetch): if is_different(module, fetch):
fetch = update(module, self_link(module), kind) update(module, self_link(module), kind, fetch)
fetch = fetch_resource(module, self_link(module), kind)
changed = True changed = True
else: else:
delete(module, self_link(module), kind) delete(module, self_link(module), kind)
@ -450,8 +462,44 @@ def create(module, link, kind):
return wait_for_operation(module, auth.post(link, resource_to_request(module))) return wait_for_operation(module, auth.post(link, resource_to_request(module)))
def update(module, link, kind): def update(module, link, kind, fetch):
module.fail_json(msg="Disk cannot be edited") 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('labels') != request.get('labels'):
label_fingerprint_update(module, request, response)
if response.get('sizeGb') != request.get('sizeGb'):
size_gb_update(module, request, response)
def label_fingerprint_update(module, request, response):
auth = GcpSession(module, 'compute')
auth.post(
''.join([
"https://www.googleapis.com/compute/v1/",
"projects/{project}/zones/{zone}/disks/{name}/setLabels"
]).format(**module.params),
{
u'labelFingerprint': response.get('labelFingerprint'),
u'labels': module.params.get('labels')
}
)
def size_gb_update(module, request, response):
auth = GcpSession(module, 'compute')
auth.post(
''.join([
"https://www.googleapis.com/compute/v1/",
"projects/{project}/zones/{zone}/disks/{name}/resize"
]).format(**module.params),
{
u'sizeGb': module.params.get('size_gb')
}
)
def delete(module, link, kind): def delete(module, link, kind):
@ -481,9 +529,9 @@ def resource_to_request(module):
return return_vals return return_vals
def fetch_resource(module, link, kind): def fetch_resource(module, link, kind, allow_not_found=True):
auth = GcpSession(module, 'compute') auth = GcpSession(module, 'compute')
return return_if_object(module, auth.get(link), kind) return return_if_object(module, auth.get(link), kind, allow_not_found)
def self_link(module): def self_link(module):
@ -494,9 +542,9 @@ def collection(module):
return "https://www.googleapis.com/compute/v1/projects/{project}/zones/{zone}/disks".format(**module.params) return "https://www.googleapis.com/compute/v1/projects/{project}/zones/{zone}/disks".format(**module.params)
def return_if_object(module, response, kind): def return_if_object(module, response, kind, allow_not_found=False):
# If not found, return nothing. # If not found, return nothing.
if response.status_code == 404: if allow_not_found and response.status_code == 404:
return None return None
# If no content, return nothing. # If no content, return nothing.
@ -511,8 +559,6 @@ def return_if_object(module, response, kind):
if navigate_hash(result, ['error', 'errors']): if navigate_hash(result, ['error', 'errors']):
module.fail_json(msg=navigate_hash(result, ['error', 'errors'])) module.fail_json(msg=navigate_hash(result, ['error', 'errors']))
if result['kind'] != kind:
module.fail_json(msg="Incorrect result: {kind}".format(**result))
return result return result
@ -539,6 +585,7 @@ def is_different(module, response):
# This is for doing comparisons with Ansible's current parameters. # This is for doing comparisons with Ansible's current parameters.
def response_to_hash(module, response): def response_to_hash(module, response):
return { return {
u'labelFingerprint': response.get(u'labelFingerprint'),
u'creationTimestamp': response.get(u'creationTimestamp'), u'creationTimestamp': response.get(u'creationTimestamp'),
u'description': response.get(u'description'), u'description': response.get(u'description'),
u'id': response.get(u'id'), u'id': response.get(u'id'),
@ -548,8 +595,8 @@ def response_to_hash(module, response):
u'licenses': response.get(u'licenses'), u'licenses': response.get(u'licenses'),
u'name': module.params.get('name'), u'name': module.params.get('name'),
u'sizeGb': response.get(u'sizeGb'), u'sizeGb': response.get(u'sizeGb'),
u'type': response.get(u'type'),
u'users': response.get(u'users'), u'users': response.get(u'users'),
u'type': response.get(u'type'),
u'sourceImage': module.params.get('source_image') u'sourceImage': module.params.get('source_image')
} }
@ -557,7 +604,7 @@ def response_to_hash(module, response):
def disk_type_selflink(name, params): def disk_type_selflink(name, params):
if name is None: if name is None:
return return
url = r"https://www.googleapis.com/compute/v1/projects/.*/zones/{zone}/diskTypes/[a-z1-9\-]*" url = r"https://www.googleapis.com/compute/v1/projects/.*/zones/[a-z1-9\-]*/diskTypes/[a-z1-9\-]*"
if not re.match(url, name): if not re.match(url, name):
name = "https://www.googleapis.com/compute/v1/projects/{project}/zones/{zone}/diskTypes/%s".format(**params) % name name = "https://www.googleapis.com/compute/v1/projects/{project}/zones/{zone}/diskTypes/%s".format(**params) % name
return name return name

@ -61,7 +61,7 @@ EXAMPLES = '''
filters: filters:
- name = test_object - name = test_object
project: test_project project: test_project
auth_kind: service_account auth_kind: serviceaccount
service_account_file: "/tmp/auth.pem" service_account_file: "/tmp/auth.pem"
''' '''
@ -71,7 +71,13 @@ items:
returned: always returned: always
type: complex type: complex
contains: contains:
creation_timestamp: labelFingerprint:
description:
- The fingerprint used for optimistic locking of this resource. Used internally during
updates.
returned: success
type: str
creationTimestamp:
description: description:
- Creation timestamp in RFC3339 text format. - Creation timestamp in RFC3339 text format.
returned: success returned: success
@ -87,12 +93,12 @@ items:
- The unique identifier for the resource. - The unique identifier for the resource.
returned: success returned: success
type: int type: int
last_attach_timestamp: lastAttachTimestamp:
description: description:
- Last attach timestamp in RFC3339 text format. - Last attach timestamp in RFC3339 text format.
returned: success returned: success
type: str type: str
last_detach_timestamp: lastDetachTimestamp:
description: description:
- Last dettach timestamp in RFC3339 text format. - Last dettach timestamp in RFC3339 text format.
returned: success returned: success
@ -117,7 +123,7 @@ items:
be a dash. be a dash.
returned: success returned: success
type: str type: str
size_gb: sizeGb:
description: description:
- Size of the persistent disk, specified in GB. You can specify this field when creating - Size of the persistent disk, specified in GB. You can specify this field when creating
a persistent disk using the sourceImage or sourceSnapshot parameter, or specify a persistent disk using the sourceImage or sourceSnapshot parameter, or specify
@ -138,7 +144,7 @@ items:
Provide this when creating the disk. Provide this when creating the disk.
returned: success returned: success
type: str type: str
source_image: sourceImage:
description: description:
- The source image used to create this disk. If the source image is deleted, this - The source image used to create this disk. If the source image is deleted, this
field will not be set. field will not be set.
@ -158,14 +164,14 @@ items:
- A reference to the zone where the disk resides. - A reference to the zone where the disk resides.
returned: success returned: success
type: str type: str
source_image_encryption_key: sourceImageEncryptionKey:
description: description:
- The customer-supplied encryption key of the source image. Required if the source - The customer-supplied encryption key of the source image. Required if the source
image is protected by a customer-supplied encryption key. image is protected by a customer-supplied encryption key.
returned: success returned: success
type: complex type: complex
contains: contains:
raw_key: rawKey:
description: description:
- Specifies a 256-bit customer-supplied encryption key, encoded in RFC 4648 base64 - Specifies a 256-bit customer-supplied encryption key, encoded in RFC 4648 base64
to either encrypt or decrypt this resource. to either encrypt or decrypt this resource.
@ -177,7 +183,7 @@ items:
that protects this resource. that protects this resource.
returned: success returned: success
type: str type: str
source_image_id: sourceImageId:
description: description:
- The ID value of the image used to create this disk. This value identifies the exact - The ID value of the image used to create this disk. This value identifies the exact
image that was used to create this persistent disk. For example, if you created image that was used to create this persistent disk. For example, if you created
@ -186,7 +192,7 @@ items:
was used. was used.
returned: success returned: success
type: str type: str
disk_encryption_key: diskEncryptionKey:
description: description:
- Encrypts the disk using a customer-supplied encryption key. - Encrypts the disk using a customer-supplied encryption key.
- After you encrypt a disk with a customer-supplied key, you must provide the same - After you encrypt a disk with a customer-supplied key, you must provide the same
@ -199,7 +205,7 @@ items:
returned: success returned: success
type: complex type: complex
contains: contains:
raw_key: rawKey:
description: description:
- Specifies a 256-bit customer-supplied encryption key, encoded in RFC 4648 base64 - Specifies a 256-bit customer-supplied encryption key, encoded in RFC 4648 base64
to either encrypt or decrypt this resource. to either encrypt or decrypt this resource.
@ -211,7 +217,7 @@ items:
that protects this resource. that protects this resource.
returned: success returned: success
type: str type: str
source_snapshot: sourceSnapshot:
description: description:
- 'The source snapshot used to create this disk. You can provide this as a partial - 'The source snapshot used to create this disk. You can provide this as a partial
or full URL to the resource. For example, the following are valid values: * or full URL to the resource. For example, the following are valid values: *
@ -219,14 +225,14 @@ items:
* `projects/project/global/snapshots/snapshot` * `global/snapshots/snapshot` .' * `projects/project/global/snapshots/snapshot` * `global/snapshots/snapshot` .'
returned: success returned: success
type: dict type: dict
source_snapshot_encryption_key: sourceSnapshotEncryptionKey:
description: description:
- The customer-supplied encryption key of the source snapshot. Required if the source - The customer-supplied encryption key of the source snapshot. Required if the source
snapshot is protected by a customer-supplied encryption key. snapshot is protected by a customer-supplied encryption key.
returned: success returned: success
type: complex type: complex
contains: contains:
raw_key: rawKey:
description: description:
- Specifies a 256-bit customer-supplied encryption key, encoded in RFC 4648 base64 - Specifies a 256-bit customer-supplied encryption key, encoded in RFC 4648 base64
to either encrypt or decrypt this resource. to either encrypt or decrypt this resource.
@ -238,7 +244,7 @@ items:
that protects this resource. that protects this resource.
returned: success returned: success
type: str type: str
source_snapshot_id: sourceSnapshotId:
description: description:
- The unique ID of the snapshot used to create this disk. This value identifies the - The unique ID of the snapshot used to create this disk. This value identifies the
exact snapshot that was used to create this persistent disk. For example, if you exact snapshot that was used to create this persistent disk. For example, if you

@ -72,11 +72,55 @@ options:
specified, this rule applies to connections through any port. specified, this rule applies to connections through any port.
- 'Example inputs include: ["22"], ["80","443"], and ["12345-12349"].' - 'Example inputs include: ["22"], ["80","443"], and ["12345-12349"].'
required: false required: false
denied:
description:
- The list of DENY rules specified by this firewall. Each rule specifies a protocol
and port-range tuple that describes a denied connection.
required: false
version_added: 2.8
suboptions:
ip_protocol:
description:
- The IP protocol to which this rule applies. The protocol type is required when creating
a firewall rule. This value can either be one of the following well known protocol
strings (tcp, udp, icmp, esp, ah, sctp), or the IP protocol number.
required: true
ports:
description:
- An optional list of ports to which this rule applies. This field is only applicable
for UDP or TCP protocol. Each entry must be either an integer or a range. If not
specified, this rule applies to connections through any port.
- 'Example inputs include: ["22"], ["80","443"], and ["12345-12349"].'
required: false
description: description:
description: description:
- An optional description of this resource. Provide this property when you create - An optional description of this resource. Provide this property when you create
the resource. the resource.
required: false required: false
destination_ranges:
description:
- If destination ranges are specified, the firewall will apply only to traffic that
has destination IP address in these ranges. These ranges must be expressed in CIDR
format. Only IPv4 is supported.
required: false
version_added: 2.8
direction:
description:
- 'Direction of traffic to which this firewall applies; default is INGRESS. Note:
For INGRESS traffic, it is NOT supported to specify destinationRanges; For EGRESS
traffic, it is NOT supported to specify sourceRanges OR sourceTags.'
required: false
version_added: 2.8
choices: ['INGRESS', 'EGRESS']
disabled:
description:
- Denotes whether the firewall rule is disabled, i.e not applied to the network it
is associated with. When set to true, the firewall rule is not enforced and the
network behaves as if it did not exist. If this is unspecified, the firewall rule
will be enabled.
required: false
type: bool
version_added: 2.8
name: name:
description: description:
- Name of the resource. Provided by the client when the resource is created. The name - Name of the resource. Provided by the client when the resource is created. The name
@ -85,7 +129,7 @@ options:
which means the first character must be a lowercase letter, and all following characters which means the first character must be a lowercase letter, and all following characters
must be a dash, lowercase letter, or digit, except the last character, which cannot must be a dash, lowercase letter, or digit, except the last character, which cannot
be a dash. be a dash.
required: false required: true
network: network:
description: description:
- 'URL of the network resource for this firewall rule. If not specified when creating - 'URL of the network resource for this firewall rule. If not specified when creating
@ -95,7 +139,22 @@ options:
U(https://www.googleapis.com/compute/v1/projects/myproject/global/) U(https://www.googleapis.com/compute/v1/projects/myproject/global/)
networks/my-network projects/myproject/global/networks/my-network networks/my-network projects/myproject/global/networks/my-network
global/networks/default .' global/networks/default .'
- 'This field represents a link to a Network resource in GCP. It can be specified
in two ways. You can add `register: name-of-resource` to a gcp_compute_network 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
priority:
description:
- Priority for this rule. This is an integer between 0 and 65535, both inclusive.
When not specified, the value assumed is 1000. Relative priorities determine precedence
of conflicting rules. Lower value of priority implies higher precedence (eg, a rule
with priority 0 has higher precedence than a rule with priority 1). DENY rules take
precedence over ALLOW rules having equal priority.
required: false required: false
default: 1000
version_added: 2.8
source_ranges: source_ranges:
description: description:
- If source ranges are specified, the firewall will apply only to traffic that has - If source ranges are specified, the firewall will apply only to traffic that has
@ -105,6 +164,19 @@ options:
OR the source IP that belongs to a tag listed in the sourceTags property. The connection OR the source IP that belongs to a tag listed in the sourceTags property. The connection
does not need to match both properties for the firewall to apply. Only IPv4 is supported. does not need to match both properties for the firewall to apply. Only IPv4 is supported.
required: false required: false
source_service_accounts:
description:
- If source service accounts are specified, the firewall will apply only to traffic
originating from an instance with a service account in this list. Source service
accounts cannot be used to control traffic to an instance's external IP address
because service accounts are associated with an instance, not an IP address. sourceRanges
can be set at the same time as sourceServiceAccounts. If both are set, the firewall
will apply to traffic that has source IP address within sourceRanges OR the source
IP belongs to an instance with service account listed in sourceServiceAccount. The
connection does not need to match both properties for the firewall to apply. sourceServiceAccounts
cannot be used at the same time as sourceTags or targetTags.
required: false
version_added: 2.8
source_tags: source_tags:
description: description:
- If source tags are specified, the firewall will apply only to traffic with source - If source tags are specified, the firewall will apply only to traffic with source
@ -116,6 +188,15 @@ options:
sourceTags property. The connection does not need to match both properties for the sourceTags property. The connection does not need to match both properties for the
firewall to apply. firewall to apply.
required: false required: false
target_service_accounts:
description:
- A list of service accounts indicating sets of instances located in the network that
may make network connections as specified in allowed[].
- targetServiceAccounts cannot be used at the same time as targetTags or sourceTags.
If neither targetServiceAccounts nor targetTags are specified, the firewall rule
applies to all instances on the specified network.
required: false
version_added: 2.8
target_tags: target_tags:
description: description:
- A list of instance tags indicating sets of instances located in the network that - A list of instance tags indicating sets of instances located in the network that
@ -124,6 +205,9 @@ options:
specified network. specified network.
required: false required: false
extends_documentation_fragment: gcp extends_documentation_fragment: gcp
notes:
- "API Reference: U(https://cloud.google.com/compute/docs/reference/latest/firewalls)"
- "Official Documentation: U(https://cloud.google.com/vpc/docs/firewalls)"
''' '''
EXAMPLES = ''' EXAMPLES = '''
@ -140,7 +224,7 @@ EXAMPLES = '''
source_tags: source_tags:
- test-ssh-clients - test-ssh-clients
project: "test_project" project: "test_project"
auth_kind: "service_account" auth_kind: "serviceaccount"
service_account_file: "/tmp/auth.pem" service_account_file: "/tmp/auth.pem"
state: present state: present
''' '''
@ -168,17 +252,61 @@ RETURN = '''
- 'Example inputs include: ["22"], ["80","443"], and ["12345-12349"].' - 'Example inputs include: ["22"], ["80","443"], and ["12345-12349"].'
returned: success returned: success
type: list type: list
creation_timestamp: creationTimestamp:
description: description:
- Creation timestamp in RFC3339 text format. - Creation timestamp in RFC3339 text format.
returned: success returned: success
type: str type: str
denied:
description:
- The list of DENY rules specified by this firewall. Each rule specifies a protocol
and port-range tuple that describes a denied connection.
returned: success
type: complex
contains:
ip_protocol:
description:
- The IP protocol to which this rule applies. The protocol type is required when creating
a firewall rule. This value can either be one of the following well known protocol
strings (tcp, udp, icmp, esp, ah, sctp), or the IP protocol number.
returned: success
type: str
ports:
description:
- An optional list of ports to which this rule applies. This field is only applicable
for UDP or TCP protocol. Each entry must be either an integer or a range. If not
specified, this rule applies to connections through any port.
- 'Example inputs include: ["22"], ["80","443"], and ["12345-12349"].'
returned: success
type: list
description: description:
description: description:
- An optional description of this resource. Provide this property when you create - An optional description of this resource. Provide this property when you create
the resource. the resource.
returned: success returned: success
type: str type: str
destinationRanges:
description:
- If destination ranges are specified, the firewall will apply only to traffic that
has destination IP address in these ranges. These ranges must be expressed in CIDR
format. Only IPv4 is supported.
returned: success
type: list
direction:
description:
- 'Direction of traffic to which this firewall applies; default is INGRESS. Note:
For INGRESS traffic, it is NOT supported to specify destinationRanges; For EGRESS
traffic, it is NOT supported to specify sourceRanges OR sourceTags.'
returned: success
type: str
disabled:
description:
- Denotes whether the firewall rule is disabled, i.e not applied to the network it
is associated with. When set to true, the firewall rule is not enforced and the
network behaves as if it did not exist. If this is unspecified, the firewall rule
will be enabled.
returned: success
type: bool
id: id:
description: description:
- The unique identifier for the resource. - The unique identifier for the resource.
@ -204,8 +332,17 @@ RETURN = '''
networks/my-network projects/myproject/global/networks/my-network networks/my-network projects/myproject/global/networks/my-network
global/networks/default .' global/networks/default .'
returned: success returned: success
type: str type: dict
source_ranges: priority:
description:
- Priority for this rule. This is an integer between 0 and 65535, both inclusive.
When not specified, the value assumed is 1000. Relative priorities determine precedence
of conflicting rules. Lower value of priority implies higher precedence (eg, a rule
with priority 0 has higher precedence than a rule with priority 1). DENY rules take
precedence over ALLOW rules having equal priority.
returned: success
type: int
sourceRanges:
description: description:
- If source ranges are specified, the firewall will apply only to traffic that has - If source ranges are specified, the firewall will apply only to traffic that has
source IP address in these ranges. These ranges must be expressed in CIDR format. source IP address in these ranges. These ranges must be expressed in CIDR format.
@ -215,7 +352,20 @@ RETURN = '''
does not need to match both properties for the firewall to apply. Only IPv4 is supported. does not need to match both properties for the firewall to apply. Only IPv4 is supported.
returned: success returned: success
type: list type: list
source_tags: sourceServiceAccounts:
description:
- If source service accounts are specified, the firewall will apply only to traffic
originating from an instance with a service account in this list. Source service
accounts cannot be used to control traffic to an instance's external IP address
because service accounts are associated with an instance, not an IP address. sourceRanges
can be set at the same time as sourceServiceAccounts. If both are set, the firewall
will apply to traffic that has source IP address within sourceRanges OR the source
IP belongs to an instance with service account listed in sourceServiceAccount. The
connection does not need to match both properties for the firewall to apply. sourceServiceAccounts
cannot be used at the same time as sourceTags or targetTags.
returned: success
type: list
sourceTags:
description: description:
- If source tags are specified, the firewall will apply only to traffic with source - If source tags are specified, the firewall will apply only to traffic with source
IP that belongs to a tag listed in source tags. Source tags cannot be used to control IP that belongs to a tag listed in source tags. Source tags cannot be used to control
@ -227,7 +377,16 @@ RETURN = '''
firewall to apply. firewall to apply.
returned: success returned: success
type: list type: list
target_tags: targetServiceAccounts:
description:
- A list of service accounts indicating sets of instances located in the network that
may make network connections as specified in allowed[].
- targetServiceAccounts cannot be used at the same time as targetTags or sourceTags.
If neither targetServiceAccounts nor targetTags are specified, the firewall rule
applies to all instances on the specified network.
returned: success
type: list
targetTags:
description: description:
- A list of instance tags indicating sets of instances located in the network that - A list of instance tags indicating sets of instances located in the network that
may make network connections as specified in allowed[]. may make network connections as specified in allowed[].
@ -260,11 +419,21 @@ def main():
ip_protocol=dict(required=True, type='str'), ip_protocol=dict(required=True, type='str'),
ports=dict(type='list', elements='str') ports=dict(type='list', elements='str')
)), )),
denied=dict(type='list', elements='dict', options=dict(
ip_protocol=dict(required=True, type='str'),
ports=dict(type='list', elements='str')
)),
description=dict(type='str'), description=dict(type='str'),
name=dict(type='str'), destination_ranges=dict(type='list', elements='str'),
network=dict(type='str'), direction=dict(type='str', choices=['INGRESS', 'EGRESS']),
disabled=dict(type='bool'),
name=dict(required=True, type='str'),
network=dict(required=True, type='dict'),
priority=dict(default=1000, type='int'),
source_ranges=dict(type='list', elements='str'), source_ranges=dict(type='list', elements='str'),
source_service_accounts=dict(type='list', elements='str'),
source_tags=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') target_tags=dict(type='list', elements='str')
) )
) )
@ -281,7 +450,8 @@ def main():
if fetch: if fetch:
if state == 'present': if state == 'present':
if is_different(module, fetch): if is_different(module, fetch):
fetch = update(module, self_link(module), kind) update(module, self_link(module), kind)
fetch = fetch_resource(module, self_link(module), kind)
changed = True changed = True
else: else:
delete(module, self_link(module), kind) delete(module, self_link(module), kind)
@ -306,7 +476,7 @@ def create(module, link, kind):
def update(module, link, kind): def update(module, link, kind):
auth = GcpSession(module, 'compute') auth = GcpSession(module, 'compute')
return wait_for_operation(module, auth.put(link, resource_to_request(module))) return wait_for_operation(module, auth.patch(link, resource_to_request(module)))
def delete(module, link, kind): def delete(module, link, kind):
@ -318,11 +488,18 @@ def resource_to_request(module):
request = { request = {
u'kind': 'compute#firewall', u'kind': 'compute#firewall',
u'allowed': FirewallAllowedArray(module.params.get('allowed', []), module).to_request(), u'allowed': FirewallAllowedArray(module.params.get('allowed', []), module).to_request(),
u'denied': FirewallDeniedArray(module.params.get('denied', []), module).to_request(),
u'description': module.params.get('description'), u'description': module.params.get('description'),
u'destinationRanges': module.params.get('destination_ranges'),
u'direction': module.params.get('direction'),
u'disabled': module.params.get('disabled'),
u'name': module.params.get('name'), u'name': module.params.get('name'),
u'network': module.params.get('network'), u'network': replace_resource_dict(module.params.get(u'network', {}), 'selfLink'),
u'priority': module.params.get('priority'),
u'sourceRanges': module.params.get('source_ranges'), u'sourceRanges': module.params.get('source_ranges'),
u'sourceServiceAccounts': module.params.get('source_service_accounts'),
u'sourceTags': module.params.get('source_tags'), u'sourceTags': module.params.get('source_tags'),
u'targetServiceAccounts': module.params.get('target_service_accounts'),
u'targetTags': module.params.get('target_tags') u'targetTags': module.params.get('target_tags')
} }
return_vals = {} return_vals = {}
@ -333,9 +510,9 @@ def resource_to_request(module):
return return_vals return return_vals
def fetch_resource(module, link, kind): def fetch_resource(module, link, kind, allow_not_found=True):
auth = GcpSession(module, 'compute') auth = GcpSession(module, 'compute')
return return_if_object(module, auth.get(link), kind) return return_if_object(module, auth.get(link), kind, allow_not_found)
def self_link(module): def self_link(module):
@ -346,9 +523,9 @@ def collection(module):
return "https://www.googleapis.com/compute/v1/projects/{project}/global/firewalls".format(**module.params) return "https://www.googleapis.com/compute/v1/projects/{project}/global/firewalls".format(**module.params)
def return_if_object(module, response, kind): def return_if_object(module, response, kind, allow_not_found=False):
# If not found, return nothing. # If not found, return nothing.
if response.status_code == 404: if allow_not_found and response.status_code == 404:
return None return None
# If no content, return nothing. # If no content, return nothing.
@ -363,8 +540,6 @@ def return_if_object(module, response, kind):
if navigate_hash(result, ['error', 'errors']): if navigate_hash(result, ['error', 'errors']):
module.fail_json(msg=navigate_hash(result, ['error', 'errors'])) module.fail_json(msg=navigate_hash(result, ['error', 'errors']))
if result['kind'] != kind:
module.fail_json(msg="Incorrect result: {kind}".format(**result))
return result return result
@ -393,12 +568,19 @@ def response_to_hash(module, response):
return { return {
u'allowed': FirewallAllowedArray(response.get(u'allowed', []), module).from_response(), u'allowed': FirewallAllowedArray(response.get(u'allowed', []), module).from_response(),
u'creationTimestamp': response.get(u'creationTimestamp'), u'creationTimestamp': response.get(u'creationTimestamp'),
u'denied': FirewallDeniedArray(response.get(u'denied', []), module).from_response(),
u'description': response.get(u'description'), u'description': response.get(u'description'),
u'destinationRanges': response.get(u'destinationRanges'),
u'direction': response.get(u'direction'),
u'disabled': response.get(u'disabled'),
u'id': response.get(u'id'), u'id': response.get(u'id'),
u'name': response.get(u'name'), u'name': module.params.get('name'),
u'network': response.get(u'network'), u'network': response.get(u'network'),
u'priority': response.get(u'priority'),
u'sourceRanges': response.get(u'sourceRanges'), u'sourceRanges': response.get(u'sourceRanges'),
u'sourceServiceAccounts': response.get(u'sourceServiceAccounts'),
u'sourceTags': response.get(u'sourceTags'), u'sourceTags': response.get(u'sourceTags'),
u'targetServiceAccounts': response.get(u'targetServiceAccounts'),
u'targetTags': response.get(u'targetTags') u'targetTags': response.get(u'targetTags')
} }
@ -473,5 +655,38 @@ class FirewallAllowedArray(object):
}) })
class FirewallDeniedArray(object):
def __init__(self, request, module):
self.module = module
if request:
self.request = request
else:
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'IPProtocol': item.get('ip_protocol'),
u'ports': item.get('ports')
})
def _response_from_item(self, item):
return remove_nones_from_dict({
u'IPProtocol': item.get(u'ip_protocol'),
u'ports': item.get(u'ports')
})
if __name__ == '__main__': if __name__ == '__main__':
main() main()

@ -56,7 +56,7 @@ EXAMPLES = '''
filters: filters:
- name = test_object - name = test_object
project: test_project project: test_project
auth_kind: service_account auth_kind: serviceaccount
service_account_file: "/tmp/auth.pem" service_account_file: "/tmp/auth.pem"
''' '''
@ -88,17 +88,61 @@ items:
- 'Example inputs include: ["22"], ["80","443"], and ["12345-12349"].' - 'Example inputs include: ["22"], ["80","443"], and ["12345-12349"].'
returned: success returned: success
type: list type: list
creation_timestamp: creationTimestamp:
description: description:
- Creation timestamp in RFC3339 text format. - Creation timestamp in RFC3339 text format.
returned: success returned: success
type: str type: str
denied:
description:
- The list of DENY rules specified by this firewall. Each rule specifies a protocol
and port-range tuple that describes a denied connection.
returned: success
type: complex
contains:
ip_protocol:
description:
- The IP protocol to which this rule applies. The protocol type is required when creating
a firewall rule. This value can either be one of the following well known protocol
strings (tcp, udp, icmp, esp, ah, sctp), or the IP protocol number.
returned: success
type: str
ports:
description:
- An optional list of ports to which this rule applies. This field is only applicable
for UDP or TCP protocol. Each entry must be either an integer or a range. If not
specified, this rule applies to connections through any port.
- 'Example inputs include: ["22"], ["80","443"], and ["12345-12349"].'
returned: success
type: list
description: description:
description: description:
- An optional description of this resource. Provide this property when you create - An optional description of this resource. Provide this property when you create
the resource. the resource.
returned: success returned: success
type: str type: str
destinationRanges:
description:
- If destination ranges are specified, the firewall will apply only to traffic that
has destination IP address in these ranges. These ranges must be expressed in CIDR
format. Only IPv4 is supported.
returned: success
type: list
direction:
description:
- 'Direction of traffic to which this firewall applies; default is INGRESS. Note:
For INGRESS traffic, it is NOT supported to specify destinationRanges; For EGRESS
traffic, it is NOT supported to specify sourceRanges OR sourceTags.'
returned: success
type: str
disabled:
description:
- Denotes whether the firewall rule is disabled, i.e not applied to the network it
is associated with. When set to true, the firewall rule is not enforced and the
network behaves as if it did not exist. If this is unspecified, the firewall rule
will be enabled.
returned: success
type: bool
id: id:
description: description:
- The unique identifier for the resource. - The unique identifier for the resource.
@ -124,8 +168,17 @@ items:
networks/my-network projects/myproject/global/networks/my-network networks/my-network projects/myproject/global/networks/my-network
global/networks/default .' global/networks/default .'
returned: success returned: success
type: str type: dict
source_ranges: priority:
description:
- Priority for this rule. This is an integer between 0 and 65535, both inclusive.
When not specified, the value assumed is 1000. Relative priorities determine precedence
of conflicting rules. Lower value of priority implies higher precedence (eg, a rule
with priority 0 has higher precedence than a rule with priority 1). DENY rules take
precedence over ALLOW rules having equal priority.
returned: success
type: int
sourceRanges:
description: description:
- If source ranges are specified, the firewall will apply only to traffic that has - If source ranges are specified, the firewall will apply only to traffic that has
source IP address in these ranges. These ranges must be expressed in CIDR format. source IP address in these ranges. These ranges must be expressed in CIDR format.
@ -135,7 +188,20 @@ items:
does not need to match both properties for the firewall to apply. Only IPv4 is supported. does not need to match both properties for the firewall to apply. Only IPv4 is supported.
returned: success returned: success
type: list type: list
source_tags: sourceServiceAccounts:
description:
- If source service accounts are specified, the firewall will apply only to traffic
originating from an instance with a service account in this list. Source service
accounts cannot be used to control traffic to an instance's external IP address
because service accounts are associated with an instance, not an IP address. sourceRanges
can be set at the same time as sourceServiceAccounts. If both are set, the firewall
will apply to traffic that has source IP address within sourceRanges OR the source
IP belongs to an instance with service account listed in sourceServiceAccount. The
connection does not need to match both properties for the firewall to apply. sourceServiceAccounts
cannot be used at the same time as sourceTags or targetTags.
returned: success
type: list
sourceTags:
description: description:
- If source tags are specified, the firewall will apply only to traffic with source - If source tags are specified, the firewall will apply only to traffic with source
IP that belongs to a tag listed in source tags. Source tags cannot be used to control IP that belongs to a tag listed in source tags. Source tags cannot be used to control
@ -147,7 +213,16 @@ items:
firewall to apply. firewall to apply.
returned: success returned: success
type: list type: list
target_tags: targetServiceAccounts:
description:
- A list of service accounts indicating sets of instances located in the network that
may make network connections as specified in allowed[].
- targetServiceAccounts cannot be used at the same time as targetTags or sourceTags.
If neither targetServiceAccounts nor targetTags are specified, the firewall rule
applies to all instances on the specified network.
returned: success
type: list
targetTags:
description: description:
- A list of instance tags indicating sets of instances located in the network that - A list of instance tags indicating sets of instances located in the network that
may make network connections as specified in allowed[]. may make network connections as specified in allowed[].
@ -171,7 +246,7 @@ import json
def main(): def main():
module = GcpModule( module = GcpModule(
argument_spec=dict( argument_spec=dict(
filters=dict(type='list', elements='str'), filters=dict(type='list', elements='str')
) )
) )

@ -85,6 +85,11 @@ options:
- A reference to a BackendService to receive the matched traffic. - A reference to a BackendService to receive the matched traffic.
- This is used for internal load balancing. - This is used for internal load balancing.
- "(not used for external load balancing) ." - "(not used for external load balancing) ."
- 'This field represents a link to a BackendService resource in GCP. It can be specified
in two ways. You can add `register: name-of-resource` to a gcp_compute_backend_service
task and then set this backend_service field to "{{ name-of-resource }}" Alternatively,
you can set this backend_service to a dictionary with the selfLink key where the
value is the selfLink of your BackendService.'
required: false required: false
ip_version: ip_version:
description: description:
@ -116,6 +121,11 @@ options:
IP should belong to for this Forwarding Rule. If this field is not specified, the IP should belong to for this Forwarding Rule. If this field is not specified, the
default network will be used. default network will be used.
- This field is not used for external load balancing. - This field is not used for external load balancing.
- 'This field represents a link to a Network resource in GCP. It can be specified
in two ways. You can add `register: name-of-resource` to a gcp_compute_network 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: false required: false
port_range: port_range:
description: description:
@ -147,6 +157,11 @@ options:
- If the network specified is in auto subnet mode, this field is optional. However, - If the network specified is in auto subnet mode, this field is optional. However,
if the network is in custom subnet mode, a subnetwork must be specified. if the network is in custom subnet mode, a subnetwork must be specified.
- This field is not used for external load balancing. - This field is not used for external load balancing.
- 'This field represents a link to a Subnetwork resource in GCP. It can be specified
in two ways. You can add `register: name-of-resource` to a gcp_compute_subnetwork
task and then set this subnetwork field to "{{ name-of-resource }}" Alternatively,
you can set this subnetwork to a dictionary with the selfLink key where the value
is the selfLink of your Subnetwork.'
required: false required: false
target: target:
description: description:
@ -155,8 +170,21 @@ options:
rule. For global forwarding rules, this target must be a global load balancing resource. rule. For global forwarding rules, this target must be a global load balancing resource.
The forwarded traffic must be of a type appropriate to the target object. The forwarded traffic must be of a type appropriate to the target object.
- This field is not used for internal load balancing. - This field is not used for internal load balancing.
- 'This field represents a link to a TargetPool resource in GCP. It can be specified
in two ways. You can add `register: name-of-resource` to a gcp_compute_target_pool
task and then set this target field to "{{ name-of-resource }}" Alternatively, you
can set this target to a dictionary with the selfLink key where the value is the
selfLink of your TargetPool.'
required: false required: false
version_added: 2.7 version_added: 2.7
network_tier:
description:
- 'The networking tier used for configuring this address. This field can take the
following values: PREMIUM or STANDARD. If this field is not specified, it is assumed
to be PREMIUM.'
required: false
version_added: 2.8
choices: ['PREMIUM', 'STANDARD']
region: region:
description: description:
- A reference to the region where the regional forwarding rule resides. - A reference to the region where the regional forwarding rule resides.
@ -198,13 +226,13 @@ EXAMPLES = '''
port_range: 80-80 port_range: 80-80
ip_address: "{{ address.address }}" ip_address: "{{ address.address }}"
project: "test_project" project: "test_project"
auth_kind: "service_account" auth_kind: "serviceaccount"
service_account_file: "/tmp/auth.pem" service_account_file: "/tmp/auth.pem"
state: present state: present
''' '''
RETURN = ''' RETURN = '''
creation_timestamp: creationTimestamp:
description: description:
- Creation timestamp in RFC3339 text format. - Creation timestamp in RFC3339 text format.
returned: success returned: success
@ -220,7 +248,7 @@ RETURN = '''
- The unique identifier for the resource. - The unique identifier for the resource.
returned: success returned: success
type: int type: int
ip_address: IPAddress:
description: description:
- The IP address that this forwarding rule is serving on behalf of. - The IP address that this forwarding rule is serving on behalf of.
- Addresses are restricted based on the forwarding rule's load balancing scheme (EXTERNAL - Addresses are restricted based on the forwarding rule's load balancing scheme (EXTERNAL
@ -241,27 +269,27 @@ RETURN = '''
* global/addresses/address * address .' * global/addresses/address * address .'
returned: success returned: success
type: str type: str
ip_protocol: IPProtocol:
description: description:
- The IP protocol to which this rule applies. Valid options are TCP, UDP, ESP, AH, - The IP protocol to which this rule applies. Valid options are TCP, UDP, ESP, AH,
SCTP or ICMP. SCTP or ICMP.
- When the load balancing scheme is INTERNAL, only TCP and UDP are valid. - When the load balancing scheme is INTERNAL, only TCP and UDP are valid.
returned: success returned: success
type: str type: str
backend_service: backendService:
description: description:
- A reference to a BackendService to receive the matched traffic. - A reference to a BackendService to receive the matched traffic.
- This is used for internal load balancing. - This is used for internal load balancing.
- "(not used for external load balancing) ." - "(not used for external load balancing) ."
returned: success returned: success
type: dict type: dict
ip_version: ipVersion:
description: description:
- The IP Version that will be used by this forwarding rule. Valid options are IPV4 - The IP Version that will be used by this forwarding rule. Valid options are IPV4
or IPV6. This can only be specified for a global forwarding rule. or IPV6. This can only be specified for a global forwarding rule.
returned: success returned: success
type: str type: str
load_balancing_scheme: loadBalancingScheme:
description: description:
- 'This signifies what the ForwardingRule will be used for and can only take the following - 'This signifies what the ForwardingRule will be used for and can only take the following
values: INTERNAL, EXTERNAL The value of INTERNAL means that this will be used for values: INTERNAL, EXTERNAL The value of INTERNAL means that this will be used for
@ -288,7 +316,7 @@ RETURN = '''
- This field is not used for external load balancing. - This field is not used for external load balancing.
returned: success returned: success
type: dict type: dict
port_range: portRange:
description: description:
- This field is used along with the target field for TargetHttpProxy, TargetHttpsProxy, - This field is used along with the target field for TargetHttpProxy, TargetHttpsProxy,
TargetSslProxy, TargetTcpProxy, TargetVpnGateway, TargetPool, TargetInstance. TargetSslProxy, TargetTcpProxy, TargetVpnGateway, TargetPool, TargetInstance.
@ -331,6 +359,19 @@ RETURN = '''
- This field is not used for internal load balancing. - This field is not used for internal load balancing.
returned: success returned: success
type: dict type: dict
labelFingerprint:
description:
- The fingerprint used for optimistic locking of this resource. Used internally during
updates.
returned: success
type: str
networkTier:
description:
- 'The networking tier used for configuring this address. This field can take the
following values: PREMIUM or STANDARD. If this field is not specified, it is assumed
to be PREMIUM.'
returned: success
type: str
region: region:
description: description:
- A reference to the region where the regional forwarding rule resides. - A reference to the region where the regional forwarding rule resides.
@ -370,6 +411,7 @@ def main():
ports=dict(type='list', elements='str'), ports=dict(type='list', elements='str'),
subnetwork=dict(type='dict'), subnetwork=dict(type='dict'),
target=dict(type='dict'), target=dict(type='dict'),
network_tier=dict(type='str', choices=['PREMIUM', 'STANDARD']),
region=dict(required=True, type='str') region=dict(required=True, type='str')
) )
) )
@ -386,7 +428,8 @@ def main():
if fetch: if fetch:
if state == 'present': if state == 'present':
if is_different(module, fetch): if is_different(module, fetch):
fetch = update(module, self_link(module), kind) update(module, self_link(module), kind, fetch)
fetch = fetch_resource(module, self_link(module), kind)
changed = True changed = True
else: else:
delete(module, self_link(module), kind) delete(module, self_link(module), kind)
@ -409,9 +452,41 @@ def create(module, link, kind):
return wait_for_operation(module, auth.post(link, resource_to_request(module))) return wait_for_operation(module, auth.post(link, resource_to_request(module)))
def update(module, link, kind): 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('target') != request.get('target'):
target_update(module, request, response)
def target_update(module, request, response):
auth = GcpSession(module, 'compute')
auth.post(
''.join([
"https://www.googleapis.com/compute/v1/",
"projects/{project}/regions/{region}/forwardingRules/{name}/setTarget"
]).format(**module.params),
{
u'target': replace_resource_dict(module.params.get(u'target', {}), 'selfLink')
}
)
def label_fingerprint_update(module, request, response):
auth = GcpSession(module, 'compute') auth = GcpSession(module, 'compute')
return wait_for_operation(module, auth.put(link, resource_to_request(module))) auth.post(
''.join([
"https://www.googleapis.com/compute/v1/",
"projects/{project}/regions/{region}/forwardingRules/{name}/setLabels"
]).format(**module.params),
{
u'labelFingerprint': response.get('labelFingerprint')
}
)
def delete(module, link, kind): def delete(module, link, kind):
@ -433,7 +508,8 @@ def resource_to_request(module):
u'portRange': module.params.get('port_range'), u'portRange': module.params.get('port_range'),
u'ports': module.params.get('ports'), u'ports': module.params.get('ports'),
u'subnetwork': replace_resource_dict(module.params.get(u'subnetwork', {}), 'selfLink'), u'subnetwork': replace_resource_dict(module.params.get(u'subnetwork', {}), 'selfLink'),
u'target': replace_resource_dict(module.params.get(u'target', {}), 'selfLink') u'target': replace_resource_dict(module.params.get(u'target', {}), 'selfLink'),
u'networkTier': module.params.get('network_tier')
} }
return_vals = {} return_vals = {}
for k, v in request.items(): for k, v in request.items():
@ -443,9 +519,9 @@ def resource_to_request(module):
return return_vals return return_vals
def fetch_resource(module, link, kind): def fetch_resource(module, link, kind, allow_not_found=True):
auth = GcpSession(module, 'compute') auth = GcpSession(module, 'compute')
return return_if_object(module, auth.get(link), kind) return return_if_object(module, auth.get(link), kind, allow_not_found)
def self_link(module): def self_link(module):
@ -456,9 +532,9 @@ def collection(module):
return "https://www.googleapis.com/compute/v1/projects/{project}/regions/{region}/forwardingRules".format(**module.params) return "https://www.googleapis.com/compute/v1/projects/{project}/regions/{region}/forwardingRules".format(**module.params)
def return_if_object(module, response, kind): def return_if_object(module, response, kind, allow_not_found=False):
# If not found, return nothing. # If not found, return nothing.
if response.status_code == 404: if allow_not_found and response.status_code == 404:
return None return None
# If no content, return nothing. # If no content, return nothing.
@ -473,8 +549,6 @@ def return_if_object(module, response, kind):
if navigate_hash(result, ['error', 'errors']): if navigate_hash(result, ['error', 'errors']):
module.fail_json(msg=navigate_hash(result, ['error', 'errors'])) module.fail_json(msg=navigate_hash(result, ['error', 'errors']))
if result['kind'] != kind:
module.fail_json(msg="Incorrect result: {kind}".format(**result))
return result return result
@ -514,7 +588,9 @@ def response_to_hash(module, response):
u'portRange': response.get(u'portRange'), u'portRange': response.get(u'portRange'),
u'ports': response.get(u'ports'), u'ports': response.get(u'ports'),
u'subnetwork': response.get(u'subnetwork'), u'subnetwork': response.get(u'subnetwork'),
u'target': response.get(u'target') u'target': response.get(u'target'),
u'labelFingerprint': response.get(u'labelFingerprint'),
u'networkTier': module.params.get('network_tier')
} }

@ -62,7 +62,7 @@ EXAMPLES = '''
filters: filters:
- name = test_object - name = test_object
project: test_project project: test_project
auth_kind: service_account auth_kind: serviceaccount
service_account_file: "/tmp/auth.pem" service_account_file: "/tmp/auth.pem"
''' '''
@ -72,7 +72,7 @@ items:
returned: always returned: always
type: complex type: complex
contains: contains:
creation_timestamp: creationTimestamp:
description: description:
- Creation timestamp in RFC3339 text format. - Creation timestamp in RFC3339 text format.
returned: success returned: success
@ -88,7 +88,7 @@ items:
- The unique identifier for the resource. - The unique identifier for the resource.
returned: success returned: success
type: int type: int
ip_address: IPAddress:
description: description:
- The IP address that this forwarding rule is serving on behalf of. - The IP address that this forwarding rule is serving on behalf of.
- Addresses are restricted based on the forwarding rule's load balancing scheme (EXTERNAL - Addresses are restricted based on the forwarding rule's load balancing scheme (EXTERNAL
@ -109,27 +109,27 @@ items:
* global/addresses/address * address .' * global/addresses/address * address .'
returned: success returned: success
type: str type: str
ip_protocol: IPProtocol:
description: description:
- The IP protocol to which this rule applies. Valid options are TCP, UDP, ESP, AH, - The IP protocol to which this rule applies. Valid options are TCP, UDP, ESP, AH,
SCTP or ICMP. SCTP or ICMP.
- When the load balancing scheme is INTERNAL, only TCP and UDP are valid. - When the load balancing scheme is INTERNAL, only TCP and UDP are valid.
returned: success returned: success
type: str type: str
backend_service: backendService:
description: description:
- A reference to a BackendService to receive the matched traffic. - A reference to a BackendService to receive the matched traffic.
- This is used for internal load balancing. - This is used for internal load balancing.
- "(not used for external load balancing) ." - "(not used for external load balancing) ."
returned: success returned: success
type: dict type: dict
ip_version: ipVersion:
description: description:
- The IP Version that will be used by this forwarding rule. Valid options are IPV4 - The IP Version that will be used by this forwarding rule. Valid options are IPV4
or IPV6. This can only be specified for a global forwarding rule. or IPV6. This can only be specified for a global forwarding rule.
returned: success returned: success
type: str type: str
load_balancing_scheme: loadBalancingScheme:
description: description:
- 'This signifies what the ForwardingRule will be used for and can only take the following - 'This signifies what the ForwardingRule will be used for and can only take the following
values: INTERNAL, EXTERNAL The value of INTERNAL means that this will be used for values: INTERNAL, EXTERNAL The value of INTERNAL means that this will be used for
@ -156,7 +156,7 @@ items:
- This field is not used for external load balancing. - This field is not used for external load balancing.
returned: success returned: success
type: dict type: dict
port_range: portRange:
description: description:
- This field is used along with the target field for TargetHttpProxy, TargetHttpsProxy, - This field is used along with the target field for TargetHttpProxy, TargetHttpsProxy,
TargetSslProxy, TargetTcpProxy, TargetVpnGateway, TargetPool, TargetInstance. TargetSslProxy, TargetTcpProxy, TargetVpnGateway, TargetPool, TargetInstance.
@ -199,6 +199,19 @@ items:
- This field is not used for internal load balancing. - This field is not used for internal load balancing.
returned: success returned: success
type: dict type: dict
labelFingerprint:
description:
- The fingerprint used for optimistic locking of this resource. Used internally during
updates.
returned: success
type: str
networkTier:
description:
- 'The networking tier used for configuring this address. This field can take the
following values: PREMIUM or STANDARD. If this field is not specified, it is assumed
to be PREMIUM.'
returned: success
type: str
region: region:
description: description:
- A reference to the region where the regional forwarding rule resides. - A reference to the region where the regional forwarding rule resides.

@ -67,6 +67,15 @@ options:
The default value is IPV4. The default value is IPV4.
required: false required: false
choices: ['IPV4', 'IPV6'] choices: ['IPV4', 'IPV6']
address_type:
description:
- The type of the address to reserve, default is EXTERNAL.
- "* EXTERNAL indicates public/external single IP address."
- "* INTERNAL indicates internal IP ranges belonging to some network."
required: false
default: EXTERNAL
version_added: 2.8
choices: ['EXTERNAL', 'INTERNAL']
extends_documentation_fragment: gcp extends_documentation_fragment: gcp
notes: notes:
- "API Reference: U(https://cloud.google.com/compute/docs/reference/latest/globalAddresses)" - "API Reference: U(https://cloud.google.com/compute/docs/reference/latest/globalAddresses)"
@ -78,7 +87,7 @@ EXAMPLES = '''
gcp_compute_global_address: gcp_compute_global_address:
name: "test_object" name: "test_object"
project: "test_project" project: "test_project"
auth_kind: "service_account" auth_kind: "serviceaccount"
service_account_file: "/tmp/auth.pem" service_account_file: "/tmp/auth.pem"
state: present state: present
''' '''
@ -89,7 +98,7 @@ RETURN = '''
- The static external IP address represented by this resource. - The static external IP address represented by this resource.
returned: success returned: success
type: str type: str
creation_timestamp: creationTimestamp:
description: description:
- Creation timestamp in RFC3339 text format. - Creation timestamp in RFC3339 text format.
returned: success returned: success
@ -115,7 +124,13 @@ RETURN = '''
be a dash. be a dash.
returned: success returned: success
type: str type: str
ip_version: labelFingerprint:
description:
- The fingerprint used for optimistic locking of this resource. Used internally during
updates.
returned: success
type: str
ipVersion:
description: description:
- The IP Version that will be used by this address. Valid options are IPV4 or IPV6. - The IP Version that will be used by this address. Valid options are IPV4 or IPV6.
The default value is IPV4. The default value is IPV4.
@ -126,6 +141,13 @@ RETURN = '''
- A reference to the region where the regional address resides. - A reference to the region where the regional address resides.
returned: success returned: success
type: str type: str
addressType:
description:
- The type of the address to reserve, default is EXTERNAL.
- "* EXTERNAL indicates public/external single IP address."
- "* INTERNAL indicates internal IP ranges belonging to some network."
returned: success
type: str
''' '''
################################################################################ ################################################################################
@ -150,7 +172,8 @@ def main():
state=dict(default='present', choices=['present', 'absent'], type='str'), state=dict(default='present', choices=['present', 'absent'], type='str'),
description=dict(type='str'), description=dict(type='str'),
name=dict(required=True, type='str'), name=dict(required=True, type='str'),
ip_version=dict(type='str', choices=['IPV4', 'IPV6']) ip_version=dict(type='str', choices=['IPV4', 'IPV6']),
address_type=dict(default='EXTERNAL', type='str', choices=['EXTERNAL', 'INTERNAL'])
) )
) )
@ -166,7 +189,8 @@ def main():
if fetch: if fetch:
if state == 'present': if state == 'present':
if is_different(module, fetch): if is_different(module, fetch):
fetch = update(module, self_link(module), kind) update(module, self_link(module), kind, fetch)
fetch = fetch_resource(module, self_link(module), kind)
changed = True changed = True
else: else:
delete(module, self_link(module), kind) delete(module, self_link(module), kind)
@ -189,9 +213,27 @@ def create(module, link, kind):
return wait_for_operation(module, auth.post(link, resource_to_request(module))) return wait_for_operation(module, auth.post(link, resource_to_request(module)))
def update(module, link, kind): 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):
pass
def label_fingerprint_update(module, request, response):
auth = GcpSession(module, 'compute') auth = GcpSession(module, 'compute')
return wait_for_operation(module, auth.put(link, resource_to_request(module))) auth.post(
''.join([
"https://www.googleapis.com/compute/v1/",
"projects/{project}/global/addresses/{name}/setLabels"
]).format(**module.params),
{
u'labelFingerprint': response.get('labelFingerprint')
}
)
def delete(module, link, kind): def delete(module, link, kind):
@ -204,7 +246,8 @@ def resource_to_request(module):
u'kind': 'compute#address', u'kind': 'compute#address',
u'description': module.params.get('description'), u'description': module.params.get('description'),
u'name': module.params.get('name'), u'name': module.params.get('name'),
u'ipVersion': module.params.get('ip_version') u'ipVersion': module.params.get('ip_version'),
u'addressType': module.params.get('address_type')
} }
return_vals = {} return_vals = {}
for k, v in request.items(): for k, v in request.items():
@ -214,9 +257,9 @@ def resource_to_request(module):
return return_vals return return_vals
def fetch_resource(module, link, kind): def fetch_resource(module, link, kind, allow_not_found=True):
auth = GcpSession(module, 'compute') auth = GcpSession(module, 'compute')
return return_if_object(module, auth.get(link), kind) return return_if_object(module, auth.get(link), kind, allow_not_found)
def self_link(module): def self_link(module):
@ -227,9 +270,9 @@ def collection(module):
return "https://www.googleapis.com/compute/v1/projects/{project}/global/addresses".format(**module.params) return "https://www.googleapis.com/compute/v1/projects/{project}/global/addresses".format(**module.params)
def return_if_object(module, response, kind): def return_if_object(module, response, kind, allow_not_found=False):
# If not found, return nothing. # If not found, return nothing.
if response.status_code == 404: if allow_not_found and response.status_code == 404:
return None return None
# If no content, return nothing. # If no content, return nothing.
@ -244,8 +287,6 @@ def return_if_object(module, response, kind):
if navigate_hash(result, ['error', 'errors']): if navigate_hash(result, ['error', 'errors']):
module.fail_json(msg=navigate_hash(result, ['error', 'errors'])) module.fail_json(msg=navigate_hash(result, ['error', 'errors']))
if result['kind'] != kind:
module.fail_json(msg="Incorrect result: {kind}".format(**result))
return result return result
@ -277,8 +318,10 @@ def response_to_hash(module, response):
u'description': response.get(u'description'), u'description': response.get(u'description'),
u'id': response.get(u'id'), u'id': response.get(u'id'),
u'name': response.get(u'name'), u'name': response.get(u'name'),
u'labelFingerprint': response.get(u'labelFingerprint'),
u'ipVersion': response.get(u'ipVersion'), u'ipVersion': response.get(u'ipVersion'),
u'region': response.get(u'region') u'region': response.get(u'region'),
u'addressType': response.get(u'addressType')
} }

@ -56,7 +56,7 @@ EXAMPLES = '''
filters: filters:
- name = test_object - name = test_object
project: test_project project: test_project
auth_kind: service_account auth_kind: serviceaccount
service_account_file: "/tmp/auth.pem" service_account_file: "/tmp/auth.pem"
''' '''
@ -71,7 +71,7 @@ items:
- The static external IP address represented by this resource. - The static external IP address represented by this resource.
returned: success returned: success
type: str type: str
creation_timestamp: creationTimestamp:
description: description:
- Creation timestamp in RFC3339 text format. - Creation timestamp in RFC3339 text format.
returned: success returned: success
@ -97,7 +97,13 @@ items:
be a dash. be a dash.
returned: success returned: success
type: str type: str
ip_version: labelFingerprint:
description:
- The fingerprint used for optimistic locking of this resource. Used internally during
updates.
returned: success
type: str
ipVersion:
description: description:
- The IP Version that will be used by this address. Valid options are IPV4 or IPV6. - The IP Version that will be used by this address. Valid options are IPV4 or IPV6.
The default value is IPV4. The default value is IPV4.
@ -108,6 +114,13 @@ items:
- A reference to the region where the regional address resides. - A reference to the region where the regional address resides.
returned: success returned: success
type: str type: str
addressType:
description:
- The type of the address to reserve, default is EXTERNAL.
- "* EXTERNAL indicates public/external single IP address."
- "* INTERNAL indicates internal IP ranges belonging to some network."
returned: success
type: str
''' '''
################################################################################ ################################################################################
@ -124,7 +137,7 @@ import json
def main(): def main():
module = GcpModule( module = GcpModule(
argument_spec=dict( argument_spec=dict(
filters=dict(type='list', elements='str'), filters=dict(type='list', elements='str')
) )
) )

@ -87,6 +87,11 @@ options:
- A reference to a BackendService to receive the matched traffic. - A reference to a BackendService to receive the matched traffic.
- This is used for internal load balancing. - This is used for internal load balancing.
- "(not used for external load balancing) ." - "(not used for external load balancing) ."
- 'This field represents a link to a BackendService resource in GCP. It can be specified
in two ways. You can add `register: name-of-resource` to a gcp_compute_backend_service
task and then set this backend_service field to "{{ name-of-resource }}" Alternatively,
you can set this backend_service to a dictionary with the selfLink key where the
value is the selfLink of your BackendService.'
required: false required: false
ip_version: ip_version:
description: description:
@ -118,6 +123,11 @@ options:
IP should belong to for this Forwarding Rule. If this field is not specified, the IP should belong to for this Forwarding Rule. If this field is not specified, the
default network will be used. default network will be used.
- This field is not used for external load balancing. - This field is not used for external load balancing.
- 'This field represents a link to a Network resource in GCP. It can be specified
in two ways. You can add `register: name-of-resource` to a gcp_compute_network 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: false required: false
port_range: port_range:
description: description:
@ -149,6 +159,11 @@ options:
- If the network specified is in auto subnet mode, this field is optional. However, - If the network specified is in auto subnet mode, this field is optional. However,
if the network is in custom subnet mode, a subnetwork must be specified. if the network is in custom subnet mode, a subnetwork must be specified.
- This field is not used for external load balancing. - This field is not used for external load balancing.
- 'This field represents a link to a Subnetwork resource in GCP. It can be specified
in two ways. You can add `register: name-of-resource` to a gcp_compute_subnetwork
task and then set this subnetwork field to "{{ name-of-resource }}" Alternatively,
you can set this subnetwork to a dictionary with the selfLink key where the value
is the selfLink of your Subnetwork.'
required: false required: false
target: target:
description: description:
@ -234,13 +249,13 @@ EXAMPLES = '''
port_range: 80-80 port_range: 80-80
target: "{{ httpproxy.selfLink }}" target: "{{ httpproxy.selfLink }}"
project: "test_project" project: "test_project"
auth_kind: "service_account" auth_kind: "serviceaccount"
service_account_file: "/tmp/auth.pem" service_account_file: "/tmp/auth.pem"
state: present state: present
''' '''
RETURN = ''' RETURN = '''
creation_timestamp: creationTimestamp:
description: description:
- Creation timestamp in RFC3339 text format. - Creation timestamp in RFC3339 text format.
returned: success returned: success
@ -256,7 +271,7 @@ RETURN = '''
- The unique identifier for the resource. - The unique identifier for the resource.
returned: success returned: success
type: int type: int
ip_address: IPAddress:
description: description:
- The IP address that this forwarding rule is serving on behalf of. - The IP address that this forwarding rule is serving on behalf of.
- Addresses are restricted based on the forwarding rule's load balancing scheme (EXTERNAL - Addresses are restricted based on the forwarding rule's load balancing scheme (EXTERNAL
@ -277,27 +292,27 @@ RETURN = '''
* global/addresses/address * address .' * global/addresses/address * address .'
returned: success returned: success
type: str type: str
ip_protocol: IPProtocol:
description: description:
- The IP protocol to which this rule applies. Valid options are TCP, UDP, ESP, AH, - The IP protocol to which this rule applies. Valid options are TCP, UDP, ESP, AH,
SCTP or ICMP. SCTP or ICMP.
- When the load balancing scheme is INTERNAL, only TCP and UDP are valid. - When the load balancing scheme is INTERNAL, only TCP and UDP are valid.
returned: success returned: success
type: str type: str
backend_service: backendService:
description: description:
- A reference to a BackendService to receive the matched traffic. - A reference to a BackendService to receive the matched traffic.
- This is used for internal load balancing. - This is used for internal load balancing.
- "(not used for external load balancing) ." - "(not used for external load balancing) ."
returned: success returned: success
type: dict type: dict
ip_version: ipVersion:
description: description:
- The IP Version that will be used by this forwarding rule. Valid options are IPV4 - The IP Version that will be used by this forwarding rule. Valid options are IPV4
or IPV6. This can only be specified for a global forwarding rule. or IPV6. This can only be specified for a global forwarding rule.
returned: success returned: success
type: str type: str
load_balancing_scheme: loadBalancingScheme:
description: description:
- 'This signifies what the ForwardingRule will be used for and can only take the following - 'This signifies what the ForwardingRule will be used for and can only take the following
values: INTERNAL, EXTERNAL The value of INTERNAL means that this will be used for values: INTERNAL, EXTERNAL The value of INTERNAL means that this will be used for
@ -324,7 +339,7 @@ RETURN = '''
- This field is not used for external load balancing. - This field is not used for external load balancing.
returned: success returned: success
type: dict type: dict
port_range: portRange:
description: description:
- This field is used along with the target field for TargetHttpProxy, TargetHttpsProxy, - This field is used along with the target field for TargetHttpProxy, TargetHttpsProxy,
TargetSslProxy, TargetTcpProxy, TargetVpnGateway, TargetPool, TargetInstance. TargetSslProxy, TargetTcpProxy, TargetVpnGateway, TargetPool, TargetInstance.
@ -419,7 +434,8 @@ def main():
if fetch: if fetch:
if state == 'present': if state == 'present':
if is_different(module, fetch): if is_different(module, fetch):
fetch = update(module, self_link(module), kind) update(module, self_link(module), kind)
fetch = fetch_resource(module, self_link(module), kind)
changed = True changed = True
else: else:
delete(module, self_link(module), kind) delete(module, self_link(module), kind)
@ -476,9 +492,9 @@ def resource_to_request(module):
return return_vals return return_vals
def fetch_resource(module, link, kind): def fetch_resource(module, link, kind, allow_not_found=True):
auth = GcpSession(module, 'compute') auth = GcpSession(module, 'compute')
return return_if_object(module, auth.get(link), kind) return return_if_object(module, auth.get(link), kind, allow_not_found)
def self_link(module): def self_link(module):
@ -489,9 +505,9 @@ def collection(module):
return "https://www.googleapis.com/compute/v1/projects/{project}/global/forwardingRules".format(**module.params) return "https://www.googleapis.com/compute/v1/projects/{project}/global/forwardingRules".format(**module.params)
def return_if_object(module, response, kind): def return_if_object(module, response, kind, allow_not_found=False):
# If not found, return nothing. # If not found, return nothing.
if response.status_code == 404: if allow_not_found and response.status_code == 404:
return None return None
# If no content, return nothing. # If no content, return nothing.
@ -506,8 +522,6 @@ def return_if_object(module, response, kind):
if navigate_hash(result, ['error', 'errors']): if navigate_hash(result, ['error', 'errors']):
module.fail_json(msg=navigate_hash(result, ['error', 'errors'])) module.fail_json(msg=navigate_hash(result, ['error', 'errors']))
if result['kind'] != kind:
module.fail_json(msg="Incorrect result: {kind}".format(**result))
return result return result

@ -56,7 +56,7 @@ EXAMPLES = '''
filters: filters:
- name = test_object - name = test_object
project: test_project project: test_project
auth_kind: service_account auth_kind: serviceaccount
service_account_file: "/tmp/auth.pem" service_account_file: "/tmp/auth.pem"
''' '''
@ -66,7 +66,7 @@ items:
returned: always returned: always
type: complex type: complex
contains: contains:
creation_timestamp: creationTimestamp:
description: description:
- Creation timestamp in RFC3339 text format. - Creation timestamp in RFC3339 text format.
returned: success returned: success
@ -82,7 +82,7 @@ items:
- The unique identifier for the resource. - The unique identifier for the resource.
returned: success returned: success
type: int type: int
ip_address: IPAddress:
description: description:
- The IP address that this forwarding rule is serving on behalf of. - The IP address that this forwarding rule is serving on behalf of.
- Addresses are restricted based on the forwarding rule's load balancing scheme (EXTERNAL - Addresses are restricted based on the forwarding rule's load balancing scheme (EXTERNAL
@ -103,27 +103,27 @@ items:
* global/addresses/address * address .' * global/addresses/address * address .'
returned: success returned: success
type: str type: str
ip_protocol: IPProtocol:
description: description:
- The IP protocol to which this rule applies. Valid options are TCP, UDP, ESP, AH, - The IP protocol to which this rule applies. Valid options are TCP, UDP, ESP, AH,
SCTP or ICMP. SCTP or ICMP.
- When the load balancing scheme is INTERNAL, only TCP and UDP are valid. - When the load balancing scheme is INTERNAL, only TCP and UDP are valid.
returned: success returned: success
type: str type: str
backend_service: backendService:
description: description:
- A reference to a BackendService to receive the matched traffic. - A reference to a BackendService to receive the matched traffic.
- This is used for internal load balancing. - This is used for internal load balancing.
- "(not used for external load balancing) ." - "(not used for external load balancing) ."
returned: success returned: success
type: dict type: dict
ip_version: ipVersion:
description: description:
- The IP Version that will be used by this forwarding rule. Valid options are IPV4 - The IP Version that will be used by this forwarding rule. Valid options are IPV4
or IPV6. This can only be specified for a global forwarding rule. or IPV6. This can only be specified for a global forwarding rule.
returned: success returned: success
type: str type: str
load_balancing_scheme: loadBalancingScheme:
description: description:
- 'This signifies what the ForwardingRule will be used for and can only take the following - 'This signifies what the ForwardingRule will be used for and can only take the following
values: INTERNAL, EXTERNAL The value of INTERNAL means that this will be used for values: INTERNAL, EXTERNAL The value of INTERNAL means that this will be used for
@ -150,7 +150,7 @@ items:
- This field is not used for external load balancing. - This field is not used for external load balancing.
returned: success returned: success
type: dict type: dict
port_range: portRange:
description: description:
- This field is used along with the target field for TargetHttpProxy, TargetHttpsProxy, - This field is used along with the target field for TargetHttpProxy, TargetHttpsProxy,
TargetSslProxy, TargetTcpProxy, TargetVpnGateway, TargetPool, TargetInstance. TargetSslProxy, TargetTcpProxy, TargetVpnGateway, TargetPool, TargetInstance.
@ -213,7 +213,7 @@ import json
def main(): def main():
module = GcpModule( module = GcpModule(
argument_spec=dict( argument_spec=dict(
filters=dict(type='list', elements='str'), filters=dict(type='list', elements='str')
) )
) )

@ -32,8 +32,15 @@ DOCUMENTATION = '''
--- ---
module: gcp_compute_health_check module: gcp_compute_health_check
description: description:
- An HealthCheck resource. This resource defines a template for how individual virtual - Health Checks determine whether instances are responsive and able to do work.
machines should be checked for health, via one of the supported protocols. - They are an important part of a comprehensive load balancing configuration, as they
enable monitoring instances behind load balancers.
- Health Checks poll instances at a specified interval. Instances that do not respond
successfully to some number of probes in a row are marked as unhealthy. No new connections
are sent to unhealthy instances, though existing connections will continue. The
health check will continue to poll unhealthy instances. If an instance later responds
successfully to some number of consecutive probes, it is marked healthy again and
can receive new connections.
short_description: Creates a GCP HealthCheck short_description: Creates a GCP HealthCheck
version_added: 2.6 version_added: 2.6
author: Google Inc. (@googlecloudplatform) author: Google Inc. (@googlecloudplatform)
@ -62,6 +69,7 @@ options:
- A so-far unhealthy instance will be marked healthy after this many consecutive successes. - A so-far unhealthy instance will be marked healthy after this many consecutive successes.
The default value is 2. The default value is 2.
required: false required: false
default: 2
name: name:
description: description:
- Name of the resource. Provided by the client when the resource is created. The name - Name of the resource. Provided by the client when the resource is created. The name
@ -70,7 +78,7 @@ options:
which means the first character must be a lowercase letter, and all following characters which means the first character must be a lowercase letter, and all following characters
must be a dash, lowercase letter, or digit, except the last character, which cannot must be a dash, lowercase letter, or digit, except the last character, which cannot
be a dash. be a dash.
required: false required: true
timeout_sec: timeout_sec:
description: description:
- How long (in seconds) to wait before claiming failure. - How long (in seconds) to wait before claiming failure.
@ -91,7 +99,7 @@ options:
the default is TCP. Exactly one of the protocol-specific health check field must the default is TCP. Exactly one of the protocol-specific health check field must
be specified, which must match type field. be specified, which must match type field.
required: false required: false
choices: ['TCP', 'SSL', 'HTTP'] choices: ['TCP', 'SSL', 'HTTP', 'HTTPS']
http_health_check: http_health_check:
description: description:
- A nested object resource. - A nested object resource.
@ -108,6 +116,7 @@ options:
- The request path of the HTTP health check request. - The request path of the HTTP health check request.
- The default value is /. - The default value is /.
required: false required: false
default: /
port: port:
description: description:
- The TCP port number for the HTTP health check request. - The TCP port number for the HTTP health check request.
@ -123,6 +132,7 @@ options:
- Specifies the type of proxy header to append before sending data to the backend, - Specifies the type of proxy header to append before sending data to the backend,
either NONE or PROXY_V1. The default is NONE. either NONE or PROXY_V1. The default is NONE.
required: false required: false
default: NONE
choices: ['NONE', 'PROXY_V1'] choices: ['NONE', 'PROXY_V1']
https_health_check: https_health_check:
description: description:
@ -140,6 +150,7 @@ options:
- The request path of the HTTPS health check request. - The request path of the HTTPS health check request.
- The default value is /. - The default value is /.
required: false required: false
default: /
port: port:
description: description:
- The TCP port number for the HTTPS health check request. - The TCP port number for the HTTPS health check request.
@ -155,6 +166,7 @@ options:
- Specifies the type of proxy header to append before sending data to the backend, - Specifies the type of proxy header to append before sending data to the backend,
either NONE or PROXY_V1. The default is NONE. either NONE or PROXY_V1. The default is NONE.
required: false required: false
default: NONE
choices: ['NONE', 'PROXY_V1'] choices: ['NONE', 'PROXY_V1']
tcp_health_check: tcp_health_check:
description: description:
@ -188,6 +200,7 @@ options:
- Specifies the type of proxy header to append before sending data to the backend, - Specifies the type of proxy header to append before sending data to the backend,
either NONE or PROXY_V1. The default is NONE. either NONE or PROXY_V1. The default is NONE.
required: false required: false
default: NONE
choices: ['NONE', 'PROXY_V1'] choices: ['NONE', 'PROXY_V1']
ssl_health_check: ssl_health_check:
description: description:
@ -221,8 +234,12 @@ options:
- Specifies the type of proxy header to append before sending data to the backend, - Specifies the type of proxy header to append before sending data to the backend,
either NONE or PROXY_V1. The default is NONE. either NONE or PROXY_V1. The default is NONE.
required: false required: false
default: NONE
choices: ['NONE', 'PROXY_V1'] choices: ['NONE', 'PROXY_V1']
extends_documentation_fragment: gcp extends_documentation_fragment: gcp
notes:
- "API Reference: U(https://cloud.google.com/compute/docs/reference/rest/latest/healthChecks)"
- "Official Documentation: U(https://cloud.google.com/load-balancing/docs/health-checks)"
''' '''
EXAMPLES = ''' EXAMPLES = '''
@ -238,18 +255,18 @@ EXAMPLES = '''
timeout_sec: 2 timeout_sec: 2
unhealthy_threshold: 5 unhealthy_threshold: 5
project: "test_project" project: "test_project"
auth_kind: "service_account" auth_kind: "serviceaccount"
service_account_file: "/tmp/auth.pem" service_account_file: "/tmp/auth.pem"
state: present state: present
''' '''
RETURN = ''' RETURN = '''
check_interval_sec: checkIntervalSec:
description: description:
- How often (in seconds) to send a health check. The default value is 5 seconds. - How often (in seconds) to send a health check. The default value is 5 seconds.
returned: success returned: success
type: int type: int
creation_timestamp: creationTimestamp:
description: description:
- Creation timestamp in RFC3339 text format. - Creation timestamp in RFC3339 text format.
returned: success returned: success
@ -260,7 +277,7 @@ RETURN = '''
the resource. the resource.
returned: success returned: success
type: str type: str
healthy_threshold: healthyThreshold:
description: description:
- A so-far unhealthy instance will be marked healthy after this many consecutive successes. - A so-far unhealthy instance will be marked healthy after this many consecutive successes.
The default value is 2. The default value is 2.
@ -281,14 +298,14 @@ RETURN = '''
be a dash. be a dash.
returned: success returned: success
type: str type: str
timeout_sec: timeoutSec:
description: description:
- How long (in seconds) to wait before claiming failure. - How long (in seconds) to wait before claiming failure.
- The default value is 5 seconds. It is invalid for timeoutSec to have greater value - The default value is 5 seconds. It is invalid for timeoutSec to have greater value
than checkIntervalSec. than checkIntervalSec.
returned: success returned: success
type: int type: int
unhealthy_threshold: unhealthyThreshold:
description: description:
- A so-far healthy instance will be marked unhealthy after this many consecutive failures. - A so-far healthy instance will be marked unhealthy after this many consecutive failures.
The default value is 2. The default value is 2.
@ -301,7 +318,7 @@ RETURN = '''
be specified, which must match type field. be specified, which must match type field.
returned: success returned: success
type: str type: str
http_health_check: httpHealthCheck:
description: description:
- A nested object resource. - A nested object resource.
returned: success returned: success
@ -314,7 +331,7 @@ RETURN = '''
is performed will be used. is performed will be used.
returned: success returned: success
type: str type: str
request_path: requestPath:
description: description:
- The request path of the HTTP health check request. - The request path of the HTTP health check request.
- The default value is /. - The default value is /.
@ -326,19 +343,19 @@ RETURN = '''
- The default value is 80. - The default value is 80.
returned: success returned: success
type: int type: int
port_name: portName:
description: description:
- Port name as defined in InstanceGroup#NamedPort#name. If both port and port_name - Port name as defined in InstanceGroup#NamedPort#name. If both port and port_name
are defined, port takes precedence. are defined, port takes precedence.
returned: success returned: success
type: str type: str
proxy_header: proxyHeader:
description: description:
- Specifies the type of proxy header to append before sending data to the backend, - Specifies the type of proxy header to append before sending data to the backend,
either NONE or PROXY_V1. The default is NONE. either NONE or PROXY_V1. The default is NONE.
returned: success returned: success
type: str type: str
https_health_check: httpsHealthCheck:
description: description:
- A nested object resource. - A nested object resource.
returned: success returned: success
@ -351,7 +368,7 @@ RETURN = '''
is performed will be used. is performed will be used.
returned: success returned: success
type: str type: str
request_path: requestPath:
description: description:
- The request path of the HTTPS health check request. - The request path of the HTTPS health check request.
- The default value is /. - The default value is /.
@ -363,19 +380,19 @@ RETURN = '''
- The default value is 443. - The default value is 443.
returned: success returned: success
type: int type: int
port_name: portName:
description: description:
- Port name as defined in InstanceGroup#NamedPort#name. If both port and port_name - Port name as defined in InstanceGroup#NamedPort#name. If both port and port_name
are defined, port takes precedence. are defined, port takes precedence.
returned: success returned: success
type: str type: str
proxy_header: proxyHeader:
description: description:
- Specifies the type of proxy header to append before sending data to the backend, - Specifies the type of proxy header to append before sending data to the backend,
either NONE or PROXY_V1. The default is NONE. either NONE or PROXY_V1. The default is NONE.
returned: success returned: success
type: str type: str
tcp_health_check: tcpHealthCheck:
description: description:
- A nested object resource. - A nested object resource.
returned: success returned: success
@ -401,19 +418,19 @@ RETURN = '''
- The default value is 443. - The default value is 443.
returned: success returned: success
type: int type: int
port_name: portName:
description: description:
- Port name as defined in InstanceGroup#NamedPort#name. If both port and port_name - Port name as defined in InstanceGroup#NamedPort#name. If both port and port_name
are defined, port takes precedence. are defined, port takes precedence.
returned: success returned: success
type: str type: str
proxy_header: proxyHeader:
description: description:
- Specifies the type of proxy header to append before sending data to the backend, - Specifies the type of proxy header to append before sending data to the backend,
either NONE or PROXY_V1. The default is NONE. either NONE or PROXY_V1. The default is NONE.
returned: success returned: success
type: str type: str
ssl_health_check: sslHealthCheck:
description: description:
- A nested object resource. - A nested object resource.
returned: success returned: success
@ -439,13 +456,13 @@ RETURN = '''
- The default value is 443. - The default value is 443.
returned: success returned: success
type: int type: int
port_name: portName:
description: description:
- Port name as defined in InstanceGroup#NamedPort#name. If both port and port_name - Port name as defined in InstanceGroup#NamedPort#name. If both port and port_name
are defined, port takes precedence. are defined, port takes precedence.
returned: success returned: success
type: str type: str
proxy_header: proxyHeader:
description: description:
- Specifies the type of proxy header to append before sending data to the backend, - Specifies the type of proxy header to append before sending data to the backend,
either NONE or PROXY_V1. The default is NONE. either NONE or PROXY_V1. The default is NONE.
@ -474,38 +491,38 @@ def main():
state=dict(default='present', choices=['present', 'absent'], type='str'), state=dict(default='present', choices=['present', 'absent'], type='str'),
check_interval_sec=dict(default=5, type='int'), check_interval_sec=dict(default=5, type='int'),
description=dict(type='str'), description=dict(type='str'),
healthy_threshold=dict(type='int'), healthy_threshold=dict(default=2, type='int'),
name=dict(type='str'), name=dict(required=True, type='str'),
timeout_sec=dict(default=5, type='int', aliases=['timeout_seconds']), timeout_sec=dict(default=5, type='int', aliases=['timeout_seconds']),
unhealthy_threshold=dict(default=2, type='int'), unhealthy_threshold=dict(default=2, type='int'),
type=dict(type='str', choices=['TCP', 'SSL', 'HTTP']), type=dict(type='str', choices=['TCP', 'SSL', 'HTTP', 'HTTPS']),
http_health_check=dict(type='dict', options=dict( http_health_check=dict(type='dict', options=dict(
host=dict(type='str'), host=dict(type='str'),
request_path=dict(type='str'), request_path=dict(default='/', type='str'),
port=dict(type='int'), port=dict(type='int'),
port_name=dict(type='str'), port_name=dict(type='str'),
proxy_header=dict(type='str', choices=['NONE', 'PROXY_V1']) proxy_header=dict(default='NONE', type='str', choices=['NONE', 'PROXY_V1'])
)), )),
https_health_check=dict(type='dict', options=dict( https_health_check=dict(type='dict', options=dict(
host=dict(type='str'), host=dict(type='str'),
request_path=dict(type='str'), request_path=dict(default='/', type='str'),
port=dict(type='int'), port=dict(type='int'),
port_name=dict(type='str'), port_name=dict(type='str'),
proxy_header=dict(type='str', choices=['NONE', 'PROXY_V1']) proxy_header=dict(default='NONE', type='str', choices=['NONE', 'PROXY_V1'])
)), )),
tcp_health_check=dict(type='dict', options=dict( tcp_health_check=dict(type='dict', options=dict(
request=dict(type='str'), request=dict(type='str'),
response=dict(type='str'), response=dict(type='str'),
port=dict(type='int'), port=dict(type='int'),
port_name=dict(type='str'), port_name=dict(type='str'),
proxy_header=dict(type='str', choices=['NONE', 'PROXY_V1']) proxy_header=dict(default='NONE', type='str', choices=['NONE', 'PROXY_V1'])
)), )),
ssl_health_check=dict(type='dict', options=dict( ssl_health_check=dict(type='dict', options=dict(
request=dict(type='str'), request=dict(type='str'),
response=dict(type='str'), response=dict(type='str'),
port=dict(type='int'), port=dict(type='int'),
port_name=dict(type='str'), port_name=dict(type='str'),
proxy_header=dict(type='str', choices=['NONE', 'PROXY_V1']) proxy_header=dict(default='NONE', type='str', choices=['NONE', 'PROXY_V1'])
)) ))
) )
) )
@ -522,7 +539,8 @@ def main():
if fetch: if fetch:
if state == 'present': if state == 'present':
if is_different(module, fetch): if is_different(module, fetch):
fetch = update(module, self_link(module), kind) update(module, self_link(module), kind)
fetch = fetch_resource(module, self_link(module), kind)
changed = True changed = True
else: else:
delete(module, self_link(module), kind) delete(module, self_link(module), kind)
@ -578,9 +596,9 @@ def resource_to_request(module):
return return_vals return return_vals
def fetch_resource(module, link, kind): def fetch_resource(module, link, kind, allow_not_found=True):
auth = GcpSession(module, 'compute') auth = GcpSession(module, 'compute')
return return_if_object(module, auth.get(link), kind) return return_if_object(module, auth.get(link), kind, allow_not_found)
def self_link(module): def self_link(module):
@ -591,9 +609,9 @@ def collection(module):
return "https://www.googleapis.com/compute/v1/projects/{project}/global/healthChecks".format(**module.params) return "https://www.googleapis.com/compute/v1/projects/{project}/global/healthChecks".format(**module.params)
def return_if_object(module, response, kind): def return_if_object(module, response, kind, allow_not_found=False):
# If not found, return nothing. # If not found, return nothing.
if response.status_code == 404: if allow_not_found and response.status_code == 404:
return None return None
# If no content, return nothing. # If no content, return nothing.
@ -608,8 +626,6 @@ def return_if_object(module, response, kind):
if navigate_hash(result, ['error', 'errors']): if navigate_hash(result, ['error', 'errors']):
module.fail_json(msg=navigate_hash(result, ['error', 'errors'])) module.fail_json(msg=navigate_hash(result, ['error', 'errors']))
if result['kind'] != kind:
module.fail_json(msg="Incorrect result: {kind}".format(**result))
return result return result
@ -641,7 +657,7 @@ def response_to_hash(module, response):
u'description': response.get(u'description'), u'description': response.get(u'description'),
u'healthyThreshold': response.get(u'healthyThreshold'), u'healthyThreshold': response.get(u'healthyThreshold'),
u'id': response.get(u'id'), u'id': response.get(u'id'),
u'name': response.get(u'name'), u'name': module.params.get('name'),
u'timeoutSec': response.get(u'timeoutSec'), u'timeoutSec': response.get(u'timeoutSec'),
u'unhealthyThreshold': response.get(u'unhealthyThreshold'), u'unhealthyThreshold': response.get(u'unhealthyThreshold'),
u'type': response.get(u'type'), u'type': response.get(u'type'),

@ -56,7 +56,7 @@ EXAMPLES = '''
filters: filters:
- name = test_object - name = test_object
project: test_project project: test_project
auth_kind: service_account auth_kind: serviceaccount
service_account_file: "/tmp/auth.pem" service_account_file: "/tmp/auth.pem"
''' '''
@ -66,12 +66,12 @@ items:
returned: always returned: always
type: complex type: complex
contains: contains:
check_interval_sec: checkIntervalSec:
description: description:
- How often (in seconds) to send a health check. The default value is 5 seconds. - How often (in seconds) to send a health check. The default value is 5 seconds.
returned: success returned: success
type: int type: int
creation_timestamp: creationTimestamp:
description: description:
- Creation timestamp in RFC3339 text format. - Creation timestamp in RFC3339 text format.
returned: success returned: success
@ -82,7 +82,7 @@ items:
the resource. the resource.
returned: success returned: success
type: str type: str
healthy_threshold: healthyThreshold:
description: description:
- A so-far unhealthy instance will be marked healthy after this many consecutive successes. - A so-far unhealthy instance will be marked healthy after this many consecutive successes.
The default value is 2. The default value is 2.
@ -103,14 +103,14 @@ items:
be a dash. be a dash.
returned: success returned: success
type: str type: str
timeout_sec: timeoutSec:
description: description:
- How long (in seconds) to wait before claiming failure. - How long (in seconds) to wait before claiming failure.
- The default value is 5 seconds. It is invalid for timeoutSec to have greater value - The default value is 5 seconds. It is invalid for timeoutSec to have greater value
than checkIntervalSec. than checkIntervalSec.
returned: success returned: success
type: int type: int
unhealthy_threshold: unhealthyThreshold:
description: description:
- A so-far healthy instance will be marked unhealthy after this many consecutive failures. - A so-far healthy instance will be marked unhealthy after this many consecutive failures.
The default value is 2. The default value is 2.
@ -123,7 +123,7 @@ items:
be specified, which must match type field. be specified, which must match type field.
returned: success returned: success
type: str type: str
http_health_check: httpHealthCheck:
description: description:
- A nested object resource. - A nested object resource.
returned: success returned: success
@ -136,7 +136,7 @@ items:
is performed will be used. is performed will be used.
returned: success returned: success
type: str type: str
request_path: requestPath:
description: description:
- The request path of the HTTP health check request. - The request path of the HTTP health check request.
- The default value is /. - The default value is /.
@ -148,19 +148,19 @@ items:
- The default value is 80. - The default value is 80.
returned: success returned: success
type: int type: int
port_name: portName:
description: description:
- Port name as defined in InstanceGroup#NamedPort#name. If both port and port_name - Port name as defined in InstanceGroup#NamedPort#name. If both port and port_name
are defined, port takes precedence. are defined, port takes precedence.
returned: success returned: success
type: str type: str
proxy_header: proxyHeader:
description: description:
- Specifies the type of proxy header to append before sending data to the backend, - Specifies the type of proxy header to append before sending data to the backend,
either NONE or PROXY_V1. The default is NONE. either NONE or PROXY_V1. The default is NONE.
returned: success returned: success
type: str type: str
https_health_check: httpsHealthCheck:
description: description:
- A nested object resource. - A nested object resource.
returned: success returned: success
@ -173,7 +173,7 @@ items:
is performed will be used. is performed will be used.
returned: success returned: success
type: str type: str
request_path: requestPath:
description: description:
- The request path of the HTTPS health check request. - The request path of the HTTPS health check request.
- The default value is /. - The default value is /.
@ -185,19 +185,19 @@ items:
- The default value is 443. - The default value is 443.
returned: success returned: success
type: int type: int
port_name: portName:
description: description:
- Port name as defined in InstanceGroup#NamedPort#name. If both port and port_name - Port name as defined in InstanceGroup#NamedPort#name. If both port and port_name
are defined, port takes precedence. are defined, port takes precedence.
returned: success returned: success
type: str type: str
proxy_header: proxyHeader:
description: description:
- Specifies the type of proxy header to append before sending data to the backend, - Specifies the type of proxy header to append before sending data to the backend,
either NONE or PROXY_V1. The default is NONE. either NONE or PROXY_V1. The default is NONE.
returned: success returned: success
type: str type: str
tcp_health_check: tcpHealthCheck:
description: description:
- A nested object resource. - A nested object resource.
returned: success returned: success
@ -223,19 +223,19 @@ items:
- The default value is 443. - The default value is 443.
returned: success returned: success
type: int type: int
port_name: portName:
description: description:
- Port name as defined in InstanceGroup#NamedPort#name. If both port and port_name - Port name as defined in InstanceGroup#NamedPort#name. If both port and port_name
are defined, port takes precedence. are defined, port takes precedence.
returned: success returned: success
type: str type: str
proxy_header: proxyHeader:
description: description:
- Specifies the type of proxy header to append before sending data to the backend, - Specifies the type of proxy header to append before sending data to the backend,
either NONE or PROXY_V1. The default is NONE. either NONE or PROXY_V1. The default is NONE.
returned: success returned: success
type: str type: str
ssl_health_check: sslHealthCheck:
description: description:
- A nested object resource. - A nested object resource.
returned: success returned: success
@ -261,13 +261,13 @@ items:
- The default value is 443. - The default value is 443.
returned: success returned: success
type: int type: int
port_name: portName:
description: description:
- Port name as defined in InstanceGroup#NamedPort#name. If both port and port_name - Port name as defined in InstanceGroup#NamedPort#name. If both port and port_name
are defined, port takes precedence. are defined, port takes precedence.
returned: success returned: success
type: str type: str
proxy_header: proxyHeader:
description: description:
- Specifies the type of proxy header to append before sending data to the backend, - Specifies the type of proxy header to append before sending data to the backend,
either NONE or PROXY_V1. The default is NONE. either NONE or PROXY_V1. The default is NONE.
@ -289,7 +289,7 @@ import json
def main(): def main():
module = GcpModule( module = GcpModule(
argument_spec=dict( argument_spec=dict(
filters=dict(type='list', elements='str'), filters=dict(type='list', elements='str')
) )
) )

@ -115,18 +115,18 @@ EXAMPLES = '''
timeout_sec: 2 timeout_sec: 2
unhealthy_threshold: 5 unhealthy_threshold: 5
project: "test_project" project: "test_project"
auth_kind: "service_account" auth_kind: "serviceaccount"
service_account_file: "/tmp/auth.pem" service_account_file: "/tmp/auth.pem"
state: present state: present
''' '''
RETURN = ''' RETURN = '''
check_interval_sec: checkIntervalSec:
description: description:
- How often (in seconds) to send a health check. The default value is 5 seconds. - How often (in seconds) to send a health check. The default value is 5 seconds.
returned: success returned: success
type: int type: int
creation_timestamp: creationTimestamp:
description: description:
- Creation timestamp in RFC3339 text format. - Creation timestamp in RFC3339 text format.
returned: success returned: success
@ -137,7 +137,7 @@ RETURN = '''
the resource. the resource.
returned: success returned: success
type: str type: str
healthy_threshold: healthyThreshold:
description: description:
- A so-far unhealthy instance will be marked healthy after this many consecutive successes. - A so-far unhealthy instance will be marked healthy after this many consecutive successes.
The default value is 2. The default value is 2.
@ -171,20 +171,20 @@ RETURN = '''
- The default value is 80. - The default value is 80.
returned: success returned: success
type: int type: int
request_path: requestPath:
description: description:
- The request path of the HTTP health check request. - The request path of the HTTP health check request.
- The default value is /. - The default value is /.
returned: success returned: success
type: str type: str
timeout_sec: timeoutSec:
description: description:
- How long (in seconds) to wait before claiming failure. - How long (in seconds) to wait before claiming failure.
- The default value is 5 seconds. It is invalid for timeoutSec to have greater value - The default value is 5 seconds. It is invalid for timeoutSec to have greater value
than checkIntervalSec. than checkIntervalSec.
returned: success returned: success
type: int type: int
unhealthy_threshold: unhealthyThreshold:
description: description:
- A so-far healthy instance will be marked unhealthy after this many consecutive failures. - A so-far healthy instance will be marked unhealthy after this many consecutive failures.
The default value is 2. The default value is 2.
@ -235,7 +235,8 @@ def main():
if fetch: if fetch:
if state == 'present': if state == 'present':
if is_different(module, fetch): if is_different(module, fetch):
fetch = update(module, self_link(module), kind) update(module, self_link(module), kind)
fetch = fetch_resource(module, self_link(module), kind)
changed = True changed = True
else: else:
delete(module, self_link(module), kind) delete(module, self_link(module), kind)
@ -289,9 +290,9 @@ def resource_to_request(module):
return return_vals return return_vals
def fetch_resource(module, link, kind): def fetch_resource(module, link, kind, allow_not_found=True):
auth = GcpSession(module, 'compute') auth = GcpSession(module, 'compute')
return return_if_object(module, auth.get(link), kind) return return_if_object(module, auth.get(link), kind, allow_not_found)
def self_link(module): def self_link(module):
@ -302,9 +303,9 @@ def collection(module):
return "https://www.googleapis.com/compute/v1/projects/{project}/global/httpHealthChecks".format(**module.params) return "https://www.googleapis.com/compute/v1/projects/{project}/global/httpHealthChecks".format(**module.params)
def return_if_object(module, response, kind): def return_if_object(module, response, kind, allow_not_found=False):
# If not found, return nothing. # If not found, return nothing.
if response.status_code == 404: if allow_not_found and response.status_code == 404:
return None return None
# If no content, return nothing. # If no content, return nothing.
@ -319,8 +320,6 @@ def return_if_object(module, response, kind):
if navigate_hash(result, ['error', 'errors']): if navigate_hash(result, ['error', 'errors']):
module.fail_json(msg=navigate_hash(result, ['error', 'errors'])) module.fail_json(msg=navigate_hash(result, ['error', 'errors']))
if result['kind'] != kind:
module.fail_json(msg="Incorrect result: {kind}".format(**result))
return result return result

@ -56,7 +56,7 @@ EXAMPLES = '''
filters: filters:
- name = test_object - name = test_object
project: test_project project: test_project
auth_kind: service_account auth_kind: serviceaccount
service_account_file: "/tmp/auth.pem" service_account_file: "/tmp/auth.pem"
''' '''
@ -66,12 +66,12 @@ items:
returned: always returned: always
type: complex type: complex
contains: contains:
check_interval_sec: checkIntervalSec:
description: description:
- How often (in seconds) to send a health check. The default value is 5 seconds. - How often (in seconds) to send a health check. The default value is 5 seconds.
returned: success returned: success
type: int type: int
creation_timestamp: creationTimestamp:
description: description:
- Creation timestamp in RFC3339 text format. - Creation timestamp in RFC3339 text format.
returned: success returned: success
@ -82,7 +82,7 @@ items:
the resource. the resource.
returned: success returned: success
type: str type: str
healthy_threshold: healthyThreshold:
description: description:
- A so-far unhealthy instance will be marked healthy after this many consecutive successes. - A so-far unhealthy instance will be marked healthy after this many consecutive successes.
The default value is 2. The default value is 2.
@ -116,20 +116,20 @@ items:
- The default value is 80. - The default value is 80.
returned: success returned: success
type: int type: int
request_path: requestPath:
description: description:
- The request path of the HTTP health check request. - The request path of the HTTP health check request.
- The default value is /. - The default value is /.
returned: success returned: success
type: str type: str
timeout_sec: timeoutSec:
description: description:
- How long (in seconds) to wait before claiming failure. - How long (in seconds) to wait before claiming failure.
- The default value is 5 seconds. It is invalid for timeoutSec to have greater value - The default value is 5 seconds. It is invalid for timeoutSec to have greater value
than checkIntervalSec. than checkIntervalSec.
returned: success returned: success
type: int type: int
unhealthy_threshold: unhealthyThreshold:
description: description:
- A so-far healthy instance will be marked unhealthy after this many consecutive failures. - A so-far healthy instance will be marked unhealthy after this many consecutive failures.
The default value is 2. The default value is 2.
@ -151,7 +151,7 @@ import json
def main(): def main():
module = GcpModule( module = GcpModule(
argument_spec=dict( argument_spec=dict(
filters=dict(type='list', elements='str'), filters=dict(type='list', elements='str')
) )
) )

@ -113,18 +113,18 @@ EXAMPLES = '''
timeout_sec: 2 timeout_sec: 2
unhealthy_threshold: 5 unhealthy_threshold: 5
project: "test_project" project: "test_project"
auth_kind: "service_account" auth_kind: "serviceaccount"
service_account_file: "/tmp/auth.pem" service_account_file: "/tmp/auth.pem"
state: present state: present
''' '''
RETURN = ''' RETURN = '''
check_interval_sec: checkIntervalSec:
description: description:
- How often (in seconds) to send a health check. The default value is 5 seconds. - How often (in seconds) to send a health check. The default value is 5 seconds.
returned: success returned: success
type: int type: int
creation_timestamp: creationTimestamp:
description: description:
- Creation timestamp in RFC3339 text format. - Creation timestamp in RFC3339 text format.
returned: success returned: success
@ -135,7 +135,7 @@ RETURN = '''
the resource. the resource.
returned: success returned: success
type: str type: str
healthy_threshold: healthyThreshold:
description: description:
- A so-far unhealthy instance will be marked healthy after this many consecutive successes. - A so-far unhealthy instance will be marked healthy after this many consecutive successes.
The default value is 2. The default value is 2.
@ -169,20 +169,20 @@ RETURN = '''
- The default value is 80. - The default value is 80.
returned: success returned: success
type: int type: int
request_path: requestPath:
description: description:
- The request path of the HTTPS health check request. - The request path of the HTTPS health check request.
- The default value is /. - The default value is /.
returned: success returned: success
type: str type: str
timeout_sec: timeoutSec:
description: description:
- How long (in seconds) to wait before claiming failure. - How long (in seconds) to wait before claiming failure.
- The default value is 5 seconds. It is invalid for timeoutSec to have greater value - The default value is 5 seconds. It is invalid for timeoutSec to have greater value
than checkIntervalSec. than checkIntervalSec.
returned: success returned: success
type: int type: int
unhealthy_threshold: unhealthyThreshold:
description: description:
- A so-far healthy instance will be marked unhealthy after this many consecutive failures. - A so-far healthy instance will be marked unhealthy after this many consecutive failures.
The default value is 2. The default value is 2.
@ -233,7 +233,8 @@ def main():
if fetch: if fetch:
if state == 'present': if state == 'present':
if is_different(module, fetch): if is_different(module, fetch):
fetch = update(module, self_link(module), kind) update(module, self_link(module), kind)
fetch = fetch_resource(module, self_link(module), kind)
changed = True changed = True
else: else:
delete(module, self_link(module), kind) delete(module, self_link(module), kind)
@ -287,9 +288,9 @@ def resource_to_request(module):
return return_vals return return_vals
def fetch_resource(module, link, kind): def fetch_resource(module, link, kind, allow_not_found=True):
auth = GcpSession(module, 'compute') auth = GcpSession(module, 'compute')
return return_if_object(module, auth.get(link), kind) return return_if_object(module, auth.get(link), kind, allow_not_found)
def self_link(module): def self_link(module):
@ -300,9 +301,9 @@ def collection(module):
return "https://www.googleapis.com/compute/v1/projects/{project}/global/httpsHealthChecks".format(**module.params) return "https://www.googleapis.com/compute/v1/projects/{project}/global/httpsHealthChecks".format(**module.params)
def return_if_object(module, response, kind): def return_if_object(module, response, kind, allow_not_found=False):
# If not found, return nothing. # If not found, return nothing.
if response.status_code == 404: if allow_not_found and response.status_code == 404:
return None return None
# If no content, return nothing. # If no content, return nothing.
@ -317,8 +318,6 @@ def return_if_object(module, response, kind):
if navigate_hash(result, ['error', 'errors']): if navigate_hash(result, ['error', 'errors']):
module.fail_json(msg=navigate_hash(result, ['error', 'errors'])) module.fail_json(msg=navigate_hash(result, ['error', 'errors']))
if result['kind'] != kind:
module.fail_json(msg="Incorrect result: {kind}".format(**result))
return result return result

@ -56,7 +56,7 @@ EXAMPLES = '''
filters: filters:
- name = test_object - name = test_object
project: test_project project: test_project
auth_kind: service_account auth_kind: serviceaccount
service_account_file: "/tmp/auth.pem" service_account_file: "/tmp/auth.pem"
''' '''
@ -66,12 +66,12 @@ items:
returned: always returned: always
type: complex type: complex
contains: contains:
check_interval_sec: checkIntervalSec:
description: description:
- How often (in seconds) to send a health check. The default value is 5 seconds. - How often (in seconds) to send a health check. The default value is 5 seconds.
returned: success returned: success
type: int type: int
creation_timestamp: creationTimestamp:
description: description:
- Creation timestamp in RFC3339 text format. - Creation timestamp in RFC3339 text format.
returned: success returned: success
@ -82,7 +82,7 @@ items:
the resource. the resource.
returned: success returned: success
type: str type: str
healthy_threshold: healthyThreshold:
description: description:
- A so-far unhealthy instance will be marked healthy after this many consecutive successes. - A so-far unhealthy instance will be marked healthy after this many consecutive successes.
The default value is 2. The default value is 2.
@ -116,20 +116,20 @@ items:
- The default value is 80. - The default value is 80.
returned: success returned: success
type: int type: int
request_path: requestPath:
description: description:
- The request path of the HTTPS health check request. - The request path of the HTTPS health check request.
- The default value is /. - The default value is /.
returned: success returned: success
type: str type: str
timeout_sec: timeoutSec:
description: description:
- How long (in seconds) to wait before claiming failure. - How long (in seconds) to wait before claiming failure.
- The default value is 5 seconds. It is invalid for timeoutSec to have greater value - The default value is 5 seconds. It is invalid for timeoutSec to have greater value
than checkIntervalSec. than checkIntervalSec.
returned: success returned: success
type: int type: int
unhealthy_threshold: unhealthyThreshold:
description: description:
- A so-far healthy instance will be marked unhealthy after this many consecutive failures. - A so-far healthy instance will be marked unhealthy after this many consecutive failures.
The default value is 2. The default value is 2.
@ -151,7 +151,7 @@ import json
def main(): def main():
module = GcpModule( module = GcpModule(
argument_spec=dict( argument_spec=dict(
filters=dict(type='list', elements='str'), filters=dict(type='list', elements='str')
) )
) )

@ -148,6 +148,11 @@ options:
description: description:
- Refers to a gcompute_disk object You must provide either this property or the rawDisk.source - Refers to a gcompute_disk object You must provide either this property or the rawDisk.source
property but not both to create an image. property but not both to create an image.
- 'This field represents a link to a Disk resource in GCP. It can be specified in
two ways. You can add `register: name-of-resource` to a gcp_compute_disk task and
then set this source_disk field to "{{ name-of-resource }}" Alternatively, you can
set this source_disk to a dictionary with the selfLink key where the value is the
selfLink of your Disk.'
required: false required: false
source_disk_encryption_key: source_disk_encryption_key:
description: description:
@ -196,18 +201,18 @@ EXAMPLES = '''
name: "test_object" name: "test_object"
source_disk: "{{ disk }}" source_disk: "{{ disk }}"
project: "test_project" project: "test_project"
auth_kind: "service_account" auth_kind: "serviceaccount"
service_account_file: "/tmp/auth.pem" service_account_file: "/tmp/auth.pem"
state: present state: present
''' '''
RETURN = ''' RETURN = '''
archive_size_bytes: archiveSizeBytes:
description: description:
- Size of the image tar.gz archive stored in Google Cloud Storage (in bytes). - Size of the image tar.gz archive stored in Google Cloud Storage (in bytes).
returned: success returned: success
type: int type: int
creation_timestamp: creationTimestamp:
description: description:
- Creation timestamp in RFC3339 text format. - Creation timestamp in RFC3339 text format.
returned: success returned: success
@ -261,7 +266,7 @@ RETURN = '''
the resource. the resource.
returned: success returned: success
type: str type: str
disk_size_gb: diskSizeGb:
description: description:
- Size of the image when restored onto a persistent disk (in GB). - Size of the image when restored onto a persistent disk (in GB).
returned: success returned: success
@ -274,7 +279,7 @@ RETURN = '''
comply with RFC1035. comply with RFC1035.
returned: success returned: success
type: str type: str
guest_os_features: guestOsFeatures:
description: description:
- A list of features to enable on the guest OS. Applicable for bootable images only. - A list of features to enable on the guest OS. Applicable for bootable images only.
Currently, only one feature can be enabled, VIRTIO_SCSI_MULTIQUEUE, which allows Currently, only one feature can be enabled, VIRTIO_SCSI_MULTIQUEUE, which allows
@ -300,7 +305,7 @@ RETURN = '''
- The unique identifier for the resource. This identifier is defined by the server. - The unique identifier for the resource. This identifier is defined by the server.
returned: success returned: success
type: int type: int
image_encryption_key: imageEncryptionKey:
description: description:
- Encrypts the image using a customer-supplied encryption key. - Encrypts the image using a customer-supplied encryption key.
- After you encrypt an image with a customer-supplied key, you must provide the same - After you encrypt an image with a customer-supplied key, you must provide the same
@ -308,7 +313,7 @@ RETURN = '''
returned: success returned: success
type: complex type: complex
contains: contains:
raw_key: rawKey:
description: description:
- Specifies a 256-bit customer-supplied encryption key, encoded in RFC 4648 base64 - Specifies a 256-bit customer-supplied encryption key, encoded in RFC 4648 base64
to either encrypt or decrypt this resource. to either encrypt or decrypt this resource.
@ -335,20 +340,20 @@ RETURN = '''
be a dash. be a dash.
returned: success returned: success
type: str type: str
raw_disk: rawDisk:
description: description:
- The parameters of the raw disk image. - The parameters of the raw disk image.
returned: success returned: success
type: complex type: complex
contains: contains:
container_type: containerType:
description: description:
- The format used to encode and transmit the block device, which should be TAR. This - The format used to encode and transmit the block device, which should be TAR. This
is just a container and transmission format and not a runtime format. Provided by is just a container and transmission format and not a runtime format. Provided by
the client when the disk image is created. the client when the disk image is created.
returned: success returned: success
type: str type: str
sha1_checksum: sha1Checksum:
description: description:
- An optional SHA1 checksum of the disk image before unpackaging. - An optional SHA1 checksum of the disk image before unpackaging.
- This is provided by the client when the disk image is created. - This is provided by the client when the disk image is created.
@ -360,20 +365,20 @@ RETURN = '''
either this property or the sourceDisk property but not both. either this property or the sourceDisk property but not both.
returned: success returned: success
type: str type: str
source_disk: sourceDisk:
description: description:
- Refers to a gcompute_disk object You must provide either this property or the rawDisk.source - Refers to a gcompute_disk object You must provide either this property or the rawDisk.source
property but not both to create an image. property but not both to create an image.
returned: success returned: success
type: dict type: dict
source_disk_encryption_key: sourceDiskEncryptionKey:
description: description:
- The customer-supplied encryption key of the source disk. Required if the source - The customer-supplied encryption key of the source disk. Required if the source
disk is protected by a customer-supplied encryption key. disk is protected by a customer-supplied encryption key.
returned: success returned: success
type: complex type: complex
contains: contains:
raw_key: rawKey:
description: description:
- Specifies a 256-bit customer-supplied encryption key, encoded in RFC 4648 base64 - Specifies a 256-bit customer-supplied encryption key, encoded in RFC 4648 base64
to either encrypt or decrypt this resource. to either encrypt or decrypt this resource.
@ -385,14 +390,14 @@ RETURN = '''
that protects this resource. that protects this resource.
returned: success returned: success
type: str type: str
source_disk_id: sourceDiskId:
description: description:
- The ID value of the disk used to create this image. This value may be used to determine - The ID value of the disk used to create this image. This value may be used to determine
whether the image was taken from the current or a previous instance of a given disk whether the image was taken from the current or a previous instance of a given disk
name. name.
returned: success returned: success
type: str type: str
source_type: sourceType:
description: description:
- The type of the image used to create this disk. The default and only value is RAW - The type of the image used to create this disk. The default and only value is RAW
. .
@ -458,7 +463,8 @@ def main():
if fetch: if fetch:
if state == 'present': if state == 'present':
if is_different(module, fetch): if is_different(module, fetch):
fetch = update(module, self_link(module), kind) update(module, self_link(module), kind)
fetch = fetch_resource(module, self_link(module), kind)
changed = True changed = True
else: else:
delete(module, self_link(module), kind) delete(module, self_link(module), kind)
@ -515,9 +521,9 @@ def resource_to_request(module):
return return_vals return return_vals
def fetch_resource(module, link, kind): def fetch_resource(module, link, kind, allow_not_found=True):
auth = GcpSession(module, 'compute') auth = GcpSession(module, 'compute')
return return_if_object(module, auth.get(link), kind) return return_if_object(module, auth.get(link), kind, allow_not_found)
def self_link(module): def self_link(module):
@ -528,9 +534,9 @@ def collection(module):
return "https://www.googleapis.com/compute/v1/projects/{project}/global/images".format(**module.params) return "https://www.googleapis.com/compute/v1/projects/{project}/global/images".format(**module.params)
def return_if_object(module, response, kind): def return_if_object(module, response, kind, allow_not_found=False):
# If not found, return nothing. # If not found, return nothing.
if response.status_code == 404: if allow_not_found and response.status_code == 404:
return None return None
# If no content, return nothing. # If no content, return nothing.
@ -545,8 +551,6 @@ def return_if_object(module, response, kind):
if navigate_hash(result, ['error', 'errors']): if navigate_hash(result, ['error', 'errors']):
module.fail_json(msg=navigate_hash(result, ['error', 'errors'])) module.fail_json(msg=navigate_hash(result, ['error', 'errors']))
if result['kind'] != kind:
module.fail_json(msg="Incorrect result: {kind}".format(**result))
return result return result

@ -56,7 +56,7 @@ EXAMPLES = '''
filters: filters:
- name = test_object - name = test_object
project: test_project project: test_project
auth_kind: service_account auth_kind: serviceaccount
service_account_file: "/tmp/auth.pem" service_account_file: "/tmp/auth.pem"
''' '''
@ -66,12 +66,12 @@ items:
returned: always returned: always
type: complex type: complex
contains: contains:
archive_size_bytes: archiveSizeBytes:
description: description:
- Size of the image tar.gz archive stored in Google Cloud Storage (in bytes). - Size of the image tar.gz archive stored in Google Cloud Storage (in bytes).
returned: success returned: success
type: int type: int
creation_timestamp: creationTimestamp:
description: description:
- Creation timestamp in RFC3339 text format. - Creation timestamp in RFC3339 text format.
returned: success returned: success
@ -125,7 +125,7 @@ items:
the resource. the resource.
returned: success returned: success
type: str type: str
disk_size_gb: diskSizeGb:
description: description:
- Size of the image when restored onto a persistent disk (in GB). - Size of the image when restored onto a persistent disk (in GB).
returned: success returned: success
@ -138,7 +138,7 @@ items:
comply with RFC1035. comply with RFC1035.
returned: success returned: success
type: str type: str
guest_os_features: guestOsFeatures:
description: description:
- A list of features to enable on the guest OS. Applicable for bootable images only. - A list of features to enable on the guest OS. Applicable for bootable images only.
Currently, only one feature can be enabled, VIRTIO_SCSI_MULTIQUEUE, which allows Currently, only one feature can be enabled, VIRTIO_SCSI_MULTIQUEUE, which allows
@ -164,7 +164,7 @@ items:
- The unique identifier for the resource. This identifier is defined by the server. - The unique identifier for the resource. This identifier is defined by the server.
returned: success returned: success
type: int type: int
image_encryption_key: imageEncryptionKey:
description: description:
- Encrypts the image using a customer-supplied encryption key. - Encrypts the image using a customer-supplied encryption key.
- After you encrypt an image with a customer-supplied key, you must provide the same - After you encrypt an image with a customer-supplied key, you must provide the same
@ -172,7 +172,7 @@ items:
returned: success returned: success
type: complex type: complex
contains: contains:
raw_key: rawKey:
description: description:
- Specifies a 256-bit customer-supplied encryption key, encoded in RFC 4648 base64 - Specifies a 256-bit customer-supplied encryption key, encoded in RFC 4648 base64
to either encrypt or decrypt this resource. to either encrypt or decrypt this resource.
@ -199,20 +199,20 @@ items:
be a dash. be a dash.
returned: success returned: success
type: str type: str
raw_disk: rawDisk:
description: description:
- The parameters of the raw disk image. - The parameters of the raw disk image.
returned: success returned: success
type: complex type: complex
contains: contains:
container_type: containerType:
description: description:
- The format used to encode and transmit the block device, which should be TAR. This - The format used to encode and transmit the block device, which should be TAR. This
is just a container and transmission format and not a runtime format. Provided by is just a container and transmission format and not a runtime format. Provided by
the client when the disk image is created. the client when the disk image is created.
returned: success returned: success
type: str type: str
sha1_checksum: sha1Checksum:
description: description:
- An optional SHA1 checksum of the disk image before unpackaging. - An optional SHA1 checksum of the disk image before unpackaging.
- This is provided by the client when the disk image is created. - This is provided by the client when the disk image is created.
@ -224,20 +224,20 @@ items:
either this property or the sourceDisk property but not both. either this property or the sourceDisk property but not both.
returned: success returned: success
type: str type: str
source_disk: sourceDisk:
description: description:
- Refers to a gcompute_disk object You must provide either this property or the rawDisk.source - Refers to a gcompute_disk object You must provide either this property or the rawDisk.source
property but not both to create an image. property but not both to create an image.
returned: success returned: success
type: dict type: dict
source_disk_encryption_key: sourceDiskEncryptionKey:
description: description:
- The customer-supplied encryption key of the source disk. Required if the source - The customer-supplied encryption key of the source disk. Required if the source
disk is protected by a customer-supplied encryption key. disk is protected by a customer-supplied encryption key.
returned: success returned: success
type: complex type: complex
contains: contains:
raw_key: rawKey:
description: description:
- Specifies a 256-bit customer-supplied encryption key, encoded in RFC 4648 base64 - Specifies a 256-bit customer-supplied encryption key, encoded in RFC 4648 base64
to either encrypt or decrypt this resource. to either encrypt or decrypt this resource.
@ -249,14 +249,14 @@ items:
that protects this resource. that protects this resource.
returned: success returned: success
type: str type: str
source_disk_id: sourceDiskId:
description: description:
- The ID value of the disk used to create this image. This value may be used to determine - The ID value of the disk used to create this image. This value may be used to determine
whether the image was taken from the current or a previous instance of a given disk whether the image was taken from the current or a previous instance of a given disk
name. name.
returned: success returned: success
type: str type: str
source_type: sourceType:
description: description:
- The type of the image used to create this disk. The default and only value is RAW - The type of the image used to create this disk. The default and only value is RAW
. .
@ -278,7 +278,7 @@ import json
def main(): def main():
module = GcpModule( module = GcpModule(
argument_spec=dict( argument_spec=dict(
filters=dict(type='list', elements='str'), filters=dict(type='list', elements='str')
) )
) )

@ -171,6 +171,11 @@ options:
or disks.source is required. or disks.source is required.
- If desired, you can also attach existing non-root persistent disks using this property. - If desired, you can also attach existing non-root persistent disks using this property.
This field is only applicable for persistent disks. This field is only applicable for persistent disks.
- 'This field represents a link to a Disk resource in GCP. It can be specified in
two ways. You can add `register: name-of-resource` to a gcp_compute_disk task and
then set this source field to "{{ name-of-resource }}" Alternatively, you can set
this source to a dictionary with the selfLink key where the value is the selfLink
of your Disk.'
required: false required: false
type: type:
description: description:
@ -249,6 +254,11 @@ options:
field undefined to use an IP from a shared ephemeral IP address pool. If you specify field undefined to use an IP from a shared ephemeral IP address pool. If you specify
a static external IP address, it must live in the same region as the zone of the a static external IP address, it must live in the same region as the zone of the
instance. instance.
- 'This field represents a link to a Address resource in GCP. It can be specified
in two ways. You can add `register: name-of-resource` to a gcp_compute_address task
and then set this nat_ip field to "{{ name-of-resource }}" Alternatively, you can
set this nat_ip to a dictionary with the address key where the value is the address
of your Address.'
required: false required: false
type: type:
description: description:
@ -286,6 +296,11 @@ options:
if neither the network nor the subnetwork is specified, the default network global/networks/default if neither the network nor the subnetwork is specified, the default network global/networks/default
is used; if the network is not specified but the subnetwork is specified, the network is used; if the network is not specified but the subnetwork is specified, the network
is inferred. is inferred.
- 'This field represents a link to a Network resource in GCP. It can be specified
in two ways. You can add `register: name-of-resource` to a gcp_compute_network 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: false required: false
network_ip: network_ip:
description: description:
@ -298,6 +313,11 @@ options:
- If the network resource is in legacy mode, do not provide this property. If the - If the network resource is in legacy mode, do not provide this property. If the
network is in auto subnet mode, providing the subnetwork is optional. If the network network is in auto subnet mode, providing the subnetwork is optional. If the network
is in custom subnet mode, then this field should be specified. is in custom subnet mode, then this field should be specified.
- 'This field represents a link to a Subnetwork resource in GCP. It can be specified
in two ways. You can add `register: name-of-resource` to a gcp_compute_subnetwork
task and then set this subnetwork field to "{{ name-of-resource }}" Alternatively,
you can set this subnetwork to a dictionary with the selfLink key where the value
is the selfLink of your Subnetwork.'
required: false required: false
scheduling: scheduling:
description: description:
@ -417,24 +437,24 @@ EXAMPLES = '''
type: ONE_TO_ONE_NAT type: ONE_TO_ONE_NAT
zone: us-central1-a zone: us-central1-a
project: "test_project" project: "test_project"
auth_kind: "service_account" auth_kind: "serviceaccount"
service_account_file: "/tmp/auth.pem" service_account_file: "/tmp/auth.pem"
state: present state: present
''' '''
RETURN = ''' RETURN = '''
can_ip_forward: canIpForward:
description: description:
- Allows this instance to send and receive packets with non-matching destination or - Allows this instance to send and receive packets with non-matching destination or
source IPs. This is required if you plan to use this instance to forward routes. source IPs. This is required if you plan to use this instance to forward routes.
returned: success returned: success
type: bool type: bool
cpu_platform: cpuPlatform:
description: description:
- The CPU platform used by this instance. - The CPU platform used by this instance.
returned: success returned: success
type: str type: str
creation_timestamp: creationTimestamp:
description: description:
- Creation timestamp in RFC3339 text format. - Creation timestamp in RFC3339 text format.
returned: success returned: success
@ -446,7 +466,7 @@ RETURN = '''
returned: success returned: success
type: complex type: complex
contains: contains:
auto_delete: autoDelete:
description: description:
- Specifies whether the disk will be auto-deleted when the instance is deleted (but - Specifies whether the disk will be auto-deleted when the instance is deleted (but
not when the disk is detached from the instance). not when the disk is detached from the instance).
@ -460,26 +480,26 @@ RETURN = '''
of the disk for its root filesystem. of the disk for its root filesystem.
returned: success returned: success
type: bool type: bool
device_name: deviceName:
description: description:
- Specifies a unique device name of your choice that is reflected into the /dev/disk/by-id/google-* - Specifies a unique device name of your choice that is reflected into the /dev/disk/by-id/google-*
tree of a Linux operating system running within the instance. This name can be used tree of a Linux operating system running within the instance. This name can be used
to reference the device for mounting, resizing, and so on, from within the instance. to reference the device for mounting, resizing, and so on, from within the instance.
returned: success returned: success
type: str type: str
disk_encryption_key: diskEncryptionKey:
description: description:
- Encrypts or decrypts a disk using a customer-supplied encryption key. - Encrypts or decrypts a disk using a customer-supplied encryption key.
returned: success returned: success
type: complex type: complex
contains: contains:
raw_key: rawKey:
description: description:
- Specifies a 256-bit customer-supplied encryption key, encoded in RFC 4648 base64 - Specifies a 256-bit customer-supplied encryption key, encoded in RFC 4648 base64
to either encrypt or decrypt this resource. to either encrypt or decrypt this resource.
returned: success returned: success
type: str type: str
rsa_encrypted_key: rsaEncryptedKey:
description: description:
- Specifies an RFC 4648 base64 encoded, RSA-wrapped 2048-bit customer-supplied encryption - Specifies an RFC 4648 base64 encoded, RSA-wrapped 2048-bit customer-supplied encryption
key to either encrypt or decrypt this resource. key to either encrypt or decrypt this resource.
@ -498,7 +518,7 @@ RETURN = '''
a unique index number. If not specified, the server will choose an appropriate value. a unique index number. If not specified, the server will choose an appropriate value.
returned: success returned: success
type: int type: int
initialize_params: initializeParams:
description: description:
- Specifies the parameters for a new disk that will be created alongside the new instance. - Specifies the parameters for a new disk that will be created alongside the new instance.
Use initialization parameters to create boot disks or local SSDs attached to the Use initialization parameters to create boot disks or local SSDs attached to the
@ -506,32 +526,32 @@ RETURN = '''
returned: success returned: success
type: complex type: complex
contains: contains:
disk_name: diskName:
description: description:
- Specifies the disk name. If not specified, the default is to use the name of the - Specifies the disk name. If not specified, the default is to use the name of the
instance. instance.
returned: success returned: success
type: str type: str
disk_size_gb: diskSizeGb:
description: description:
- Specifies the size of the disk in base-2 GB. - Specifies the size of the disk in base-2 GB.
returned: success returned: success
type: int type: int
disk_type: diskType:
description: description:
- Reference to a gcompute_disk_type resource. - Reference to a gcompute_disk_type resource.
- Specifies the disk type to use to create the instance. - Specifies the disk type to use to create the instance.
- If not specified, the default is pd-standard. - If not specified, the default is pd-standard.
returned: success returned: success
type: str type: str
source_image: sourceImage:
description: description:
- The source image to create this disk. When creating a new instance, one of initializeParams.sourceImage - The source image to create this disk. When creating a new instance, one of initializeParams.sourceImage
or disks.source is required. To create a disk with one of the public operating or disks.source is required. To create a disk with one of the public operating
system images, specify the image by its family name. system images, specify the image by its family name.
returned: success returned: success
type: str type: str
source_image_encryption_key: sourceImageEncryptionKey:
description: description:
- The customer-supplied encryption key of the source image. Required if the source - The customer-supplied encryption key of the source image. Required if the source
image is protected by a customer-supplied encryption key. image is protected by a customer-supplied encryption key.
@ -541,7 +561,7 @@ RETURN = '''
returned: success returned: success
type: complex type: complex
contains: contains:
raw_key: rawKey:
description: description:
- Specifies a 256-bit customer-supplied encryption key, encoded in RFC 4648 base64 - Specifies a 256-bit customer-supplied encryption key, encoded in RFC 4648 base64
to either encrypt or decrypt this resource. to either encrypt or decrypt this resource.
@ -581,18 +601,18 @@ RETURN = '''
the default is PERSISTENT. the default is PERSISTENT.
returned: success returned: success
type: str type: str
guest_accelerators: guestAccelerators:
description: description:
- List of the type and count of accelerator cards attached to the instance . - List of the type and count of accelerator cards attached to the instance .
returned: success returned: success
type: complex type: complex
contains: contains:
accelerator_count: acceleratorCount:
description: description:
- The number of the guest accelerator cards exposed to this instance. - The number of the guest accelerator cards exposed to this instance.
returned: success returned: success
type: int type: int
accelerator_type: acceleratorType:
description: description:
- Full or partial URL of the accelerator type resource to expose to this instance. - Full or partial URL of the accelerator type resource to expose to this instance.
returned: success returned: success
@ -602,7 +622,7 @@ RETURN = '''
- The unique identifier for the resource. This identifier is defined by the server. - The unique identifier for the resource. This identifier is defined by the server.
returned: success returned: success
type: int type: int
label_fingerprint: labelFingerprint:
description: description:
- A fingerprint for this request, which is essentially a hash of the metadata's contents - A fingerprint for this request, which is essentially a hash of the metadata's contents
and used for optimistic locking. The fingerprint is initially generated by Compute and used for optimistic locking. The fingerprint is initially generated by Compute
@ -616,12 +636,12 @@ RETURN = '''
These pairs can consist of custom metadata or predefined keys. These pairs can consist of custom metadata or predefined keys.
returned: success returned: success
type: dict type: dict
machine_type: machineType:
description: description:
- A reference to a machine type which defines VM kind. - A reference to a machine type which defines VM kind.
returned: success returned: success
type: str type: str
min_cpu_platform: minCpuPlatform:
description: description:
- Specifies a minimum CPU platform for the VM instance. Applicable values are the - Specifies a minimum CPU platform for the VM instance. Applicable values are the
friendly names of CPU platforms . friendly names of CPU platforms .
@ -637,7 +657,7 @@ RETURN = '''
be a dash. be a dash.
returned: success returned: success
type: str type: str
network_interfaces: networkInterfaces:
description: description:
- An array of configurations for this interface. This specifies how this interface - An array of configurations for this interface. This specifies how this interface
is configured to interact with other network services, such as connecting to the is configured to interact with other network services, such as connecting to the
@ -645,7 +665,7 @@ RETURN = '''
returned: success returned: success
type: complex type: complex
contains: contains:
access_configs: accessConfigs:
description: description:
- An array of configurations for this interface. Currently, only one access config, - An array of configurations for this interface. Currently, only one access config,
ONE_TO_ONE_NAT, is supported. If there are no accessConfigs specified, then this ONE_TO_ONE_NAT, is supported. If there are no accessConfigs specified, then this
@ -660,7 +680,7 @@ RETURN = '''
IP or Network Access. IP or Network Access.
returned: success returned: success
type: str type: str
nat_ip: natIP:
description: description:
- Specifies the title of a gcompute_address. - Specifies the title of a gcompute_address.
- An external IP address associated with this instance. - An external IP address associated with this instance.
@ -675,14 +695,14 @@ RETURN = '''
- The type of configuration. The default and only option is ONE_TO_ONE_NAT. - The type of configuration. The default and only option is ONE_TO_ONE_NAT.
returned: success returned: success
type: str type: str
alias_ip_ranges: aliasIpRanges:
description: description:
- An array of alias IP ranges for this network interface. Can only be specified for - An array of alias IP ranges for this network interface. Can only be specified for
network interfaces on subnet-mode networks. network interfaces on subnet-mode networks.
returned: success returned: success
type: complex type: complex
contains: contains:
ip_cidr_range: ipCidrRange:
description: description:
- The IP CIDR range represented by this alias IP range. - The IP CIDR range represented by this alias IP range.
- This IP CIDR range must belong to the specified subnetwork and cannot contain IP - This IP CIDR range must belong to the specified subnetwork and cannot contain IP
@ -691,7 +711,7 @@ RETURN = '''
(e.g. 10.1.2.0/24). (e.g. 10.1.2.0/24).
returned: success returned: success
type: str type: str
subnetwork_range_name: subnetworkRangeName:
description: description:
- Optional subnetwork secondary range name specifying the secondary range from which - Optional subnetwork secondary range name specifying the secondary range from which
to allocate the IP CIDR range for this alias IP range. If left unspecified, the to allocate the IP CIDR range for this alias IP range. If left unspecified, the
@ -712,7 +732,7 @@ RETURN = '''
is inferred. is inferred.
returned: success returned: success
type: dict type: dict
network_ip: networkIP:
description: description:
- An IPv4 internal network address to assign to the instance for this network interface. - An IPv4 internal network address to assign to the instance for this network interface.
If not specified by the user, an unused internal IP is assigned by the system. If not specified by the user, an unused internal IP is assigned by the system.
@ -732,7 +752,7 @@ RETURN = '''
returned: success returned: success
type: complex type: complex
contains: contains:
automatic_restart: automaticRestart:
description: description:
- Specifies whether the instance should be automatically restarted if it is terminated - Specifies whether the instance should be automatically restarted if it is terminated
by Compute Engine (not terminated by a user). by Compute Engine (not terminated by a user).
@ -740,7 +760,7 @@ RETURN = '''
instances cannot be automatically restarted. instances cannot be automatically restarted.
returned: success returned: success
type: bool type: bool
on_host_maintenance: onHostMaintenance:
description: description:
- Defines the maintenance behavior for this instance. For standard instances, the - Defines the maintenance behavior for this instance. For standard instances, the
default behavior is MIGRATE. For preemptible instances, the default and only possible default behavior is MIGRATE. For preemptible instances, the default and only possible
@ -754,7 +774,7 @@ RETURN = '''
creation, it cannot be set or changed after the instance has been created. creation, it cannot be set or changed after the instance has been created.
returned: success returned: success
type: bool type: bool
service_accounts: serviceAccounts:
description: description:
- A list of service accounts, with their specified scopes, authorized for this instance. - A list of service accounts, with their specified scopes, authorized for this instance.
Only one service account per VM instance is supported. Only one service account per VM instance is supported.
@ -777,7 +797,7 @@ RETURN = '''
RUNNING, STOPPING, SUSPENDING, SUSPENDED, and TERMINATED.' RUNNING, STOPPING, SUSPENDING, SUSPENDED, and TERMINATED.'
returned: success returned: success
type: str type: str
status_message: statusMessage:
description: description:
- An optional, human-readable explanation of the status. - An optional, human-readable explanation of the status.
returned: success returned: success
@ -911,7 +931,8 @@ def main():
if fetch: if fetch:
if state == 'present': if state == 'present':
if is_different(module, fetch): if is_different(module, fetch):
fetch = update(module, self_link(module), kind) update(module, self_link(module), kind, fetch)
fetch = fetch_resource(module, self_link(module), kind)
changed = True changed = True
else: else:
delete(module, self_link(module), kind) delete(module, self_link(module), kind)
@ -934,9 +955,28 @@ def create(module, link, kind):
return wait_for_operation(module, auth.post(link, resource_to_request(module))) return wait_for_operation(module, auth.post(link, resource_to_request(module)))
def update(module, link, kind): 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('machineType') != request.get('machineType'):
machine_type_update(module, request, response)
def machine_type_update(module, request, response):
auth = GcpSession(module, 'compute') auth = GcpSession(module, 'compute')
return wait_for_operation(module, auth.put(link, resource_to_request(module))) auth.post(
''.join([
"https://www.googleapis.com/compute/v1/",
"projdcts/{project}/zones/{zone}/instances/{name}/setMachineType"
]).format(**module.params),
{
u'machineType': machine_type_selflink(module.params.get('machine_type'), module.params)
}
)
def delete(module, link, kind): def delete(module, link, kind):
@ -969,9 +1009,9 @@ def resource_to_request(module):
return return_vals return return_vals
def fetch_resource(module, link, kind): def fetch_resource(module, link, kind, allow_not_found=True):
auth = GcpSession(module, 'compute') auth = GcpSession(module, 'compute')
return return_if_object(module, auth.get(link), kind) return return_if_object(module, auth.get(link), kind, allow_not_found)
def self_link(module): def self_link(module):
@ -982,9 +1022,9 @@ def collection(module):
return "https://www.googleapis.com/compute/v1/projects/{project}/zones/{zone}/instances".format(**module.params) return "https://www.googleapis.com/compute/v1/projects/{project}/zones/{zone}/instances".format(**module.params)
def return_if_object(module, response, kind): def return_if_object(module, response, kind, allow_not_found=False):
# If not found, return nothing. # If not found, return nothing.
if response.status_code == 404: if allow_not_found and response.status_code == 404:
return None return None
# If no content, return nothing. # If no content, return nothing.
@ -1001,8 +1041,6 @@ def return_if_object(module, response, kind):
if navigate_hash(result, ['error', 'errors']): if navigate_hash(result, ['error', 'errors']):
module.fail_json(msg=navigate_hash(result, ['error', 'errors'])) module.fail_json(msg=navigate_hash(result, ['error', 'errors']))
if result['kind'] != kind:
module.fail_json(msg="Incorrect result: {kind}".format(**result))
return result return result
@ -1053,7 +1091,7 @@ def response_to_hash(module, response):
def disk_type_selflink(name, params): def disk_type_selflink(name, params):
if name is None: if name is None:
return return
url = r"https://www.googleapis.com/compute/v1/projects/.*/zones/{zone}/diskTypes/[a-z1-9\-]*" url = r"https://www.googleapis.com/compute/v1/projects/.*/zones/[a-z1-9\-]*/diskTypes/[a-z1-9\-]*"
if not re.match(url, name): if not re.match(url, name):
name = "https://www.googleapis.com/compute/v1/projects/{project}/zones/{zone}/diskTypes/%s".format(**params) % name name = "https://www.googleapis.com/compute/v1/projects/{project}/zones/{zone}/diskTypes/%s".format(**params) % name
return name return name
@ -1062,7 +1100,7 @@ def disk_type_selflink(name, params):
def machine_type_selflink(name, params): def machine_type_selflink(name, params):
if name is None: if name is None:
return return
url = r"https://www.googleapis.com/compute/v1/projects/.*/zones/{zone}/machineTypes/[a-z1-9\-]*" url = r"https://www.googleapis.com/compute/v1/projects/.*/zones/[a-z1-9\-]*/machineTypes/[a-z1-9\-]*"
if not re.match(url, name): if not re.match(url, name):
name = "https://www.googleapis.com/compute/v1/projects/{project}/zones/{zone}/machineTypes/%s".format(**params) % name name = "https://www.googleapis.com/compute/v1/projects/{project}/zones/{zone}/machineTypes/%s".format(**params) % name
return name return name
@ -1112,7 +1150,7 @@ def encode_request(request, module):
def decode_response(response, module): def decode_response(response, module):
if 'metadata' in response: if 'metadata' in response and response['metadata'] is not None:
response['metadata'] = metadata_decoder(response['metadata']) response['metadata'] = metadata_decoder(response['metadata'])
return response return response

@ -61,7 +61,7 @@ EXAMPLES = '''
filters: filters:
- name = test_object - name = test_object
project: test_project project: test_project
auth_kind: service_account auth_kind: serviceaccount
service_account_file: "/tmp/auth.pem" service_account_file: "/tmp/auth.pem"
''' '''
@ -71,18 +71,18 @@ items:
returned: always returned: always
type: complex type: complex
contains: contains:
can_ip_forward: canIpForward:
description: description:
- Allows this instance to send and receive packets with non-matching destination or - Allows this instance to send and receive packets with non-matching destination or
source IPs. This is required if you plan to use this instance to forward routes. source IPs. This is required if you plan to use this instance to forward routes.
returned: success returned: success
type: bool type: bool
cpu_platform: cpuPlatform:
description: description:
- The CPU platform used by this instance. - The CPU platform used by this instance.
returned: success returned: success
type: str type: str
creation_timestamp: creationTimestamp:
description: description:
- Creation timestamp in RFC3339 text format. - Creation timestamp in RFC3339 text format.
returned: success returned: success
@ -94,7 +94,7 @@ items:
returned: success returned: success
type: complex type: complex
contains: contains:
auto_delete: autoDelete:
description: description:
- Specifies whether the disk will be auto-deleted when the instance is deleted (but - Specifies whether the disk will be auto-deleted when the instance is deleted (but
not when the disk is detached from the instance). not when the disk is detached from the instance).
@ -108,26 +108,26 @@ items:
of the disk for its root filesystem. of the disk for its root filesystem.
returned: success returned: success
type: bool type: bool
device_name: deviceName:
description: description:
- Specifies a unique device name of your choice that is reflected into the /dev/disk/by-id/google-* - Specifies a unique device name of your choice that is reflected into the /dev/disk/by-id/google-*
tree of a Linux operating system running within the instance. This name can be used tree of a Linux operating system running within the instance. This name can be used
to reference the device for mounting, resizing, and so on, from within the instance. to reference the device for mounting, resizing, and so on, from within the instance.
returned: success returned: success
type: str type: str
disk_encryption_key: diskEncryptionKey:
description: description:
- Encrypts or decrypts a disk using a customer-supplied encryption key. - Encrypts or decrypts a disk using a customer-supplied encryption key.
returned: success returned: success
type: complex type: complex
contains: contains:
raw_key: rawKey:
description: description:
- Specifies a 256-bit customer-supplied encryption key, encoded in RFC 4648 base64 - Specifies a 256-bit customer-supplied encryption key, encoded in RFC 4648 base64
to either encrypt or decrypt this resource. to either encrypt or decrypt this resource.
returned: success returned: success
type: str type: str
rsa_encrypted_key: rsaEncryptedKey:
description: description:
- Specifies an RFC 4648 base64 encoded, RSA-wrapped 2048-bit customer-supplied encryption - Specifies an RFC 4648 base64 encoded, RSA-wrapped 2048-bit customer-supplied encryption
key to either encrypt or decrypt this resource. key to either encrypt or decrypt this resource.
@ -146,7 +146,7 @@ items:
a unique index number. If not specified, the server will choose an appropriate value. a unique index number. If not specified, the server will choose an appropriate value.
returned: success returned: success
type: int type: int
initialize_params: initializeParams:
description: description:
- Specifies the parameters for a new disk that will be created alongside the new instance. - Specifies the parameters for a new disk that will be created alongside the new instance.
Use initialization parameters to create boot disks or local SSDs attached to the Use initialization parameters to create boot disks or local SSDs attached to the
@ -154,32 +154,32 @@ items:
returned: success returned: success
type: complex type: complex
contains: contains:
disk_name: diskName:
description: description:
- Specifies the disk name. If not specified, the default is to use the name of the - Specifies the disk name. If not specified, the default is to use the name of the
instance. instance.
returned: success returned: success
type: str type: str
disk_size_gb: diskSizeGb:
description: description:
- Specifies the size of the disk in base-2 GB. - Specifies the size of the disk in base-2 GB.
returned: success returned: success
type: int type: int
disk_type: diskType:
description: description:
- Reference to a gcompute_disk_type resource. - Reference to a gcompute_disk_type resource.
- Specifies the disk type to use to create the instance. - Specifies the disk type to use to create the instance.
- If not specified, the default is pd-standard. - If not specified, the default is pd-standard.
returned: success returned: success
type: str type: str
source_image: sourceImage:
description: description:
- The source image to create this disk. When creating a new instance, one of initializeParams.sourceImage - The source image to create this disk. When creating a new instance, one of initializeParams.sourceImage
or disks.source is required. To create a disk with one of the public operating or disks.source is required. To create a disk with one of the public operating
system images, specify the image by its family name. system images, specify the image by its family name.
returned: success returned: success
type: str type: str
source_image_encryption_key: sourceImageEncryptionKey:
description: description:
- The customer-supplied encryption key of the source image. Required if the source - The customer-supplied encryption key of the source image. Required if the source
image is protected by a customer-supplied encryption key. image is protected by a customer-supplied encryption key.
@ -189,7 +189,7 @@ items:
returned: success returned: success
type: complex type: complex
contains: contains:
raw_key: rawKey:
description: description:
- Specifies a 256-bit customer-supplied encryption key, encoded in RFC 4648 base64 - Specifies a 256-bit customer-supplied encryption key, encoded in RFC 4648 base64
to either encrypt or decrypt this resource. to either encrypt or decrypt this resource.
@ -229,18 +229,18 @@ items:
the default is PERSISTENT. the default is PERSISTENT.
returned: success returned: success
type: str type: str
guest_accelerators: guestAccelerators:
description: description:
- List of the type and count of accelerator cards attached to the instance . - List of the type and count of accelerator cards attached to the instance .
returned: success returned: success
type: complex type: complex
contains: contains:
accelerator_count: acceleratorCount:
description: description:
- The number of the guest accelerator cards exposed to this instance. - The number of the guest accelerator cards exposed to this instance.
returned: success returned: success
type: int type: int
accelerator_type: acceleratorType:
description: description:
- Full or partial URL of the accelerator type resource to expose to this instance. - Full or partial URL of the accelerator type resource to expose to this instance.
returned: success returned: success
@ -250,7 +250,7 @@ items:
- The unique identifier for the resource. This identifier is defined by the server. - The unique identifier for the resource. This identifier is defined by the server.
returned: success returned: success
type: int type: int
label_fingerprint: labelFingerprint:
description: description:
- A fingerprint for this request, which is essentially a hash of the metadata's contents - A fingerprint for this request, which is essentially a hash of the metadata's contents
and used for optimistic locking. The fingerprint is initially generated by Compute and used for optimistic locking. The fingerprint is initially generated by Compute
@ -264,12 +264,12 @@ items:
These pairs can consist of custom metadata or predefined keys. These pairs can consist of custom metadata or predefined keys.
returned: success returned: success
type: dict type: dict
machine_type: machineType:
description: description:
- A reference to a machine type which defines VM kind. - A reference to a machine type which defines VM kind.
returned: success returned: success
type: str type: str
min_cpu_platform: minCpuPlatform:
description: description:
- Specifies a minimum CPU platform for the VM instance. Applicable values are the - Specifies a minimum CPU platform for the VM instance. Applicable values are the
friendly names of CPU platforms . friendly names of CPU platforms .
@ -285,7 +285,7 @@ items:
be a dash. be a dash.
returned: success returned: success
type: str type: str
network_interfaces: networkInterfaces:
description: description:
- An array of configurations for this interface. This specifies how this interface - An array of configurations for this interface. This specifies how this interface
is configured to interact with other network services, such as connecting to the is configured to interact with other network services, such as connecting to the
@ -293,7 +293,7 @@ items:
returned: success returned: success
type: complex type: complex
contains: contains:
access_configs: accessConfigs:
description: description:
- An array of configurations for this interface. Currently, only one access config, - An array of configurations for this interface. Currently, only one access config,
ONE_TO_ONE_NAT, is supported. If there are no accessConfigs specified, then this ONE_TO_ONE_NAT, is supported. If there are no accessConfigs specified, then this
@ -308,7 +308,7 @@ items:
IP or Network Access. IP or Network Access.
returned: success returned: success
type: str type: str
nat_ip: natIP:
description: description:
- Specifies the title of a gcompute_address. - Specifies the title of a gcompute_address.
- An external IP address associated with this instance. - An external IP address associated with this instance.
@ -323,14 +323,14 @@ items:
- The type of configuration. The default and only option is ONE_TO_ONE_NAT. - The type of configuration. The default and only option is ONE_TO_ONE_NAT.
returned: success returned: success
type: str type: str
alias_ip_ranges: aliasIpRanges:
description: description:
- An array of alias IP ranges for this network interface. Can only be specified for - An array of alias IP ranges for this network interface. Can only be specified for
network interfaces on subnet-mode networks. network interfaces on subnet-mode networks.
returned: success returned: success
type: complex type: complex
contains: contains:
ip_cidr_range: ipCidrRange:
description: description:
- The IP CIDR range represented by this alias IP range. - The IP CIDR range represented by this alias IP range.
- This IP CIDR range must belong to the specified subnetwork and cannot contain IP - This IP CIDR range must belong to the specified subnetwork and cannot contain IP
@ -339,7 +339,7 @@ items:
(e.g. 10.1.2.0/24). (e.g. 10.1.2.0/24).
returned: success returned: success
type: str type: str
subnetwork_range_name: subnetworkRangeName:
description: description:
- Optional subnetwork secondary range name specifying the secondary range from which - Optional subnetwork secondary range name specifying the secondary range from which
to allocate the IP CIDR range for this alias IP range. If left unspecified, the to allocate the IP CIDR range for this alias IP range. If left unspecified, the
@ -360,7 +360,7 @@ items:
is inferred. is inferred.
returned: success returned: success
type: dict type: dict
network_ip: networkIP:
description: description:
- An IPv4 internal network address to assign to the instance for this network interface. - An IPv4 internal network address to assign to the instance for this network interface.
If not specified by the user, an unused internal IP is assigned by the system. If not specified by the user, an unused internal IP is assigned by the system.
@ -380,7 +380,7 @@ items:
returned: success returned: success
type: complex type: complex
contains: contains:
automatic_restart: automaticRestart:
description: description:
- Specifies whether the instance should be automatically restarted if it is terminated - Specifies whether the instance should be automatically restarted if it is terminated
by Compute Engine (not terminated by a user). by Compute Engine (not terminated by a user).
@ -388,7 +388,7 @@ items:
instances cannot be automatically restarted. instances cannot be automatically restarted.
returned: success returned: success
type: bool type: bool
on_host_maintenance: onHostMaintenance:
description: description:
- Defines the maintenance behavior for this instance. For standard instances, the - Defines the maintenance behavior for this instance. For standard instances, the
default behavior is MIGRATE. For preemptible instances, the default and only possible default behavior is MIGRATE. For preemptible instances, the default and only possible
@ -402,7 +402,7 @@ items:
creation, it cannot be set or changed after the instance has been created. creation, it cannot be set or changed after the instance has been created.
returned: success returned: success
type: bool type: bool
service_accounts: serviceAccounts:
description: description:
- A list of service accounts, with their specified scopes, authorized for this instance. - A list of service accounts, with their specified scopes, authorized for this instance.
Only one service account per VM instance is supported. Only one service account per VM instance is supported.
@ -425,7 +425,7 @@ items:
RUNNING, STOPPING, SUSPENDING, SUSPENDED, and TERMINATED.' RUNNING, STOPPING, SUSPENDING, SUSPENDED, and TERMINATED.'
returned: success returned: success
type: str type: str
status_message: statusMessage:
description: description:
- An optional, human-readable explanation of the status. - An optional, human-readable explanation of the status.
returned: success returned: success

@ -81,6 +81,11 @@ options:
network: network:
description: description:
- The network to which all instances in the instance group belong. - The network to which all instances in the instance group belong.
- 'This field represents a link to a Network resource in GCP. It can be specified
in two ways. You can add `register: name-of-resource` to a gcp_compute_network 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: false required: false
region: region:
description: description:
@ -89,11 +94,25 @@ options:
subnetwork: subnetwork:
description: description:
- The subnetwork to which all instances in the instance group belong. - The subnetwork to which all instances in the instance group belong.
- 'This field represents a link to a Subnetwork resource in GCP. It can be specified
in two ways. You can add `register: name-of-resource` to a gcp_compute_subnetwork
task and then set this subnetwork field to "{{ name-of-resource }}" Alternatively,
you can set this subnetwork to a dictionary with the selfLink key where the value
is the selfLink of your Subnetwork.'
required: false required: false
zone: zone:
description: description:
- A reference to the zone where the instance group resides. - A reference to the zone where the instance group resides.
required: true required: true
instances:
description:
- The list of instances associated with this InstanceGroup.
- All instances must be created before being added to an InstanceGroup.
- All instances not in this list will be removed from the InstanceGroup and will not
be deleted.
- Only the full identifier of the instance will be returned.
required: false
version_added: 2.8
extends_documentation_fragment: gcp extends_documentation_fragment: gcp
''' '''
@ -116,13 +135,13 @@ EXAMPLES = '''
network: "{{ network }}" network: "{{ network }}"
zone: us-central1-a zone: us-central1-a
project: "test_project" project: "test_project"
auth_kind: "service_account" auth_kind: "serviceaccount"
service_account_file: "/tmp/auth.pem" service_account_file: "/tmp/auth.pem"
state: present state: present
''' '''
RETURN = ''' RETURN = '''
creation_timestamp: creationTimestamp:
description: description:
- Creation timestamp in RFC3339 text format. - Creation timestamp in RFC3339 text format.
returned: success returned: success
@ -144,7 +163,7 @@ RETURN = '''
- The name must be 1-63 characters long, and comply with RFC1035. - The name must be 1-63 characters long, and comply with RFC1035.
returned: success returned: success
type: str type: str
named_ports: namedPorts:
description: description:
- Assigns a name to a port number. - Assigns a name to a port number.
- 'For example: {name: "http", port: 80}.' - 'For example: {name: "http", port: 80}.'
@ -186,6 +205,15 @@ RETURN = '''
- A reference to the zone where the instance group resides. - A reference to the zone where the instance group resides.
returned: success returned: success
type: str type: str
instances:
description:
- The list of instances associated with this InstanceGroup.
- All instances must be created before being added to an InstanceGroup.
- All instances not in this list will be removed from the InstanceGroup and will not
be deleted.
- Only the full identifier of the instance will be returned.
returned: success
type: list
''' '''
################################################################################ ################################################################################
@ -217,7 +245,8 @@ def main():
network=dict(type='dict'), network=dict(type='dict'),
region=dict(type='str'), region=dict(type='str'),
subnetwork=dict(type='dict'), subnetwork=dict(type='dict'),
zone=dict(required=True, type='str') zone=dict(required=True, type='str'),
instances=dict(type='list', elements='dict')
) )
) )
@ -233,7 +262,8 @@ def main():
if fetch: if fetch:
if state == 'present': if state == 'present':
if is_different(module, fetch): if is_different(module, fetch):
fetch = update(module, self_link(module), kind) update(module, self_link(module), kind)
fetch = fetch_resource(module, self_link(module), kind)
changed = True changed = True
else: else:
delete(module, self_link(module), kind) delete(module, self_link(module), kind)
@ -246,6 +276,10 @@ def main():
else: else:
fetch = {} fetch = {}
if fetch:
instance = InstanceLogic(module)
instance.run()
fetch.update({'instances': instance.list_instances()})
fetch.update({'changed': changed}) fetch.update({'changed': changed})
module.exit_json(**fetch) module.exit_json(**fetch)
@ -257,7 +291,8 @@ def create(module, link, kind):
def update(module, link, kind): def update(module, link, kind):
module.fail_json(msg="InstanceGroup cannot be edited") instance = InstanceLogic(module)
instance.run()
def delete(module, link, kind): def delete(module, link, kind):
@ -283,9 +318,9 @@ def resource_to_request(module):
return return_vals return return_vals
def fetch_resource(module, link, kind): def fetch_resource(module, link, kind, allow_not_found=True):
auth = GcpSession(module, 'compute') auth = GcpSession(module, 'compute')
return return_if_object(module, auth.get(link), kind) return return_if_object(module, auth.get(link), kind, allow_not_found)
def self_link(module): def self_link(module):
@ -296,9 +331,9 @@ def collection(module):
return "https://www.googleapis.com/compute/v1/projects/{project}/zones/{zone}/instanceGroups".format(**module.params) return "https://www.googleapis.com/compute/v1/projects/{project}/zones/{zone}/instanceGroups".format(**module.params)
def return_if_object(module, response, kind): def return_if_object(module, response, kind, allow_not_found=False):
# If not found, return nothing. # If not found, return nothing.
if response.status_code == 404: if allow_not_found and response.status_code == 404:
return None return None
# If no content, return nothing. # If no content, return nothing.
@ -313,8 +348,6 @@ def return_if_object(module, response, kind):
if navigate_hash(result, ['error', 'errors']): if navigate_hash(result, ['error', 'errors']):
module.fail_json(msg=navigate_hash(result, ['error', 'errors'])) module.fail_json(msg=navigate_hash(result, ['error', 'errors']))
if result['kind'] != kind:
module.fail_json(msg="Incorrect result: {kind}".format(**result))
return result return result
@ -398,6 +431,66 @@ def raise_if_errors(response, err_path, module):
module.fail_json(msg=errors) module.fail_json(msg=errors)
class InstanceLogic(object):
def __init__(self, module):
self.module = module
self.current_instances = self.list_instances()
self.module_instances = []
# Transform module list of instances (dicts of instance responses) into a list of selfLinks.
instances = self.module.params.get('instances')
if instances:
for instance in instances:
self.module_instances.append(replace_resource_dict(instance, 'selfLink'))
def run(self):
# Find all instances to add and add them
instances_to_add = list(set(self.module_instances) - set(self.current_instances))
if instances_to_add:
self.add_instances(instances_to_add)
# Find all instances to remove and remove them
instances_to_remove = list(set(self.current_instances) - set(self.module_instances))
if instances_to_remove:
self.remove_instances(instances_to_remove)
def list_instances(self):
auth = GcpSession(self.module, 'compute')
response = return_if_object(self.module, auth.post(self._list_instances_url(), {'instanceState': 'ALL'}),
'compute#instanceGroupsListInstances')
# Transform instance list into a list of selfLinks for diffing with module parameters
instances = []
for instance in response.get('items', []):
instances.append(instance['instance'])
return instances
def add_instances(self, instances):
auth = GcpSession(self.module, 'compute')
wait_for_operation(self.module, auth.post(self._add_instances_url(), self._build_request(instances)))
def remove_instances(self, instances):
auth = GcpSession(self.module, 'compute')
wait_for_operation(self.module, auth.post(self._remove_instances_url(), self._build_request(instances)))
def _list_instances_url(self):
return "https://www.googleapis.com/compute/v1/projects/{project}/zones/{zone}/instanceGroups/{name}/listInstances".format(**self.module.params)
def _remove_instances_url(self):
return "https://www.googleapis.com/compute/v1/projects/{project}/zones/{zone}/instanceGroups/{name}/removeInstances".format(**self.module.params)
def _add_instances_url(self):
return "https://www.googleapis.com/compute/v1/projects/{project}/zones/{zone}/instanceGroups/{name}/addInstances".format(**self.module.params)
def _build_request(self, instances):
request = {
'instances': []
}
for instance in instances:
request['instances'].append({'instance': instance})
return request
class InstanceGroupNamedPortsArray(object): class InstanceGroupNamedPortsArray(object):
def __init__(self, request, module): def __init__(self, request, module):
self.module = module self.module = module

@ -61,7 +61,7 @@ EXAMPLES = '''
filters: filters:
- name = test_object - name = test_object
project: test_project project: test_project
auth_kind: service_account auth_kind: serviceaccount
service_account_file: "/tmp/auth.pem" service_account_file: "/tmp/auth.pem"
''' '''
@ -71,7 +71,7 @@ items:
returned: always returned: always
type: complex type: complex
contains: contains:
creation_timestamp: creationTimestamp:
description: description:
- Creation timestamp in RFC3339 text format. - Creation timestamp in RFC3339 text format.
returned: success returned: success
@ -93,7 +93,7 @@ items:
- The name must be 1-63 characters long, and comply with RFC1035. - The name must be 1-63 characters long, and comply with RFC1035.
returned: success returned: success
type: str type: str
named_ports: namedPorts:
description: description:
- Assigns a name to a port number. - Assigns a name to a port number.
- 'For example: {name: "http", port: 80}.' - 'For example: {name: "http", port: 80}.'
@ -135,6 +135,15 @@ items:
- A reference to the zone where the instance group resides. - A reference to the zone where the instance group resides.
returned: success returned: success
type: str type: str
instances:
description:
- The list of instances associated with this InstanceGroup.
- All instances must be created before being added to an InstanceGroup.
- All instances not in this list will be removed from the InstanceGroup and will not
be deleted.
- Only the full identifier of the instance will be returned.
returned: success
type: list
''' '''
################################################################################ ################################################################################

@ -67,6 +67,11 @@ options:
description: description:
- The instance template that is specified for this managed instance group. The group - The instance template that is specified for this managed instance group. The group
uses this template to create all new instances in the managed instance group. uses this template to create all new instances in the managed instance group.
- 'This field represents a link to a InstanceTemplate resource in GCP. It can be specified
in two ways. You can add `register: name-of-resource` to a gcp_compute_instance_template
task and then set this instance_template field to "{{ name-of-resource }}" Alternatively,
you can set this instance_template to a dictionary with the selfLink key where the
value is the selfLink of your InstanceTemplate.'
required: true required: true
name: name:
description: description:
@ -156,13 +161,13 @@ EXAMPLES = '''
target_size: 3 target_size: 3
zone: us-west1-a zone: us-west1-a
project: "test_project" project: "test_project"
auth_kind: "service_account" auth_kind: "serviceaccount"
service_account_file: "/tmp/auth.pem" service_account_file: "/tmp/auth.pem"
state: present state: present
''' '''
RETURN = ''' RETURN = '''
base_instance_name: baseInstanceName:
description: description:
- The base instance name to use for instances in this group. The value must be 1-58 - The base instance name to use for instances in this group. The value must be 1-58
characters long. Instances are named by appending a hyphen and a random four-character characters long. Instances are named by appending a hyphen and a random four-character
@ -170,12 +175,12 @@ RETURN = '''
- The base instance name must comply with RFC1035. - The base instance name must comply with RFC1035.
returned: success returned: success
type: str type: str
creation_timestamp: creationTimestamp:
description: description:
- The creation timestamp for this managed instance group in RFC3339 text format. - The creation timestamp for this managed instance group in RFC3339 text format.
returned: success returned: success
type: str type: str
current_actions: currentActions:
description: description:
- The list of instance actions and the number of instances in this managed instance - The list of instance actions and the number of instances in this managed instance
group that are scheduled for each of those actions. group that are scheduled for each of those actions.
@ -198,7 +203,7 @@ RETURN = '''
the creatingWithoutRetries field will be populated. the creatingWithoutRetries field will be populated.
returned: success returned: success
type: int type: int
creating_without_retries: creatingWithoutRetries:
description: description:
- The number of instances that the managed instance group will attempt to create. - The number of instances that the managed instance group will attempt to create.
The group attempts to create each instance only once. If the group fails to create The group attempts to create each instance only once. If the group fails to create
@ -249,12 +254,12 @@ RETURN = '''
- A unique identifier for this resource. - A unique identifier for this resource.
returned: success returned: success
type: int type: int
instance_group: instanceGroup:
description: description:
- The instance group being managed. - The instance group being managed.
returned: success returned: success
type: dict type: dict
instance_template: instanceTemplate:
description: description:
- The instance template that is specified for this managed instance group. The group - The instance template that is specified for this managed instance group. The group
uses this template to create all new instances in the managed instance group. uses this template to create all new instances in the managed instance group.
@ -266,7 +271,7 @@ RETURN = '''
comply with RFC1035. comply with RFC1035.
returned: success returned: success
type: str type: str
named_ports: namedPorts:
description: description:
- Named ports configured for the Instance Groups complementary to this Instance Group - Named ports configured for the Instance Groups complementary to this Instance Group
Manager. Manager.
@ -289,14 +294,14 @@ RETURN = '''
- The region this managed instance group resides (for regional resources). - The region this managed instance group resides (for regional resources).
returned: success returned: success
type: str type: str
target_pools: targetPools:
description: description:
- TargetPool resources to which instances in the instanceGroup field are added. The - TargetPool resources to which instances in the instanceGroup field are added. The
target pools automatically apply to all of the instances in the managed instance target pools automatically apply to all of the instances in the managed instance
group. group.
returned: success returned: success
type: list type: list
target_size: targetSize:
description: description:
- The target number of running instances for this managed instance group. Deleting - The target number of running instances for this managed instance group. Deleting
or abandoning instances reduces this number. Resizing the group changes this number. or abandoning instances reduces this number. Resizing the group changes this number.
@ -355,7 +360,8 @@ def main():
if fetch: if fetch:
if state == 'present': if state == 'present':
if is_different(module, fetch): if is_different(module, fetch):
fetch = update(module, self_link(module), kind) update(module, self_link(module), kind)
fetch = fetch_resource(module, self_link(module), kind)
changed = True changed = True
else: else:
delete(module, self_link(module), kind) delete(module, self_link(module), kind)
@ -407,9 +413,9 @@ def resource_to_request(module):
return return_vals return return_vals
def fetch_resource(module, link, kind): def fetch_resource(module, link, kind, allow_not_found=True):
auth = GcpSession(module, 'compute') auth = GcpSession(module, 'compute')
return return_if_object(module, auth.get(link), kind) return return_if_object(module, auth.get(link), kind, allow_not_found)
def self_link(module): def self_link(module):
@ -420,9 +426,9 @@ def collection(module):
return "https://www.googleapis.com/compute/v1/projects/{project}/zones/{zone}/instanceGroupManagers".format(**module.params) return "https://www.googleapis.com/compute/v1/projects/{project}/zones/{zone}/instanceGroupManagers".format(**module.params)
def return_if_object(module, response, kind): def return_if_object(module, response, kind, allow_not_found=False):
# If not found, return nothing. # If not found, return nothing.
if response.status_code == 404: if allow_not_found and response.status_code == 404:
return None return None
# If no content, return nothing. # If no content, return nothing.
@ -437,8 +443,6 @@ def return_if_object(module, response, kind):
if navigate_hash(result, ['error', 'errors']): if navigate_hash(result, ['error', 'errors']):
module.fail_json(msg=navigate_hash(result, ['error', 'errors'])) module.fail_json(msg=navigate_hash(result, ['error', 'errors']))
if result['kind'] != kind:
module.fail_json(msg="Incorrect result: {kind}".format(**result))
return result return result

@ -61,7 +61,7 @@ EXAMPLES = '''
filters: filters:
- name = test_object - name = test_object
project: test_project project: test_project
auth_kind: service_account auth_kind: serviceaccount
service_account_file: "/tmp/auth.pem" service_account_file: "/tmp/auth.pem"
''' '''
@ -71,7 +71,7 @@ items:
returned: always returned: always
type: complex type: complex
contains: contains:
base_instance_name: baseInstanceName:
description: description:
- The base instance name to use for instances in this group. The value must be 1-58 - The base instance name to use for instances in this group. The value must be 1-58
characters long. Instances are named by appending a hyphen and a random four-character characters long. Instances are named by appending a hyphen and a random four-character
@ -79,12 +79,12 @@ items:
- The base instance name must comply with RFC1035. - The base instance name must comply with RFC1035.
returned: success returned: success
type: str type: str
creation_timestamp: creationTimestamp:
description: description:
- The creation timestamp for this managed instance group in RFC3339 text format. - The creation timestamp for this managed instance group in RFC3339 text format.
returned: success returned: success
type: str type: str
current_actions: currentActions:
description: description:
- The list of instance actions and the number of instances in this managed instance - The list of instance actions and the number of instances in this managed instance
group that are scheduled for each of those actions. group that are scheduled for each of those actions.
@ -107,7 +107,7 @@ items:
the creatingWithoutRetries field will be populated. the creatingWithoutRetries field will be populated.
returned: success returned: success
type: int type: int
creating_without_retries: creatingWithoutRetries:
description: description:
- The number of instances that the managed instance group will attempt to create. - The number of instances that the managed instance group will attempt to create.
The group attempts to create each instance only once. If the group fails to create The group attempts to create each instance only once. If the group fails to create
@ -158,12 +158,12 @@ items:
- A unique identifier for this resource. - A unique identifier for this resource.
returned: success returned: success
type: int type: int
instance_group: instanceGroup:
description: description:
- The instance group being managed. - The instance group being managed.
returned: success returned: success
type: dict type: dict
instance_template: instanceTemplate:
description: description:
- The instance template that is specified for this managed instance group. The group - The instance template that is specified for this managed instance group. The group
uses this template to create all new instances in the managed instance group. uses this template to create all new instances in the managed instance group.
@ -175,7 +175,7 @@ items:
comply with RFC1035. comply with RFC1035.
returned: success returned: success
type: str type: str
named_ports: namedPorts:
description: description:
- Named ports configured for the Instance Groups complementary to this Instance Group - Named ports configured for the Instance Groups complementary to this Instance Group
Manager. Manager.
@ -198,14 +198,14 @@ items:
- The region this managed instance group resides (for regional resources). - The region this managed instance group resides (for regional resources).
returned: success returned: success
type: str type: str
target_pools: targetPools:
description: description:
- TargetPool resources to which instances in the instanceGroup field are added. The - TargetPool resources to which instances in the instanceGroup field are added. The
target pools automatically apply to all of the instances in the managed instance target pools automatically apply to all of the instances in the managed instance
group. group.
returned: success returned: success
type: list type: list
target_size: targetSize:
description: description:
- The target number of running instances for this managed instance group. Deleting - The target number of running instances for this managed instance group. Deleting
or abandoning instances reduces this number. Resizing the group changes this number. or abandoning instances reduces this number. Resizing the group changes this number.

@ -200,6 +200,11 @@ options:
- If desired, you can also attach existing non-root persistent disks using this property. - If desired, you can also attach existing non-root persistent disks using this property.
This field is only applicable for persistent disks. This field is only applicable for persistent disks.
- Note that for InstanceTemplate, specify the disk name, not the URL for the disk. - Note that for InstanceTemplate, specify the disk name, not the URL for the disk.
- 'This field represents a link to a Disk resource in GCP. It can be specified in
two ways. You can add `register: name-of-resource` to a gcp_compute_disk task and
then set this source field to "{{ name-of-resource }}" Alternatively, you can set
this source to a dictionary with the name key where the value is the name of your
Disk.'
required: false required: false
type: type:
description: description:
@ -257,6 +262,11 @@ options:
field undefined to use an IP from a shared ephemeral IP address pool. If you specify field undefined to use an IP from a shared ephemeral IP address pool. If you specify
a static external IP address, it must live in the same region as the zone of the a static external IP address, it must live in the same region as the zone of the
instance. instance.
- 'This field represents a link to a Address resource in GCP. It can be specified
in two ways. You can add `register: name-of-resource` to a gcp_compute_address task
and then set this nat_ip field to "{{ name-of-resource }}" Alternatively, you can
set this nat_ip to a dictionary with the address key where the value is the address
of your Address.'
required: false required: false
type: type:
description: description:
@ -294,6 +304,11 @@ options:
if neither the network nor the subnetwork is specified, the default network global/networks/default if neither the network nor the subnetwork is specified, the default network global/networks/default
is used; if the network is not specified but the subnetwork is specified, the network is used; if the network is not specified but the subnetwork is specified, the network
is inferred. is inferred.
- 'This field represents a link to a Network resource in GCP. It can be specified
in two ways. You can add `register: name-of-resource` to a gcp_compute_network 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: false required: false
network_ip: network_ip:
description: description:
@ -306,6 +321,11 @@ options:
- If the network resource is in legacy mode, do not provide this property. If the - If the network resource is in legacy mode, do not provide this property. If the
network is in auto subnet mode, providing the subnetwork is optional. If the network network is in auto subnet mode, providing the subnetwork is optional. If the network
is in custom subnet mode, then this field should be specified. is in custom subnet mode, then this field should be specified.
- 'This field represents a link to a Subnetwork resource in GCP. It can be specified
in two ways. You can add `register: name-of-resource` to a gcp_compute_subnetwork
task and then set this subnetwork field to "{{ name-of-resource }}" Alternatively,
you can set this subnetwork to a dictionary with the selfLink key where the value
is the selfLink of your Subnetwork.'
required: false required: false
scheduling: scheduling:
description: description:
@ -407,13 +427,13 @@ EXAMPLES = '''
type: ONE_TO_ONE_NAT type: ONE_TO_ONE_NAT
nat_ip: "{{ address }}" nat_ip: "{{ address }}"
project: "test_project" project: "test_project"
auth_kind: "service_account" auth_kind: "serviceaccount"
service_account_file: "/tmp/auth.pem" service_account_file: "/tmp/auth.pem"
state: present state: present
''' '''
RETURN = ''' RETURN = '''
creation_timestamp: creationTimestamp:
description: description:
- Creation timestamp in RFC3339 text format. - Creation timestamp in RFC3339 text format.
returned: success returned: success
@ -440,7 +460,7 @@ RETURN = '''
returned: success returned: success
type: complex type: complex
contains: contains:
can_ip_forward: canIpForward:
description: description:
- Enables instances created based on this template to send packets with source IP - Enables instances created based on this template to send packets with source IP
addresses other than their own and receive packets with destination IP addresses addresses other than their own and receive packets with destination IP addresses
@ -462,7 +482,7 @@ RETURN = '''
returned: success returned: success
type: complex type: complex
contains: contains:
auto_delete: autoDelete:
description: description:
- Specifies whether the disk will be auto-deleted when the instance is deleted (but - Specifies whether the disk will be auto-deleted when the instance is deleted (but
not when the disk is detached from the instance). not when the disk is detached from the instance).
@ -476,26 +496,26 @@ RETURN = '''
of the disk for its root filesystem. of the disk for its root filesystem.
returned: success returned: success
type: bool type: bool
device_name: deviceName:
description: description:
- Specifies a unique device name of your choice that is reflected into the /dev/disk/by-id/google-* - Specifies a unique device name of your choice that is reflected into the /dev/disk/by-id/google-*
tree of a Linux operating system running within the instance. This name can be used tree of a Linux operating system running within the instance. This name can be used
to reference the device for mounting, resizing, and so on, from within the instance. to reference the device for mounting, resizing, and so on, from within the instance.
returned: success returned: success
type: str type: str
disk_encryption_key: diskEncryptionKey:
description: description:
- Encrypts or decrypts a disk using a customer-supplied encryption key. - Encrypts or decrypts a disk using a customer-supplied encryption key.
returned: success returned: success
type: complex type: complex
contains: contains:
raw_key: rawKey:
description: description:
- Specifies a 256-bit customer-supplied encryption key, encoded in RFC 4648 base64 - Specifies a 256-bit customer-supplied encryption key, encoded in RFC 4648 base64
to either encrypt or decrypt this resource. to either encrypt or decrypt this resource.
returned: success returned: success
type: str type: str
rsa_encrypted_key: rsaEncryptedKey:
description: description:
- Specifies an RFC 4648 base64 encoded, RSA-wrapped 2048-bit customer-supplied encryption - Specifies an RFC 4648 base64 encoded, RSA-wrapped 2048-bit customer-supplied encryption
key to either encrypt or decrypt this resource. key to either encrypt or decrypt this resource.
@ -514,7 +534,7 @@ RETURN = '''
a unique index number. If not specified, the server will choose an appropriate value. a unique index number. If not specified, the server will choose an appropriate value.
returned: success returned: success
type: int type: int
initialize_params: initializeParams:
description: description:
- Specifies the parameters for a new disk that will be created alongside the new instance. - Specifies the parameters for a new disk that will be created alongside the new instance.
Use initialization parameters to create boot disks or local SSDs attached to the Use initialization parameters to create boot disks or local SSDs attached to the
@ -522,32 +542,32 @@ RETURN = '''
returned: success returned: success
type: complex type: complex
contains: contains:
disk_name: diskName:
description: description:
- Specifies the disk name. If not specified, the default is to use the name of the - Specifies the disk name. If not specified, the default is to use the name of the
instance. instance.
returned: success returned: success
type: str type: str
disk_size_gb: diskSizeGb:
description: description:
- Specifies the size of the disk in base-2 GB. - Specifies the size of the disk in base-2 GB.
returned: success returned: success
type: int type: int
disk_type: diskType:
description: description:
- Reference to a gcompute_disk_type resource. - Reference to a gcompute_disk_type resource.
- Specifies the disk type to use to create the instance. - Specifies the disk type to use to create the instance.
- If not specified, the default is pd-standard. - If not specified, the default is pd-standard.
returned: success returned: success
type: str type: str
source_image: sourceImage:
description: description:
- The source image to create this disk. When creating a new instance, one of initializeParams.sourceImage - The source image to create this disk. When creating a new instance, one of initializeParams.sourceImage
or disks.source is required. To create a disk with one of the public operating or disks.source is required. To create a disk with one of the public operating
system images, specify the image by its family name. system images, specify the image by its family name.
returned: success returned: success
type: str type: str
source_image_encryption_key: sourceImageEncryptionKey:
description: description:
- The customer-supplied encryption key of the source image. Required if the source - The customer-supplied encryption key of the source image. Required if the source
image is protected by a customer-supplied encryption key. image is protected by a customer-supplied encryption key.
@ -557,7 +577,7 @@ RETURN = '''
returned: success returned: success
type: complex type: complex
contains: contains:
raw_key: rawKey:
description: description:
- Specifies a 256-bit customer-supplied encryption key, encoded in RFC 4648 base64 - Specifies a 256-bit customer-supplied encryption key, encoded in RFC 4648 base64
to either encrypt or decrypt this resource. to either encrypt or decrypt this resource.
@ -598,7 +618,7 @@ RETURN = '''
the default is PERSISTENT. the default is PERSISTENT.
returned: success returned: success
type: str type: str
machine_type: machineType:
description: description:
- Reference to a gcompute_machine_type resource. - Reference to a gcompute_machine_type resource.
returned: success returned: success
@ -609,23 +629,23 @@ RETURN = '''
These pairs can consist of custom metadata or predefined keys. These pairs can consist of custom metadata or predefined keys.
returned: success returned: success
type: dict type: dict
guest_accelerators: guestAccelerators:
description: description:
- List of the type and count of accelerator cards attached to the instance . - List of the type and count of accelerator cards attached to the instance .
returned: success returned: success
type: complex type: complex
contains: contains:
accelerator_count: acceleratorCount:
description: description:
- The number of the guest accelerator cards exposed to this instance. - The number of the guest accelerator cards exposed to this instance.
returned: success returned: success
type: int type: int
accelerator_type: acceleratorType:
description: description:
- Full or partial URL of the accelerator type resource to expose to this instance. - Full or partial URL of the accelerator type resource to expose to this instance.
returned: success returned: success
type: str type: str
network_interfaces: networkInterfaces:
description: description:
- An array of configurations for this interface. This specifies how this interface - An array of configurations for this interface. This specifies how this interface
is configured to interact with other network services, such as connecting to the is configured to interact with other network services, such as connecting to the
@ -633,7 +653,7 @@ RETURN = '''
returned: success returned: success
type: complex type: complex
contains: contains:
access_configs: accessConfigs:
description: description:
- An array of configurations for this interface. Currently, only one access config, - An array of configurations for this interface. Currently, only one access config,
ONE_TO_ONE_NAT, is supported. If there are no accessConfigs specified, then this ONE_TO_ONE_NAT, is supported. If there are no accessConfigs specified, then this
@ -648,7 +668,7 @@ RETURN = '''
IP or Network Access. IP or Network Access.
returned: success returned: success
type: str type: str
nat_ip: natIP:
description: description:
- Specifies the title of a gcompute_address. - Specifies the title of a gcompute_address.
- An external IP address associated with this instance. - An external IP address associated with this instance.
@ -663,14 +683,14 @@ RETURN = '''
- The type of configuration. The default and only option is ONE_TO_ONE_NAT. - The type of configuration. The default and only option is ONE_TO_ONE_NAT.
returned: success returned: success
type: str type: str
alias_ip_ranges: aliasIpRanges:
description: description:
- An array of alias IP ranges for this network interface. Can only be specified for - An array of alias IP ranges for this network interface. Can only be specified for
network interfaces on subnet-mode networks. network interfaces on subnet-mode networks.
returned: success returned: success
type: complex type: complex
contains: contains:
ip_cidr_range: ipCidrRange:
description: description:
- The IP CIDR range represented by this alias IP range. - The IP CIDR range represented by this alias IP range.
- This IP CIDR range must belong to the specified subnetwork and cannot contain IP - This IP CIDR range must belong to the specified subnetwork and cannot contain IP
@ -679,7 +699,7 @@ RETURN = '''
(e.g. 10.1.2.0/24). (e.g. 10.1.2.0/24).
returned: success returned: success
type: str type: str
subnetwork_range_name: subnetworkRangeName:
description: description:
- Optional subnetwork secondary range name specifying the secondary range from which - Optional subnetwork secondary range name specifying the secondary range from which
to allocate the IP CIDR range for this alias IP range. If left unspecified, the to allocate the IP CIDR range for this alias IP range. If left unspecified, the
@ -700,7 +720,7 @@ RETURN = '''
is inferred. is inferred.
returned: success returned: success
type: dict type: dict
network_ip: networkIP:
description: description:
- An IPv4 internal network address to assign to the instance for this network interface. - An IPv4 internal network address to assign to the instance for this network interface.
If not specified by the user, an unused internal IP is assigned by the system. If not specified by the user, an unused internal IP is assigned by the system.
@ -720,7 +740,7 @@ RETURN = '''
returned: success returned: success
type: complex type: complex
contains: contains:
automatic_restart: automaticRestart:
description: description:
- Specifies whether the instance should be automatically restarted if it is terminated - Specifies whether the instance should be automatically restarted if it is terminated
by Compute Engine (not terminated by a user). by Compute Engine (not terminated by a user).
@ -728,7 +748,7 @@ RETURN = '''
instances cannot be automatically restarted. instances cannot be automatically restarted.
returned: success returned: success
type: bool type: bool
on_host_maintenance: onHostMaintenance:
description: description:
- Defines the maintenance behavior for this instance. For standard instances, the - Defines the maintenance behavior for this instance. For standard instances, the
default behavior is MIGRATE. For preemptible instances, the default and only possible default behavior is MIGRATE. For preemptible instances, the default and only possible
@ -742,7 +762,7 @@ RETURN = '''
creation, it cannot be set or changed after the instance has been created. creation, it cannot be set or changed after the instance has been created.
returned: success returned: success
type: bool type: bool
service_accounts: serviceAccounts:
description: description:
- A list of service accounts, with their specified scopes, authorized for this instance. - A list of service accounts, with their specified scopes, authorized for this instance.
Only one service account per VM instance is supported. Only one service account per VM instance is supported.
@ -884,7 +904,8 @@ def main():
if fetch: if fetch:
if state == 'present': if state == 'present':
if is_different(module, fetch): if is_different(module, fetch):
fetch = update(module, self_link(module), kind) update(module, self_link(module), kind)
fetch = fetch_resource(module, self_link(module), kind)
changed = True changed = True
else: else:
delete(module, self_link(module), kind) delete(module, self_link(module), kind)
@ -908,8 +929,7 @@ def create(module, link, kind):
def update(module, link, kind): def update(module, link, kind):
auth = GcpSession(module, 'compute') module.fail_json(msg="InstanceTemplate cannot be edited")
return wait_for_operation(module, auth.put(link, resource_to_request(module)))
def delete(module, link, kind): def delete(module, link, kind):
@ -933,9 +953,9 @@ def resource_to_request(module):
return return_vals return return_vals
def fetch_resource(module, link, kind): def fetch_resource(module, link, kind, allow_not_found=True):
auth = GcpSession(module, 'compute') auth = GcpSession(module, 'compute')
return return_if_object(module, auth.get(link), kind) return return_if_object(module, auth.get(link), kind, allow_not_found)
def self_link(module): def self_link(module):
@ -946,9 +966,9 @@ def collection(module):
return "https://www.googleapis.com/compute/v1/projects/{project}/global/instanceTemplates".format(**module.params) return "https://www.googleapis.com/compute/v1/projects/{project}/global/instanceTemplates".format(**module.params)
def return_if_object(module, response, kind): def return_if_object(module, response, kind, allow_not_found=False):
# If not found, return nothing. # If not found, return nothing.
if response.status_code == 404: if allow_not_found and response.status_code == 404:
return None return None
# If no content, return nothing. # If no content, return nothing.
@ -965,8 +985,6 @@ def return_if_object(module, response, kind):
if navigate_hash(result, ['error', 'errors']): if navigate_hash(result, ['error', 'errors']):
module.fail_json(msg=navigate_hash(result, ['error', 'errors'])) module.fail_json(msg=navigate_hash(result, ['error', 'errors']))
if result['kind'] != kind:
module.fail_json(msg="Incorrect result: {kind}".format(**result))
return result return result
@ -1005,7 +1023,7 @@ def response_to_hash(module, response):
def disk_type_selflink(name, params): def disk_type_selflink(name, params):
if name is None: if name is None:
return return
url = r"https://www.googleapis.com/compute/v1/projects/.*/zones/{zone}/diskTypes/[a-z1-9\-]*" url = r"https://www.googleapis.com/compute/v1/projects/.*/zones/[a-z1-9\-]*/diskTypes/[a-z1-9\-]*"
if not re.match(url, name): if not re.match(url, name):
name = "https://www.googleapis.com/compute/v1/projects/{project}/zones/{zone}/diskTypes/%s".format(**params) % name name = "https://www.googleapis.com/compute/v1/projects/{project}/zones/{zone}/diskTypes/%s".format(**params) % name
return name return name
@ -1049,13 +1067,13 @@ def raise_if_errors(response, err_path, module):
def encode_request(request, module): def encode_request(request, module):
if 'metadata' in request: if 'metadata' in request and request['metadata'] is not None:
request['metadata'] = metadata_encoder(request['metadata']) request['metadata'] = metadata_encoder(request['metadata'])
return request return request
def decode_response(response, module): def decode_response(response, module):
if 'metadata' in response: if 'metadata' in response and response['metadata'] is not None:
response['metadata'] = metadata_decoder(response['metadata']) response['metadata'] = metadata_decoder(response['metadata'])
return response return response

@ -56,7 +56,7 @@ EXAMPLES = '''
filters: filters:
- name = test_object - name = test_object
project: test_project project: test_project
auth_kind: service_account auth_kind: serviceaccount
service_account_file: "/tmp/auth.pem" service_account_file: "/tmp/auth.pem"
''' '''
@ -66,7 +66,7 @@ items:
returned: always returned: always
type: complex type: complex
contains: contains:
creation_timestamp: creationTimestamp:
description: description:
- Creation timestamp in RFC3339 text format. - Creation timestamp in RFC3339 text format.
returned: success returned: success
@ -93,7 +93,7 @@ items:
returned: success returned: success
type: complex type: complex
contains: contains:
can_ip_forward: canIpForward:
description: description:
- Enables instances created based on this template to send packets with source IP - Enables instances created based on this template to send packets with source IP
addresses other than their own and receive packets with destination IP addresses addresses other than their own and receive packets with destination IP addresses
@ -115,7 +115,7 @@ items:
returned: success returned: success
type: complex type: complex
contains: contains:
auto_delete: autoDelete:
description: description:
- Specifies whether the disk will be auto-deleted when the instance is deleted (but - Specifies whether the disk will be auto-deleted when the instance is deleted (but
not when the disk is detached from the instance). not when the disk is detached from the instance).
@ -129,26 +129,26 @@ items:
of the disk for its root filesystem. of the disk for its root filesystem.
returned: success returned: success
type: bool type: bool
device_name: deviceName:
description: description:
- Specifies a unique device name of your choice that is reflected into the /dev/disk/by-id/google-* - Specifies a unique device name of your choice that is reflected into the /dev/disk/by-id/google-*
tree of a Linux operating system running within the instance. This name can be used tree of a Linux operating system running within the instance. This name can be used
to reference the device for mounting, resizing, and so on, from within the instance. to reference the device for mounting, resizing, and so on, from within the instance.
returned: success returned: success
type: str type: str
disk_encryption_key: diskEncryptionKey:
description: description:
- Encrypts or decrypts a disk using a customer-supplied encryption key. - Encrypts or decrypts a disk using a customer-supplied encryption key.
returned: success returned: success
type: complex type: complex
contains: contains:
raw_key: rawKey:
description: description:
- Specifies a 256-bit customer-supplied encryption key, encoded in RFC 4648 base64 - Specifies a 256-bit customer-supplied encryption key, encoded in RFC 4648 base64
to either encrypt or decrypt this resource. to either encrypt or decrypt this resource.
returned: success returned: success
type: str type: str
rsa_encrypted_key: rsaEncryptedKey:
description: description:
- Specifies an RFC 4648 base64 encoded, RSA-wrapped 2048-bit customer-supplied encryption - Specifies an RFC 4648 base64 encoded, RSA-wrapped 2048-bit customer-supplied encryption
key to either encrypt or decrypt this resource. key to either encrypt or decrypt this resource.
@ -167,7 +167,7 @@ items:
a unique index number. If not specified, the server will choose an appropriate value. a unique index number. If not specified, the server will choose an appropriate value.
returned: success returned: success
type: int type: int
initialize_params: initializeParams:
description: description:
- Specifies the parameters for a new disk that will be created alongside the new instance. - Specifies the parameters for a new disk that will be created alongside the new instance.
Use initialization parameters to create boot disks or local SSDs attached to the Use initialization parameters to create boot disks or local SSDs attached to the
@ -175,32 +175,32 @@ items:
returned: success returned: success
type: complex type: complex
contains: contains:
disk_name: diskName:
description: description:
- Specifies the disk name. If not specified, the default is to use the name of the - Specifies the disk name. If not specified, the default is to use the name of the
instance. instance.
returned: success returned: success
type: str type: str
disk_size_gb: diskSizeGb:
description: description:
- Specifies the size of the disk in base-2 GB. - Specifies the size of the disk in base-2 GB.
returned: success returned: success
type: int type: int
disk_type: diskType:
description: description:
- Reference to a gcompute_disk_type resource. - Reference to a gcompute_disk_type resource.
- Specifies the disk type to use to create the instance. - Specifies the disk type to use to create the instance.
- If not specified, the default is pd-standard. - If not specified, the default is pd-standard.
returned: success returned: success
type: str type: str
source_image: sourceImage:
description: description:
- The source image to create this disk. When creating a new instance, one of initializeParams.sourceImage - The source image to create this disk. When creating a new instance, one of initializeParams.sourceImage
or disks.source is required. To create a disk with one of the public operating or disks.source is required. To create a disk with one of the public operating
system images, specify the image by its family name. system images, specify the image by its family name.
returned: success returned: success
type: str type: str
source_image_encryption_key: sourceImageEncryptionKey:
description: description:
- The customer-supplied encryption key of the source image. Required if the source - The customer-supplied encryption key of the source image. Required if the source
image is protected by a customer-supplied encryption key. image is protected by a customer-supplied encryption key.
@ -210,7 +210,7 @@ items:
returned: success returned: success
type: complex type: complex
contains: contains:
raw_key: rawKey:
description: description:
- Specifies a 256-bit customer-supplied encryption key, encoded in RFC 4648 base64 - Specifies a 256-bit customer-supplied encryption key, encoded in RFC 4648 base64
to either encrypt or decrypt this resource. to either encrypt or decrypt this resource.
@ -251,7 +251,7 @@ items:
the default is PERSISTENT. the default is PERSISTENT.
returned: success returned: success
type: str type: str
machine_type: machineType:
description: description:
- Reference to a gcompute_machine_type resource. - Reference to a gcompute_machine_type resource.
returned: success returned: success
@ -262,23 +262,23 @@ items:
These pairs can consist of custom metadata or predefined keys. These pairs can consist of custom metadata or predefined keys.
returned: success returned: success
type: dict type: dict
guest_accelerators: guestAccelerators:
description: description:
- List of the type and count of accelerator cards attached to the instance . - List of the type and count of accelerator cards attached to the instance .
returned: success returned: success
type: complex type: complex
contains: contains:
accelerator_count: acceleratorCount:
description: description:
- The number of the guest accelerator cards exposed to this instance. - The number of the guest accelerator cards exposed to this instance.
returned: success returned: success
type: int type: int
accelerator_type: acceleratorType:
description: description:
- Full or partial URL of the accelerator type resource to expose to this instance. - Full or partial URL of the accelerator type resource to expose to this instance.
returned: success returned: success
type: str type: str
network_interfaces: networkInterfaces:
description: description:
- An array of configurations for this interface. This specifies how this interface - An array of configurations for this interface. This specifies how this interface
is configured to interact with other network services, such as connecting to the is configured to interact with other network services, such as connecting to the
@ -286,7 +286,7 @@ items:
returned: success returned: success
type: complex type: complex
contains: contains:
access_configs: accessConfigs:
description: description:
- An array of configurations for this interface. Currently, only one access config, - An array of configurations for this interface. Currently, only one access config,
ONE_TO_ONE_NAT, is supported. If there are no accessConfigs specified, then this ONE_TO_ONE_NAT, is supported. If there are no accessConfigs specified, then this
@ -301,7 +301,7 @@ items:
IP or Network Access. IP or Network Access.
returned: success returned: success
type: str type: str
nat_ip: natIP:
description: description:
- Specifies the title of a gcompute_address. - Specifies the title of a gcompute_address.
- An external IP address associated with this instance. - An external IP address associated with this instance.
@ -316,14 +316,14 @@ items:
- The type of configuration. The default and only option is ONE_TO_ONE_NAT. - The type of configuration. The default and only option is ONE_TO_ONE_NAT.
returned: success returned: success
type: str type: str
alias_ip_ranges: aliasIpRanges:
description: description:
- An array of alias IP ranges for this network interface. Can only be specified for - An array of alias IP ranges for this network interface. Can only be specified for
network interfaces on subnet-mode networks. network interfaces on subnet-mode networks.
returned: success returned: success
type: complex type: complex
contains: contains:
ip_cidr_range: ipCidrRange:
description: description:
- The IP CIDR range represented by this alias IP range. - The IP CIDR range represented by this alias IP range.
- This IP CIDR range must belong to the specified subnetwork and cannot contain IP - This IP CIDR range must belong to the specified subnetwork and cannot contain IP
@ -332,7 +332,7 @@ items:
(e.g. 10.1.2.0/24). (e.g. 10.1.2.0/24).
returned: success returned: success
type: str type: str
subnetwork_range_name: subnetworkRangeName:
description: description:
- Optional subnetwork secondary range name specifying the secondary range from which - Optional subnetwork secondary range name specifying the secondary range from which
to allocate the IP CIDR range for this alias IP range. If left unspecified, the to allocate the IP CIDR range for this alias IP range. If left unspecified, the
@ -353,7 +353,7 @@ items:
is inferred. is inferred.
returned: success returned: success
type: dict type: dict
network_ip: networkIP:
description: description:
- An IPv4 internal network address to assign to the instance for this network interface. - An IPv4 internal network address to assign to the instance for this network interface.
If not specified by the user, an unused internal IP is assigned by the system. If not specified by the user, an unused internal IP is assigned by the system.
@ -373,7 +373,7 @@ items:
returned: success returned: success
type: complex type: complex
contains: contains:
automatic_restart: automaticRestart:
description: description:
- Specifies whether the instance should be automatically restarted if it is terminated - Specifies whether the instance should be automatically restarted if it is terminated
by Compute Engine (not terminated by a user). by Compute Engine (not terminated by a user).
@ -381,7 +381,7 @@ items:
instances cannot be automatically restarted. instances cannot be automatically restarted.
returned: success returned: success
type: bool type: bool
on_host_maintenance: onHostMaintenance:
description: description:
- Defines the maintenance behavior for this instance. For standard instances, the - Defines the maintenance behavior for this instance. For standard instances, the
default behavior is MIGRATE. For preemptible instances, the default and only possible default behavior is MIGRATE. For preemptible instances, the default and only possible
@ -395,7 +395,7 @@ items:
creation, it cannot be set or changed after the instance has been created. creation, it cannot be set or changed after the instance has been created.
returned: success returned: success
type: bool type: bool
service_accounts: serviceAccounts:
description: description:
- A list of service accounts, with their specified scopes, authorized for this instance. - A list of service accounts, with their specified scopes, authorized for this instance.
Only one service account per VM instance is supported. Only one service account per VM instance is supported.
@ -451,7 +451,7 @@ import json
def main(): def main():
module = GcpModule( module = GcpModule(
argument_spec=dict( argument_spec=dict(
filters=dict(type='list', elements='str'), filters=dict(type='list', elements='str')
) )
) )

@ -62,12 +62,6 @@ options:
- An optional description of this resource. Provide this property when you create - An optional description of this resource. Provide this property when you create
the resource. the resource.
required: false required: false
gateway_ipv4:
description:
- A gateway address for default routing to other networks. This value is read only
and is selected by the Google Compute Engine, typically as the first usable address
in the IPv4Range.
required: false
ipv4_range: ipv4_range:
description: description:
- 'The range of internal addresses that are legal on this network. This range is a - 'The range of internal addresses that are legal on this network. This range is a
@ -82,7 +76,7 @@ options:
which means the first character must be a lowercase letter, and all following characters which means the first character must be a lowercase letter, and all following characters
must be a dash, lowercase letter, or digit, except the last character, which cannot must be a dash, lowercase letter, or digit, except the last character, which cannot
be a dash. be a dash.
required: false required: true
auto_create_subnetworks: auto_create_subnetworks:
description: description:
- When set to true, the network is created in "auto subnet mode". When set to false, - When set to true, the network is created in "auto subnet mode". When set to false,
@ -91,7 +85,25 @@ options:
and it automatically creates one subnetwork per region. and it automatically creates one subnetwork per region.
required: false required: false
type: bool type: bool
routing_config:
description:
- The network-level routing configuration for this network. Used by Cloud Router to
determine what type of network-wide routing behavior to enforce.
required: false
version_added: 2.8
suboptions:
routing_mode:
description:
- The network-wide routing mode to use. If set to REGIONAL, this network's cloud routers
will only advertise routes with subnetworks of this network in the same region as
the router. If set to GLOBAL, this network's cloud routers will advertise routes
with all subnetworks of this network, across regions.
required: true
choices: ['REGIONAL', 'GLOBAL']
extends_documentation_fragment: gcp extends_documentation_fragment: gcp
notes:
- "API Reference: U(https://cloud.google.com/compute/docs/reference/rest/v1/networks)"
- "Official Documentation: U(https://cloud.google.com/vpc/docs/vpc)"
''' '''
EXAMPLES = ''' EXAMPLES = '''
@ -100,7 +112,7 @@ EXAMPLES = '''
name: "test_object" name: "test_object"
auto_create_subnetworks: true auto_create_subnetworks: true
project: "test_project" project: "test_project"
auth_kind: "service_account" auth_kind: "serviceaccount"
service_account_file: "/tmp/auth.pem" service_account_file: "/tmp/auth.pem"
state: present state: present
''' '''
@ -146,7 +158,7 @@ RETURN = '''
- Server-defined fully-qualified URLs for all subnetworks in this network. - Server-defined fully-qualified URLs for all subnetworks in this network.
returned: success returned: success
type: list type: list
auto_create_subnetworks: autoCreateSubnetworks:
description: description:
- When set to true, the network is created in "auto subnet mode". When set to false, - When set to true, the network is created in "auto subnet mode". When set to false,
the network is in "custom subnet mode". the network is in "custom subnet mode".
@ -154,18 +166,33 @@ RETURN = '''
and it automatically creates one subnetwork per region. and it automatically creates one subnetwork per region.
returned: success returned: success
type: bool type: bool
creation_timestamp: creationTimestamp:
description: description:
- Creation timestamp in RFC3339 text format. - Creation timestamp in RFC3339 text format.
returned: success returned: success
type: str type: str
routingConfig:
description:
- The network-level routing configuration for this network. Used by Cloud Router to
determine what type of network-wide routing behavior to enforce.
returned: success
type: complex
contains:
routingMode:
description:
- The network-wide routing mode to use. If set to REGIONAL, this network's cloud routers
will only advertise routes with subnetworks of this network in the same region as
the router. If set to GLOBAL, this network's cloud routers will advertise routes
with all subnetworks of this network, across regions.
returned: success
type: str
''' '''
################################################################################ ################################################################################
# Imports # Imports
################################################################################ ################################################################################
from ansible.module_utils.gcp_utils import navigate_hash, GcpSession, GcpModule, GcpRequest, replace_resource_dict from ansible.module_utils.gcp_utils import navigate_hash, GcpSession, GcpModule, GcpRequest, remove_nones_from_dict, replace_resource_dict
import json import json
import time import time
@ -181,10 +208,12 @@ def main():
argument_spec=dict( argument_spec=dict(
state=dict(default='present', choices=['present', 'absent'], type='str'), state=dict(default='present', choices=['present', 'absent'], type='str'),
description=dict(type='str'), description=dict(type='str'),
gateway_ipv4=dict(type='str'),
ipv4_range=dict(type='str'), ipv4_range=dict(type='str'),
name=dict(type='str'), name=dict(required=True, type='str'),
auto_create_subnetworks=dict(type='bool') auto_create_subnetworks=dict(type='bool'),
routing_config=dict(type='list', elements='dict', options=dict(
routing_mode=dict(required=True, type='str', choices=['REGIONAL', 'GLOBAL'])
))
) )
) )
@ -200,7 +229,8 @@ def main():
if fetch: if fetch:
if state == 'present': if state == 'present':
if is_different(module, fetch): if is_different(module, fetch):
fetch = update(module, self_link(module), kind) update(module, self_link(module), kind, fetch)
fetch = fetch_resource(module, self_link(module), kind)
changed = True changed = True
else: else:
delete(module, self_link(module), kind) delete(module, self_link(module), kind)
@ -223,9 +253,29 @@ def create(module, link, kind):
return wait_for_operation(module, auth.post(link, resource_to_request(module))) return wait_for_operation(module, auth.post(link, resource_to_request(module)))
def update(module, link, kind): def update(module, link, kind, fetch):
update_fields(module, resource_to_request(module),
response_to_hash(module, fetch))
auth = GcpSession(module, 'compute') auth = GcpSession(module, 'compute')
return wait_for_operation(module, auth.put(link, resource_to_request(module))) 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): def delete(module, link, kind):
@ -237,10 +287,10 @@ def resource_to_request(module):
request = { request = {
u'kind': 'compute#network', u'kind': 'compute#network',
u'description': module.params.get('description'), u'description': module.params.get('description'),
u'gatewayIPv4': module.params.get('gateway_ipv4'),
u'IPv4Range': module.params.get('ipv4_range'), u'IPv4Range': module.params.get('ipv4_range'),
u'name': module.params.get('name'), u'name': module.params.get('name'),
u'autoCreateSubnetworks': module.params.get('auto_create_subnetworks') u'autoCreateSubnetworks': module.params.get('auto_create_subnetworks'),
u'routingConfig': NetworkRoutingConfigArray(module.params.get('routing_config', []), module).to_request()
} }
return_vals = {} return_vals = {}
for k, v in request.items(): for k, v in request.items():
@ -250,9 +300,9 @@ def resource_to_request(module):
return return_vals return return_vals
def fetch_resource(module, link, kind): def fetch_resource(module, link, kind, allow_not_found=True):
auth = GcpSession(module, 'compute') auth = GcpSession(module, 'compute')
return return_if_object(module, auth.get(link), kind) return return_if_object(module, auth.get(link), kind, allow_not_found)
def self_link(module): def self_link(module):
@ -263,9 +313,9 @@ def collection(module):
return "https://www.googleapis.com/compute/v1/projects/{project}/global/networks".format(**module.params) return "https://www.googleapis.com/compute/v1/projects/{project}/global/networks".format(**module.params)
def return_if_object(module, response, kind): def return_if_object(module, response, kind, allow_not_found=False):
# If not found, return nothing. # If not found, return nothing.
if response.status_code == 404: if allow_not_found and response.status_code == 404:
return None return None
# If no content, return nothing. # If no content, return nothing.
@ -280,8 +330,6 @@ def return_if_object(module, response, kind):
if navigate_hash(result, ['error', 'errors']): if navigate_hash(result, ['error', 'errors']):
module.fail_json(msg=navigate_hash(result, ['error', 'errors'])) module.fail_json(msg=navigate_hash(result, ['error', 'errors']))
if result['kind'] != kind:
module.fail_json(msg="Incorrect result: {kind}".format(**result))
return result return result
@ -308,14 +356,15 @@ def is_different(module, response):
# This is for doing comparisons with Ansible's current parameters. # This is for doing comparisons with Ansible's current parameters.
def response_to_hash(module, response): def response_to_hash(module, response):
return { return {
u'description': response.get(u'description'), u'description': module.params.get('description'),
u'gatewayIPv4': response.get(u'gateway_ipv4'), u'gatewayIPv4': response.get(u'gateway_ipv4'),
u'id': response.get(u'id'), u'id': response.get(u'id'),
u'IPv4Range': response.get(u'ipv4_range'), u'IPv4Range': module.params.get('ipv4_range'),
u'name': response.get(u'name'), u'name': module.params.get('name'),
u'subnetworks': response.get(u'subnetworks'), u'subnetworks': response.get(u'subnetworks'),
u'autoCreateSubnetworks': response.get(u'autoCreateSubnetworks'), u'autoCreateSubnetworks': module.params.get('auto_create_subnetworks'),
u'creationTimestamp': response.get(u'creationTimestamp') u'creationTimestamp': response.get(u'creationTimestamp'),
u'routingConfig': NetworkRoutingConfigArray(response.get(u'routingConfig', []), module).from_response()
} }
@ -356,5 +405,36 @@ def raise_if_errors(response, err_path, module):
module.fail_json(msg=errors) module.fail_json(msg=errors)
class NetworkRoutingConfigArray(object):
def __init__(self, request, module):
self.module = module
if request:
self.request = request
else:
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')
})
def _response_from_item(self, item):
return remove_nones_from_dict({
u'routingMode': item.get(u'routingMode')
})
if __name__ == '__main__': if __name__ == '__main__':
main() main()

@ -56,7 +56,7 @@ EXAMPLES = '''
filters: filters:
- name = test_object - name = test_object
project: test_project project: test_project
auth_kind: service_account auth_kind: serviceaccount
service_account_file: "/tmp/auth.pem" service_account_file: "/tmp/auth.pem"
''' '''
@ -106,7 +106,7 @@ items:
- Server-defined fully-qualified URLs for all subnetworks in this network. - Server-defined fully-qualified URLs for all subnetworks in this network.
returned: success returned: success
type: list type: list
auto_create_subnetworks: autoCreateSubnetworks:
description: description:
- When set to true, the network is created in "auto subnet mode". When set to false, - When set to true, the network is created in "auto subnet mode". When set to false,
the network is in "custom subnet mode". the network is in "custom subnet mode".
@ -114,11 +114,26 @@ items:
and it automatically creates one subnetwork per region. and it automatically creates one subnetwork per region.
returned: success returned: success
type: bool type: bool
creation_timestamp: creationTimestamp:
description: description:
- Creation timestamp in RFC3339 text format. - Creation timestamp in RFC3339 text format.
returned: success returned: success
type: str type: str
routingConfig:
description:
- The network-level routing configuration for this network. Used by Cloud Router to
determine what type of network-wide routing behavior to enforce.
returned: success
type: complex
contains:
routingMode:
description:
- The network-wide routing mode to use. If set to REGIONAL, this network's cloud routers
will only advertise routes with subnetworks of this network in the same region as
the router. If set to GLOBAL, this network's cloud routers will advertise routes
with all subnetworks of this network, across regions.
returned: success
type: str
''' '''
################################################################################ ################################################################################
@ -135,7 +150,7 @@ import json
def main(): def main():
module = GcpModule( module = GcpModule(
argument_spec=dict( argument_spec=dict(
filters=dict(type='list', elements='str'), filters=dict(type='list', elements='str')
) )
) )

@ -84,6 +84,11 @@ options:
network: network:
description: description:
- The network that this route applies to. - The network that this route applies to.
- 'This field represents a link to a Network resource in GCP. It can be specified
in two ways. You can add `register: name-of-resource` to a gcp_compute_network 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: true
priority: priority:
description: description:
@ -146,13 +151,13 @@ EXAMPLES = '''
- backends - backends
- databases - databases
project: "test_project" project: "test_project"
auth_kind: "service_account" auth_kind: "serviceaccount"
service_account_file: "/tmp/auth.pem" service_account_file: "/tmp/auth.pem"
state: present state: present
''' '''
RETURN = ''' RETURN = '''
dest_range: destRange:
description: description:
- The destination range of outgoing packets that this route applies to. - The destination range of outgoing packets that this route applies to.
- Only IPv4 is supported. - Only IPv4 is supported.
@ -193,7 +198,7 @@ RETURN = '''
- A list of instance tags to which this route applies. - A list of instance tags to which this route applies.
returned: success returned: success
type: list type: list
next_hop_gateway: nextHopGateway:
description: description:
- URL to a gateway that should handle matching packets. - URL to a gateway that should handle matching packets.
- 'Currently, you can only specify the internet gateway, using a full or partial valid - 'Currently, you can only specify the internet gateway, using a full or partial valid
@ -202,7 +207,7 @@ RETURN = '''
.' .'
returned: success returned: success
type: str type: str
next_hop_instance: nextHopInstance:
description: description:
- URL to an instance that should handle matching packets. - URL to an instance that should handle matching packets.
- 'You can specify this as a full or partial URL. For example: * U(https://www.googleapis.com/compute/v1/projects/project/zones/zone/) - 'You can specify this as a full or partial URL. For example: * U(https://www.googleapis.com/compute/v1/projects/project/zones/zone/)
@ -210,17 +215,17 @@ RETURN = '''
.' .'
returned: success returned: success
type: str type: str
next_hop_ip: nextHopIp:
description: description:
- Network IP address of an instance that should handle matching packets. - Network IP address of an instance that should handle matching packets.
returned: success returned: success
type: str type: str
next_hop_vpn_tunnel: nextHopVpnTunnel:
description: description:
- URL to a VpnTunnel that should handle matching packets. - URL to a VpnTunnel that should handle matching packets.
returned: success returned: success
type: str type: str
next_hop_network: nextHopNetwork:
description: description:
- URL to a Network that should handle matching packets. - URL to a Network that should handle matching packets.
returned: success returned: success
@ -271,7 +276,8 @@ def main():
if fetch: if fetch:
if state == 'present': if state == 'present':
if is_different(module, fetch): if is_different(module, fetch):
fetch = update(module, self_link(module), kind) update(module, self_link(module), kind)
fetch = fetch_resource(module, self_link(module), kind)
changed = True changed = True
else: else:
delete(module, self_link(module), kind) delete(module, self_link(module), kind)
@ -295,8 +301,7 @@ def create(module, link, kind):
def update(module, link, kind): def update(module, link, kind):
auth = GcpSession(module, 'compute') module.fail_json(msg="Route cannot be edited")
return wait_for_operation(module, auth.put(link, resource_to_request(module)))
def delete(module, link, kind): def delete(module, link, kind):
@ -326,9 +331,9 @@ def resource_to_request(module):
return return_vals return return_vals
def fetch_resource(module, link, kind): def fetch_resource(module, link, kind, allow_not_found=True):
auth = GcpSession(module, 'compute') auth = GcpSession(module, 'compute')
return return_if_object(module, auth.get(link), kind) return return_if_object(module, auth.get(link), kind, allow_not_found)
def self_link(module): def self_link(module):
@ -339,9 +344,9 @@ def collection(module):
return "https://www.googleapis.com/compute/v1/projects/{project}/global/routes".format(**module.params) return "https://www.googleapis.com/compute/v1/projects/{project}/global/routes".format(**module.params)
def return_if_object(module, response, kind): def return_if_object(module, response, kind, allow_not_found=False):
# If not found, return nothing. # If not found, return nothing.
if response.status_code == 404: if allow_not_found and response.status_code == 404:
return None return None
# If no content, return nothing. # If no content, return nothing.
@ -356,8 +361,6 @@ def return_if_object(module, response, kind):
if navigate_hash(result, ['error', 'errors']): if navigate_hash(result, ['error', 'errors']):
module.fail_json(msg=navigate_hash(result, ['error', 'errors'])) module.fail_json(msg=navigate_hash(result, ['error', 'errors']))
if result['kind'] != kind:
module.fail_json(msg="Incorrect result: {kind}".format(**result))
return result return result

@ -56,7 +56,7 @@ EXAMPLES = '''
filters: filters:
- name = test_object - name = test_object
project: test_project project: test_project
auth_kind: service_account auth_kind: serviceaccount
service_account_file: "/tmp/auth.pem" service_account_file: "/tmp/auth.pem"
''' '''
@ -66,7 +66,7 @@ items:
returned: always returned: always
type: complex type: complex
contains: contains:
dest_range: destRange:
description: description:
- The destination range of outgoing packets that this route applies to. - The destination range of outgoing packets that this route applies to.
- Only IPv4 is supported. - Only IPv4 is supported.
@ -107,7 +107,7 @@ items:
- A list of instance tags to which this route applies. - A list of instance tags to which this route applies.
returned: success returned: success
type: list type: list
next_hop_gateway: nextHopGateway:
description: description:
- URL to a gateway that should handle matching packets. - URL to a gateway that should handle matching packets.
- 'Currently, you can only specify the internet gateway, using a full or partial valid - 'Currently, you can only specify the internet gateway, using a full or partial valid
@ -116,7 +116,7 @@ items:
.' .'
returned: success returned: success
type: str type: str
next_hop_instance: nextHopInstance:
description: description:
- URL to an instance that should handle matching packets. - URL to an instance that should handle matching packets.
- 'You can specify this as a full or partial URL. For example: * U(https://www.googleapis.com/compute/v1/projects/project/zones/zone/) - 'You can specify this as a full or partial URL. For example: * U(https://www.googleapis.com/compute/v1/projects/project/zones/zone/)
@ -124,17 +124,17 @@ items:
.' .'
returned: success returned: success
type: str type: str
next_hop_ip: nextHopIp:
description: description:
- Network IP address of an instance that should handle matching packets. - Network IP address of an instance that should handle matching packets.
returned: success returned: success
type: str type: str
next_hop_vpn_tunnel: nextHopVpnTunnel:
description: description:
- URL to a VpnTunnel that should handle matching packets. - URL to a VpnTunnel that should handle matching packets.
returned: success returned: success
type: str type: str
next_hop_network: nextHopNetwork:
description: description:
- URL to a Network that should handle matching packets. - URL to a Network that should handle matching packets.
returned: success returned: success
@ -155,7 +155,7 @@ import json
def main(): def main():
module = GcpModule( module = GcpModule(
argument_spec=dict( argument_spec=dict(
filters=dict(type='list', elements='str'), filters=dict(type='list', elements='str')
) )
) )

@ -61,6 +61,11 @@ options:
network: network:
description: description:
- A reference to the network to which this router belongs. - A reference to the network to which this router belongs.
- 'This field represents a link to a Network resource in GCP. It can be specified
in two ways. You can add `register: name-of-resource` to a gcp_compute_network 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: true
bgp: bgp:
description: description:
@ -138,7 +143,7 @@ EXAMPLES = '''
- range: 6.7.0.0/16 - range: 6.7.0.0/16
region: us-central1 region: us-central1
project: "test_project" project: "test_project"
auth_kind: "service_account" auth_kind: "serviceaccount"
service_account_file: "/tmp/auth.pem" service_account_file: "/tmp/auth.pem"
state: present state: present
''' '''
@ -149,7 +154,7 @@ RETURN = '''
- The unique identifier for the resource. - The unique identifier for the resource.
returned: success returned: success
type: int type: int
creation_timestamp: creationTimestamp:
description: description:
- Creation timestamp in RFC3339 text format. - Creation timestamp in RFC3339 text format.
returned: success returned: success
@ -186,13 +191,13 @@ RETURN = '''
that link to this router will have the same local ASN. that link to this router will have the same local ASN.
returned: success returned: success
type: int type: int
advertise_mode: advertiseMode:
description: description:
- User-specified flag to indicate which mode to use for advertisement. - User-specified flag to indicate which mode to use for advertisement.
- 'Valid values of this enum field are: DEFAULT, CUSTOM .' - 'Valid values of this enum field are: DEFAULT, CUSTOM .'
returned: success returned: success
type: str type: str
advertised_groups: advertisedGroups:
description: description:
- User-specified list of prefix groups to advertise in custom mode. - User-specified list of prefix groups to advertise in custom mode.
- This field can only be populated if advertiseMode is CUSTOM and is advertised to - This field can only be populated if advertiseMode is CUSTOM and is advertised to
@ -201,7 +206,7 @@ RETURN = '''
- 'This enum field has the one valid value: ALL_SUBNETS .' - 'This enum field has the one valid value: ALL_SUBNETS .'
returned: success returned: success
type: list type: list
advertised_ip_ranges: advertisedIpRanges:
description: description:
- User-specified list of individual IP ranges to advertise in custom mode. This field - User-specified list of individual IP ranges to advertise in custom mode. This field
can only be populated if advertiseMode is CUSTOM and is advertised to all peers can only be populated if advertiseMode is CUSTOM and is advertised to all peers
@ -274,7 +279,8 @@ def main():
if fetch: if fetch:
if state == 'present': if state == 'present':
if is_different(module, fetch): if is_different(module, fetch):
fetch = update(module, self_link(module), kind) update(module, self_link(module), kind)
fetch = fetch_resource(module, self_link(module), kind)
changed = True changed = True
else: else:
delete(module, self_link(module), kind) delete(module, self_link(module), kind)
@ -324,9 +330,9 @@ def resource_to_request(module):
return return_vals return return_vals
def fetch_resource(module, link, kind): def fetch_resource(module, link, kind, allow_not_found=True):
auth = GcpSession(module, 'compute') auth = GcpSession(module, 'compute')
return return_if_object(module, auth.get(link), kind) return return_if_object(module, auth.get(link), kind, allow_not_found)
def self_link(module): def self_link(module):
@ -337,9 +343,9 @@ def collection(module):
return "https://www.googleapis.com/compute/v1/projects/{project}/regions/{region}/routers".format(**module.params) return "https://www.googleapis.com/compute/v1/projects/{project}/regions/{region}/routers".format(**module.params)
def return_if_object(module, response, kind): def return_if_object(module, response, kind, allow_not_found=False):
# If not found, return nothing. # If not found, return nothing.
if response.status_code == 404: if allow_not_found and response.status_code == 404:
return None return None
# If no content, return nothing. # If no content, return nothing.
@ -354,8 +360,6 @@ def return_if_object(module, response, kind):
if navigate_hash(result, ['error', 'errors']): if navigate_hash(result, ['error', 'errors']):
module.fail_json(msg=navigate_hash(result, ['error', 'errors'])) module.fail_json(msg=navigate_hash(result, ['error', 'errors']))
if result['kind'] != kind:
module.fail_json(msg="Incorrect result: {kind}".format(**result))
return result return result

@ -61,7 +61,7 @@ EXAMPLES = '''
filters: filters:
- name = test_object - name = test_object
project: test_project project: test_project
auth_kind: service_account auth_kind: serviceaccount
service_account_file: "/tmp/auth.pem" service_account_file: "/tmp/auth.pem"
''' '''
@ -76,7 +76,7 @@ items:
- The unique identifier for the resource. - The unique identifier for the resource.
returned: success returned: success
type: int type: int
creation_timestamp: creationTimestamp:
description: description:
- Creation timestamp in RFC3339 text format. - Creation timestamp in RFC3339 text format.
returned: success returned: success
@ -113,13 +113,13 @@ items:
that link to this router will have the same local ASN. that link to this router will have the same local ASN.
returned: success returned: success
type: int type: int
advertise_mode: advertiseMode:
description: description:
- User-specified flag to indicate which mode to use for advertisement. - User-specified flag to indicate which mode to use for advertisement.
- 'Valid values of this enum field are: DEFAULT, CUSTOM .' - 'Valid values of this enum field are: DEFAULT, CUSTOM .'
returned: success returned: success
type: str type: str
advertised_groups: advertisedGroups:
description: description:
- User-specified list of prefix groups to advertise in custom mode. - User-specified list of prefix groups to advertise in custom mode.
- This field can only be populated if advertiseMode is CUSTOM and is advertised to - This field can only be populated if advertiseMode is CUSTOM and is advertised to
@ -128,7 +128,7 @@ items:
- 'This enum field has the one valid value: ALL_SUBNETS .' - 'This enum field has the one valid value: ALL_SUBNETS .'
returned: success returned: success
type: list type: list
advertised_ip_ranges: advertisedIpRanges:
description: description:
- User-specified list of individual IP ranges to advertise in custom mode. This field - User-specified list of individual IP ranges to advertise in custom mode. This field
can only be populated if advertiseMode is CUSTOM and is advertised to all peers can only be populated if advertiseMode is CUSTOM and is advertised to all peers

@ -32,8 +32,9 @@ DOCUMENTATION = '''
--- ---
module: gcp_compute_ssl_certificate module: gcp_compute_ssl_certificate
description: description:
- An SslCertificate resource. This resource provides a mechanism to upload an SSL - An SslCertificate resource, used for HTTPS load balancing. This resource provides
key and certificate to the load balancer to serve secure connections from the user. a mechanism to upload an SSL key and certificate to the load balancer to serve secure
connections from the user.
short_description: Creates a GCP SslCertificate short_description: Creates a GCP SslCertificate
version_added: 2.6 version_added: 2.6
author: Google Inc. (@googlecloudplatform) author: Google Inc. (@googlecloudplatform)
@ -52,7 +53,7 @@ options:
- The certificate in PEM format. - The certificate in PEM format.
- The certificate chain must be no greater than 5 certs long. - The certificate chain must be no greater than 5 certs long.
- The chain must include at least one intermediate cert. - The chain must include at least one intermediate cert.
required: false required: true
description: description:
description: description:
- An optional description of this resource. - An optional description of this resource.
@ -68,9 +69,12 @@ options:
required: false required: false
private_key: private_key:
description: description:
- The private key in PEM format. - The write-only private key in PEM format.
required: false required: true
extends_documentation_fragment: gcp extends_documentation_fragment: gcp
notes:
- "API Reference: U(https://cloud.google.com/compute/docs/reference/rest/v1/sslCertificates)"
- "Official Documentation: U(https://cloud.google.com/load-balancing/docs/ssl-certificates)"
''' '''
EXAMPLES = ''' EXAMPLES = '''
@ -103,7 +107,7 @@ EXAMPLES = '''
OGN02HtkpBOZzzvUARTR10JQoSe2/5PIwQ== OGN02HtkpBOZzzvUARTR10JQoSe2/5PIwQ==
-----END EC PRIVATE KEY----- -----END EC PRIVATE KEY-----
project: "test_project" project: "test_project"
auth_kind: "service_account" auth_kind: "serviceaccount"
service_account_file: "/tmp/auth.pem" service_account_file: "/tmp/auth.pem"
state: present state: present
''' '''
@ -116,7 +120,7 @@ RETURN = '''
- The chain must include at least one intermediate cert. - The chain must include at least one intermediate cert.
returned: success returned: success
type: str type: str
creation_timestamp: creationTimestamp:
description: description:
- Creation timestamp in RFC3339 text format. - Creation timestamp in RFC3339 text format.
returned: success returned: success
@ -141,9 +145,9 @@ RETURN = '''
be a dash. be a dash.
returned: success returned: success
type: str type: str
private_key: privateKey:
description: description:
- The private key in PEM format. - The write-only private key in PEM format.
returned: success returned: success
type: str type: str
''' '''
@ -167,10 +171,10 @@ def main():
module = GcpModule( module = GcpModule(
argument_spec=dict( argument_spec=dict(
state=dict(default='present', choices=['present', 'absent'], type='str'), state=dict(default='present', choices=['present', 'absent'], type='str'),
certificate=dict(type='str'), certificate=dict(required=True, type='str'),
description=dict(type='str'), description=dict(type='str'),
name=dict(type='str'), name=dict(type='str'),
private_key=dict(type='str') private_key=dict(required=True, type='str')
) )
) )
@ -186,7 +190,8 @@ def main():
if fetch: if fetch:
if state == 'present': if state == 'present':
if is_different(module, fetch): if is_different(module, fetch):
fetch = update(module, self_link(module), kind) update(module, self_link(module), kind)
fetch = fetch_resource(module, self_link(module), kind)
changed = True changed = True
else: else:
delete(module, self_link(module), kind) delete(module, self_link(module), kind)
@ -210,8 +215,7 @@ def create(module, link, kind):
def update(module, link, kind): def update(module, link, kind):
auth = GcpSession(module, 'compute') module.fail_json(msg="SslCertificate cannot be edited")
return wait_for_operation(module, auth.put(link, resource_to_request(module)))
def delete(module, link, kind): def delete(module, link, kind):
@ -235,9 +239,9 @@ def resource_to_request(module):
return return_vals return return_vals
def fetch_resource(module, link, kind): def fetch_resource(module, link, kind, allow_not_found=True):
auth = GcpSession(module, 'compute') auth = GcpSession(module, 'compute')
return return_if_object(module, auth.get(link), kind) return return_if_object(module, auth.get(link), kind, allow_not_found)
def self_link(module): def self_link(module):
@ -248,9 +252,9 @@ def collection(module):
return "https://www.googleapis.com/compute/v1/projects/{project}/global/sslCertificates".format(**module.params) return "https://www.googleapis.com/compute/v1/projects/{project}/global/sslCertificates".format(**module.params)
def return_if_object(module, response, kind): def return_if_object(module, response, kind, allow_not_found=False):
# If not found, return nothing. # If not found, return nothing.
if response.status_code == 404: if allow_not_found and response.status_code == 404:
return None return None
# If no content, return nothing. # If no content, return nothing.
@ -265,8 +269,6 @@ def return_if_object(module, response, kind):
if navigate_hash(result, ['error', 'errors']): if navigate_hash(result, ['error', 'errors']):
module.fail_json(msg=navigate_hash(result, ['error', 'errors'])) module.fail_json(msg=navigate_hash(result, ['error', 'errors']))
if result['kind'] != kind:
module.fail_json(msg="Incorrect result: {kind}".format(**result))
return result return result

@ -56,7 +56,7 @@ EXAMPLES = '''
filters: filters:
- name = test_object - name = test_object
project: test_project project: test_project
auth_kind: service_account auth_kind: serviceaccount
service_account_file: "/tmp/auth.pem" service_account_file: "/tmp/auth.pem"
''' '''
@ -73,7 +73,7 @@ items:
- The chain must include at least one intermediate cert. - The chain must include at least one intermediate cert.
returned: success returned: success
type: str type: str
creation_timestamp: creationTimestamp:
description: description:
- Creation timestamp in RFC3339 text format. - Creation timestamp in RFC3339 text format.
returned: success returned: success
@ -98,9 +98,9 @@ items:
be a dash. be a dash.
returned: success returned: success
type: str type: str
private_key: privateKey:
description: description:
- The private key in PEM format. - The write-only private key in PEM format.
returned: success returned: success
type: str type: str
''' '''
@ -119,7 +119,7 @@ import json
def main(): def main():
module = GcpModule( module = GcpModule(
argument_spec=dict( argument_spec=dict(
filters=dict(type='list', elements='str'), filters=dict(type='list', elements='str')
) )
) )

@ -96,13 +96,13 @@ EXAMPLES = '''
- TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 - TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
- TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 - TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
project: "test_project" project: "test_project"
auth_kind: "service_account" auth_kind: "serviceaccount"
service_account_file: "/tmp/auth.pem" service_account_file: "/tmp/auth.pem"
state: present state: present
''' '''
RETURN = ''' RETURN = '''
creation_timestamp: creationTimestamp:
description: description:
- Creation timestamp in RFC3339 text format. - Creation timestamp in RFC3339 text format.
returned: success returned: success
@ -135,18 +135,18 @@ RETURN = '''
in the `customFeatures` field. in the `customFeatures` field.
returned: success returned: success
type: str type: str
min_tls_version: minTlsVersion:
description: description:
- The minimum version of SSL protocol that can be used by the clients to establish - The minimum version of SSL protocol that can be used by the clients to establish
a connection with the load balancer. This can be one of `TLS_1_0`, `TLS_1_1`, `TLS_1_2`. a connection with the load balancer. This can be one of `TLS_1_0`, `TLS_1_1`, `TLS_1_2`.
returned: success returned: success
type: str type: str
enabled_features: enabledFeatures:
description: description:
- The list of features enabled in the SSL policy. - The list of features enabled in the SSL policy.
returned: success returned: success
type: list type: list
custom_features: customFeatures:
description: description:
- A list of features enabled when the selected profile is CUSTOM. The method returns - A list of features enabled when the selected profile is CUSTOM. The method returns
the set of features that can be specified in this list. This field must be empty the set of features that can be specified in this list. This field must be empty
@ -217,7 +217,8 @@ def main():
if fetch: if fetch:
if state == 'present': if state == 'present':
if is_different(module, fetch): if is_different(module, fetch):
fetch = update(module, self_link(module), kind) update(module, self_link(module), kind)
fetch = fetch_resource(module, self_link(module), kind)
changed = True changed = True
else: else:
delete(module, self_link(module), kind) delete(module, self_link(module), kind)
@ -267,9 +268,9 @@ def resource_to_request(module):
return return_vals return return_vals
def fetch_resource(module, link, kind): def fetch_resource(module, link, kind, allow_not_found=True):
auth = GcpSession(module, 'compute') auth = GcpSession(module, 'compute')
return return_if_object(module, auth.get(link), kind) return return_if_object(module, auth.get(link), kind, allow_not_found)
def self_link(module): def self_link(module):
@ -280,9 +281,9 @@ def collection(module):
return "https://www.googleapis.com/compute/v1/projects/{project}/global/sslPolicies".format(**module.params) return "https://www.googleapis.com/compute/v1/projects/{project}/global/sslPolicies".format(**module.params)
def return_if_object(module, response, kind): def return_if_object(module, response, kind, allow_not_found=False):
# If not found, return nothing. # If not found, return nothing.
if response.status_code == 404: if allow_not_found and response.status_code == 404:
return None return None
# If no content, return nothing. # If no content, return nothing.
@ -297,8 +298,6 @@ def return_if_object(module, response, kind):
if navigate_hash(result, ['error', 'errors']): if navigate_hash(result, ['error', 'errors']):
module.fail_json(msg=navigate_hash(result, ['error', 'errors'])) module.fail_json(msg=navigate_hash(result, ['error', 'errors']))
if result['kind'] != kind:
module.fail_json(msg="Incorrect result: {kind}".format(**result))
return result return result

@ -56,7 +56,7 @@ EXAMPLES = '''
filters: filters:
- name = test_object - name = test_object
project: test_project project: test_project
auth_kind: service_account auth_kind: serviceaccount
service_account_file: "/tmp/auth.pem" service_account_file: "/tmp/auth.pem"
''' '''
@ -66,7 +66,7 @@ items:
returned: always returned: always
type: complex type: complex
contains: contains:
creation_timestamp: creationTimestamp:
description: description:
- Creation timestamp in RFC3339 text format. - Creation timestamp in RFC3339 text format.
returned: success returned: success
@ -99,18 +99,18 @@ items:
in the `customFeatures` field. in the `customFeatures` field.
returned: success returned: success
type: str type: str
min_tls_version: minTlsVersion:
description: description:
- The minimum version of SSL protocol that can be used by the clients to establish - The minimum version of SSL protocol that can be used by the clients to establish
a connection with the load balancer. This can be one of `TLS_1_0`, `TLS_1_1`, `TLS_1_2`. a connection with the load balancer. This can be one of `TLS_1_0`, `TLS_1_1`, `TLS_1_2`.
returned: success returned: success
type: str type: str
enabled_features: enabledFeatures:
description: description:
- The list of features enabled in the SSL policy. - The list of features enabled in the SSL policy.
returned: success returned: success
type: list type: list
custom_features: customFeatures:
description: description:
- A list of features enabled when the selected profile is CUSTOM. The method returns - A list of features enabled when the selected profile is CUSTOM. The method returns
the set of features that can be specified in this list. This field must be empty the set of features that can be specified in this list. This field must be empty
@ -156,7 +156,7 @@ import json
def main(): def main():
module = GcpModule( module = GcpModule(
argument_spec=dict( argument_spec=dict(
filters=dict(type='list', elements='str'), filters=dict(type='list', elements='str')
) )
) )

@ -87,6 +87,38 @@ options:
description: description:
- The network this subnet belongs to. - The network this subnet belongs to.
- Only networks that are in the distributed mode can have subnetworks. - Only networks that are in the distributed mode can have subnetworks.
- 'This field represents a link to a Network resource in GCP. It can be specified
in two ways. You can add `register: name-of-resource` to a gcp_compute_network 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
enable_flow_logs:
description:
- Whether to enable flow logging for this subnetwork.
required: false
type: bool
version_added: 2.8
secondary_ip_ranges:
description:
- An array of configurations for secondary IP ranges for VM instances contained in
this subnetwork. The primary IP of such VM must belong to the primary ipCidrRange
of the subnetwork. The alias IPs may belong to either primary or secondary ranges.
required: false
version_added: 2.8
suboptions:
range_name:
description:
- The name associated with this subnetwork secondary range, used when adding an alias
IP range to a VM instance. The name must be 1-63 characters long, and comply with
RFC1035. The name must be unique within the subnetwork.
required: true
ip_cidr_range:
description:
- The range of IP addresses belonging to this subnetwork secondary range. Provide
this property when you create the subnetwork.
- Ranges must be unique and non-overlapping with all primary and secondary IP ranges
within a network. Only IPv4 is supported.
required: true required: true
private_ip_google_access: private_ip_google_access:
description: description:
@ -123,13 +155,13 @@ EXAMPLES = '''
network: "{{ network }}" network: "{{ network }}"
ip_cidr_range: 172.16.0.0/16 ip_cidr_range: 172.16.0.0/16
project: "test_project" project: "test_project"
auth_kind: "service_account" auth_kind: "serviceaccount"
service_account_file: "/tmp/auth.pem" service_account_file: "/tmp/auth.pem"
state: present state: present
''' '''
RETURN = ''' RETURN = '''
creation_timestamp: creationTimestamp:
description: description:
- Creation timestamp in RFC3339 text format. - Creation timestamp in RFC3339 text format.
returned: success returned: success
@ -140,7 +172,7 @@ RETURN = '''
the resource. This field can be set only at resource creation time. the resource. This field can be set only at resource creation time.
returned: success returned: success
type: str type: str
gateway_address: gatewayAddress:
description: description:
- The gateway address for default routes to reach destination addresses outside this - The gateway address for default routes to reach destination addresses outside this
subnetwork. subnetwork.
@ -151,7 +183,7 @@ RETURN = '''
- The unique identifier for the resource. - The unique identifier for the resource.
returned: success returned: success
type: int type: int
ip_cidr_range: ipCidrRange:
description: description:
- The range of internal addresses that are owned by this subnetwork. - The range of internal addresses that are owned by this subnetwork.
- Provide this property when you create the subnetwork. For example, 10.0.0.0/8 or - Provide this property when you create the subnetwork. For example, 10.0.0.0/8 or
@ -175,7 +207,41 @@ RETURN = '''
- Only networks that are in the distributed mode can have subnetworks. - Only networks that are in the distributed mode can have subnetworks.
returned: success returned: success
type: dict type: dict
private_ip_google_access: enableFlowLogs:
description:
- Whether to enable flow logging for this subnetwork.
returned: success
type: bool
fingerprint:
description:
- Fingerprint of this resource. This field is used internally during updates of this
resource.
returned: success
type: str
secondaryIpRanges:
description:
- An array of configurations for secondary IP ranges for VM instances contained in
this subnetwork. The primary IP of such VM must belong to the primary ipCidrRange
of the subnetwork. The alias IPs may belong to either primary or secondary ranges.
returned: success
type: complex
contains:
rangeName:
description:
- The name associated with this subnetwork secondary range, used when adding an alias
IP range to a VM instance. The name must be 1-63 characters long, and comply with
RFC1035. The name must be unique within the subnetwork.
returned: success
type: str
ipCidrRange:
description:
- The range of IP addresses belonging to this subnetwork secondary range. Provide
this property when you create the subnetwork.
- Ranges must be unique and non-overlapping with all primary and secondary IP ranges
within a network. Only IPv4 is supported.
returned: success
type: str
privateIpGoogleAccess:
description: description:
- Whether the VMs in this subnet can access Google services without assigned external - Whether the VMs in this subnet can access Google services without assigned external
IP addresses. IP addresses.
@ -192,7 +258,7 @@ RETURN = '''
# Imports # Imports
################################################################################ ################################################################################
from ansible.module_utils.gcp_utils import navigate_hash, GcpSession, GcpModule, GcpRequest, replace_resource_dict from ansible.module_utils.gcp_utils import navigate_hash, GcpSession, GcpModule, GcpRequest, remove_nones_from_dict, replace_resource_dict
import json import json
import time import time
@ -211,6 +277,11 @@ def main():
ip_cidr_range=dict(required=True, type='str'), ip_cidr_range=dict(required=True, type='str'),
name=dict(required=True, type='str'), name=dict(required=True, type='str'),
network=dict(required=True, type='dict'), network=dict(required=True, type='dict'),
enable_flow_logs=dict(type='bool'),
secondary_ip_ranges=dict(type='list', elements='dict', options=dict(
range_name=dict(required=True, type='str'),
ip_cidr_range=dict(required=True, type='str')
)),
private_ip_google_access=dict(type='bool'), private_ip_google_access=dict(type='bool'),
region=dict(required=True, type='str') region=dict(required=True, type='str')
) )
@ -228,7 +299,8 @@ def main():
if fetch: if fetch:
if state == 'present': if state == 'present':
if is_different(module, fetch): if is_different(module, fetch):
fetch = update(module, self_link(module), kind) update(module, self_link(module), kind, fetch)
fetch = fetch_resource(module, self_link(module), kind)
changed = True changed = True
else: else:
delete(module, self_link(module), kind) delete(module, self_link(module), kind)
@ -251,9 +323,60 @@ def create(module, link, kind):
return wait_for_operation(module, auth.post(link, resource_to_request(module))) return wait_for_operation(module, auth.post(link, resource_to_request(module)))
def update(module, link, kind): 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('ipCidrRange') != request.get('ipCidrRange'):
ip_cidr_range_update(module, request, response)
if response.get('enableFlowLogs') != request.get('enableFlowLogs') or response.get('secondaryIpRanges') != request.get('secondaryIpRanges'):
enable_flow_logs_update(module, request, response)
if response.get('privateIpGoogleAccess') != request.get('privateIpGoogleAccess'):
private_ip_google_access_update(module, request, response)
def ip_cidr_range_update(module, request, response):
auth = GcpSession(module, 'compute') auth = GcpSession(module, 'compute')
return wait_for_operation(module, auth.put(link, resource_to_request(module))) auth.post(
''.join([
"https://www.googleapis.com/compute/v1/",
"projects/{project}/regions/{region}/subnetworks/{name}/expandIpCidrRange"
]).format(**module.params),
{
u'ipCidrRange': module.params.get('ip_cidr_range')
}
)
def enable_flow_logs_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'enableFlowLogs': module.params.get('enable_flow_logs'),
u'fingerprint': response.get('fingerprint'),
u'secondaryIpRanges': SubnetworkSecondaryIpRangesArray(module.params.get('secondary_ip_ranges', []), module).to_request()
}
)
def private_ip_google_access_update(module, request, response):
auth = GcpSession(module, 'compute')
auth.post(
''.join([
"https://www.googleapis.com/compute/v1/",
"projects/{project}/regions/{region}/subnetworks/{name}/setPrivateIpGoogleAccess"
]).format(**module.params),
{
u'privateIpGoogleAccess': module.params.get('private_ip_google_access')
}
)
def delete(module, link, kind): def delete(module, link, kind):
@ -268,6 +391,8 @@ def resource_to_request(module):
u'ipCidrRange': module.params.get('ip_cidr_range'), u'ipCidrRange': module.params.get('ip_cidr_range'),
u'name': module.params.get('name'), u'name': module.params.get('name'),
u'network': replace_resource_dict(module.params.get(u'network', {}), 'selfLink'), u'network': replace_resource_dict(module.params.get(u'network', {}), 'selfLink'),
u'enableFlowLogs': module.params.get('enable_flow_logs'),
u'secondaryIpRanges': SubnetworkSecondaryIpRangesArray(module.params.get('secondary_ip_ranges', []), module).to_request(),
u'privateIpGoogleAccess': module.params.get('private_ip_google_access'), u'privateIpGoogleAccess': module.params.get('private_ip_google_access'),
u'region': module.params.get('region') u'region': module.params.get('region')
} }
@ -279,9 +404,9 @@ def resource_to_request(module):
return return_vals return return_vals
def fetch_resource(module, link, kind): def fetch_resource(module, link, kind, allow_not_found=True):
auth = GcpSession(module, 'compute') auth = GcpSession(module, 'compute')
return return_if_object(module, auth.get(link), kind) return return_if_object(module, auth.get(link), kind, allow_not_found)
def self_link(module): def self_link(module):
@ -292,9 +417,9 @@ def collection(module):
return "https://www.googleapis.com/compute/v1/projects/{project}/regions/{region}/subnetworks".format(**module.params) return "https://www.googleapis.com/compute/v1/projects/{project}/regions/{region}/subnetworks".format(**module.params)
def return_if_object(module, response, kind): def return_if_object(module, response, kind, allow_not_found=False):
# If not found, return nothing. # If not found, return nothing.
if response.status_code == 404: if allow_not_found and response.status_code == 404:
return None return None
# If no content, return nothing. # If no content, return nothing.
@ -309,8 +434,6 @@ def return_if_object(module, response, kind):
if navigate_hash(result, ['error', 'errors']): if navigate_hash(result, ['error', 'errors']):
module.fail_json(msg=navigate_hash(result, ['error', 'errors'])) module.fail_json(msg=navigate_hash(result, ['error', 'errors']))
if result['kind'] != kind:
module.fail_json(msg="Incorrect result: {kind}".format(**result))
return result return result
@ -344,6 +467,9 @@ def response_to_hash(module, response):
u'ipCidrRange': response.get(u'ipCidrRange'), u'ipCidrRange': response.get(u'ipCidrRange'),
u'name': response.get(u'name'), u'name': response.get(u'name'),
u'network': replace_resource_dict(module.params.get(u'network', {}), 'selfLink'), u'network': replace_resource_dict(module.params.get(u'network', {}), 'selfLink'),
u'enableFlowLogs': response.get(u'enableFlowLogs'),
u'fingerprint': response.get(u'fingerprint'),
u'secondaryIpRanges': SubnetworkSecondaryIpRangesArray(response.get(u'secondaryIpRanges', []), module).from_response(),
u'privateIpGoogleAccess': response.get(u'privateIpGoogleAccess'), u'privateIpGoogleAccess': response.get(u'privateIpGoogleAccess'),
u'region': module.params.get('region') u'region': module.params.get('region')
} }
@ -386,5 +512,38 @@ def raise_if_errors(response, err_path, module):
module.fail_json(msg=errors) module.fail_json(msg=errors)
class SubnetworkSecondaryIpRangesArray(object):
def __init__(self, request, module):
self.module = module
if request:
self.request = request
else:
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'rangeName': item.get('range_name'),
u'ipCidrRange': item.get('ip_cidr_range')
})
def _response_from_item(self, item):
return remove_nones_from_dict({
u'rangeName': item.get(u'rangeName'),
u'ipCidrRange': item.get(u'ipCidrRange')
})
if __name__ == '__main__': if __name__ == '__main__':
main() main()

@ -61,7 +61,7 @@ EXAMPLES = '''
filters: filters:
- name = test_object - name = test_object
project: test_project project: test_project
auth_kind: service_account auth_kind: serviceaccount
service_account_file: "/tmp/auth.pem" service_account_file: "/tmp/auth.pem"
''' '''
@ -71,7 +71,7 @@ items:
returned: always returned: always
type: complex type: complex
contains: contains:
creation_timestamp: creationTimestamp:
description: description:
- Creation timestamp in RFC3339 text format. - Creation timestamp in RFC3339 text format.
returned: success returned: success
@ -82,7 +82,7 @@ items:
the resource. This field can be set only at resource creation time. the resource. This field can be set only at resource creation time.
returned: success returned: success
type: str type: str
gateway_address: gatewayAddress:
description: description:
- The gateway address for default routes to reach destination addresses outside this - The gateway address for default routes to reach destination addresses outside this
subnetwork. subnetwork.
@ -93,7 +93,7 @@ items:
- The unique identifier for the resource. - The unique identifier for the resource.
returned: success returned: success
type: int type: int
ip_cidr_range: ipCidrRange:
description: description:
- The range of internal addresses that are owned by this subnetwork. - The range of internal addresses that are owned by this subnetwork.
- Provide this property when you create the subnetwork. For example, 10.0.0.0/8 or - Provide this property when you create the subnetwork. For example, 10.0.0.0/8 or
@ -117,7 +117,41 @@ items:
- Only networks that are in the distributed mode can have subnetworks. - Only networks that are in the distributed mode can have subnetworks.
returned: success returned: success
type: dict type: dict
private_ip_google_access: enableFlowLogs:
description:
- Whether to enable flow logging for this subnetwork.
returned: success
type: bool
fingerprint:
description:
- Fingerprint of this resource. This field is used internally during updates of this
resource.
returned: success
type: str
secondaryIpRanges:
description:
- An array of configurations for secondary IP ranges for VM instances contained in
this subnetwork. The primary IP of such VM must belong to the primary ipCidrRange
of the subnetwork. The alias IPs may belong to either primary or secondary ranges.
returned: success
type: complex
contains:
rangeName:
description:
- The name associated with this subnetwork secondary range, used when adding an alias
IP range to a VM instance. The name must be 1-63 characters long, and comply with
RFC1035. The name must be unique within the subnetwork.
returned: success
type: str
ipCidrRange:
description:
- The range of IP addresses belonging to this subnetwork secondary range. Provide
this property when you create the subnetwork.
- Ranges must be unique and non-overlapping with all primary and secondary IP ranges
within a network. Only IPv4 is supported.
returned: success
type: str
privateIpGoogleAccess:
description: description:
- Whether the VMs in this subnet can access Google services without assigned external - Whether the VMs in this subnet can access Google services without assigned external
IP addresses. IP addresses.

@ -63,6 +63,11 @@ options:
url_map: url_map:
description: description:
- A reference to the UrlMap resource that defines the mapping from URL to the BackendService. - A reference to the UrlMap resource that defines the mapping from URL to the BackendService.
- 'This field represents a link to a UrlMap resource in GCP. It can be specified in
two ways. You can add `register: name-of-resource` to a gcp_compute_url_map task
and then set this url_map field to "{{ name-of-resource }}" Alternatively, you can
set this url_map to a dictionary with the selfLink key where the value is the selfLink
of your UrlMap.'
required: true required: true
extends_documentation_fragment: gcp extends_documentation_fragment: gcp
notes: notes:
@ -123,13 +128,13 @@ EXAMPLES = '''
name: "test_object" name: "test_object"
url_map: "{{ urlmap }}" url_map: "{{ urlmap }}"
project: "test_project" project: "test_project"
auth_kind: "service_account" auth_kind: "serviceaccount"
service_account_file: "/tmp/auth.pem" service_account_file: "/tmp/auth.pem"
state: present state: present
''' '''
RETURN = ''' RETURN = '''
creation_timestamp: creationTimestamp:
description: description:
- Creation timestamp in RFC3339 text format. - Creation timestamp in RFC3339 text format.
returned: success returned: success
@ -154,7 +159,7 @@ RETURN = '''
be a dash. be a dash.
returned: success returned: success
type: str type: str
url_map: urlMap:
description: description:
- A reference to the UrlMap resource that defines the mapping from URL to the BackendService. - A reference to the UrlMap resource that defines the mapping from URL to the BackendService.
returned: success returned: success
@ -198,7 +203,8 @@ def main():
if fetch: if fetch:
if state == 'present': if state == 'present':
if is_different(module, fetch): if is_different(module, fetch):
fetch = update(module, self_link(module), kind) update(module, self_link(module), kind, fetch)
fetch = fetch_resource(module, self_link(module), kind)
changed = True changed = True
else: else:
delete(module, self_link(module), kind) delete(module, self_link(module), kind)
@ -221,9 +227,28 @@ def create(module, link, kind):
return wait_for_operation(module, auth.post(link, resource_to_request(module))) return wait_for_operation(module, auth.post(link, resource_to_request(module)))
def update(module, link, kind): 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('urlMap') != request.get('urlMap'):
url_map_update(module, request, response)
def url_map_update(module, request, response):
auth = GcpSession(module, 'compute') auth = GcpSession(module, 'compute')
return wait_for_operation(module, auth.put(link, resource_to_request(module))) auth.post(
''.join([
"https://www.googleapis.com/compute/v1/",
"projects/{project}/targetHttpProxies/{name}/setUrlMap"
]).format(**module.params),
{
u'urlMap': replace_resource_dict(module.params.get(u'url_map', {}), 'selfLink')
}
)
def delete(module, link, kind): def delete(module, link, kind):
@ -246,9 +271,9 @@ def resource_to_request(module):
return return_vals return return_vals
def fetch_resource(module, link, kind): def fetch_resource(module, link, kind, allow_not_found=True):
auth = GcpSession(module, 'compute') auth = GcpSession(module, 'compute')
return return_if_object(module, auth.get(link), kind) return return_if_object(module, auth.get(link), kind, allow_not_found)
def self_link(module): def self_link(module):
@ -259,9 +284,9 @@ def collection(module):
return "https://www.googleapis.com/compute/v1/projects/{project}/global/targetHttpProxies".format(**module.params) return "https://www.googleapis.com/compute/v1/projects/{project}/global/targetHttpProxies".format(**module.params)
def return_if_object(module, response, kind): def return_if_object(module, response, kind, allow_not_found=False):
# If not found, return nothing. # If not found, return nothing.
if response.status_code == 404: if allow_not_found and response.status_code == 404:
return None return None
# If no content, return nothing. # If no content, return nothing.
@ -276,8 +301,6 @@ def return_if_object(module, response, kind):
if navigate_hash(result, ['error', 'errors']): if navigate_hash(result, ['error', 'errors']):
module.fail_json(msg=navigate_hash(result, ['error', 'errors'])) module.fail_json(msg=navigate_hash(result, ['error', 'errors']))
if result['kind'] != kind:
module.fail_json(msg="Incorrect result: {kind}".format(**result))
return result return result

@ -56,7 +56,7 @@ EXAMPLES = '''
filters: filters:
- name = test_object - name = test_object
project: test_project project: test_project
auth_kind: service_account auth_kind: serviceaccount
service_account_file: "/tmp/auth.pem" service_account_file: "/tmp/auth.pem"
''' '''
@ -66,7 +66,7 @@ items:
returned: always returned: always
type: complex type: complex
contains: contains:
creation_timestamp: creationTimestamp:
description: description:
- Creation timestamp in RFC3339 text format. - Creation timestamp in RFC3339 text format.
returned: success returned: success
@ -91,7 +91,7 @@ items:
be a dash. be a dash.
returned: success returned: success
type: str type: str
url_map: urlMap:
description: description:
- A reference to the UrlMap resource that defines the mapping from URL to the BackendService. - A reference to the UrlMap resource that defines the mapping from URL to the BackendService.
returned: success returned: success
@ -112,7 +112,7 @@ import json
def main(): def main():
module = GcpModule( module = GcpModule(
argument_spec=dict( argument_spec=dict(
filters=dict(type='list', elements='str'), filters=dict(type='list', elements='str')
) )
) )

@ -78,6 +78,11 @@ options:
url_map: url_map:
description: description:
- A reference to the UrlMap resource that defines the mapping from URL to the BackendService. - A reference to the UrlMap resource that defines the mapping from URL to the BackendService.
- 'This field represents a link to a UrlMap resource in GCP. It can be specified in
two ways. You can add `register: name-of-resource` to a gcp_compute_url_map task
and then set this url_map field to "{{ name-of-resource }}" Alternatively, you can
set this url_map to a dictionary with the selfLink key where the value is the selfLink
of your UrlMap.'
required: true required: true
extends_documentation_fragment: gcp extends_documentation_fragment: gcp
notes: notes:
@ -174,13 +179,13 @@ EXAMPLES = '''
- "{{ sslcert }}" - "{{ sslcert }}"
url_map: "{{ urlmap }}" url_map: "{{ urlmap }}"
project: "test_project" project: "test_project"
auth_kind: "service_account" auth_kind: "serviceaccount"
service_account_file: "/tmp/auth.pem" service_account_file: "/tmp/auth.pem"
state: present state: present
''' '''
RETURN = ''' RETURN = '''
creation_timestamp: creationTimestamp:
description: description:
- Creation timestamp in RFC3339 text format. - Creation timestamp in RFC3339 text format.
returned: success returned: success
@ -205,7 +210,7 @@ RETURN = '''
be a dash. be a dash.
returned: success returned: success
type: str type: str
quic_override: quicOverride:
description: description:
- Specifies the QUIC override policy for this resource. This determines whether the - Specifies the QUIC override policy for this resource. This determines whether the
load balancer will attempt to negotiate QUIC with clients or not. Can specify one load balancer will attempt to negotiate QUIC with clients or not. Can specify one
@ -214,13 +219,13 @@ RETURN = '''
to specifying NONE. to specifying NONE.
returned: success returned: success
type: str type: str
ssl_certificates: sslCertificates:
description: description:
- A list of SslCertificate resources that are used to authenticate connections between - A list of SslCertificate resources that are used to authenticate connections between
users and the load balancer. Currently, exactly one SSL certificate must be specified. users and the load balancer. Currently, exactly one SSL certificate must be specified.
returned: success returned: success
type: list type: list
url_map: urlMap:
description: description:
- A reference to the UrlMap resource that defines the mapping from URL to the BackendService. - A reference to the UrlMap resource that defines the mapping from URL to the BackendService.
returned: success returned: success
@ -266,7 +271,8 @@ def main():
if fetch: if fetch:
if state == 'present': if state == 'present':
if is_different(module, fetch): if is_different(module, fetch):
fetch = update(module, self_link(module), kind) update(module, self_link(module), kind, fetch)
fetch = fetch_resource(module, self_link(module), kind)
changed = True changed = True
else: else:
delete(module, self_link(module), kind) delete(module, self_link(module), kind)
@ -289,9 +295,58 @@ def create(module, link, kind):
return wait_for_operation(module, auth.post(link, resource_to_request(module))) return wait_for_operation(module, auth.post(link, resource_to_request(module)))
def update(module, link, kind): 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('quicOverride') != request.get('quicOverride'):
quic_override_update(module, request, response)
if response.get('sslCertificates') != request.get('sslCertificates'):
ssl_certificates_update(module, request, response)
if response.get('urlMap') != request.get('urlMap'):
url_map_update(module, request, response)
def quic_override_update(module, request, response):
auth = GcpSession(module, 'compute') auth = GcpSession(module, 'compute')
return wait_for_operation(module, auth.put(link, resource_to_request(module))) auth.post(
''.join([
"https://www.googleapis.com/compute/v1/",
"projects/{project}/global/targetHttpsProxies/{name}/setQuicOverride"
]).format(**module.params),
{
u'quicOverride': module.params.get('quic_override')
}
)
def ssl_certificates_update(module, request, response):
auth = GcpSession(module, 'compute')
auth.post(
''.join([
"https://www.googleapis.com/compute/v1/",
"projects/{project}/targetHttpsProxies/{name}/setSslCertificates"
]).format(**module.params),
{
u'sslCertificates': replace_resource_dict(module.params.get('ssl_certificates', []), 'selfLink')
}
)
def url_map_update(module, request, response):
auth = GcpSession(module, 'compute')
auth.post(
''.join([
"https://www.googleapis.com/compute/v1/",
"projects/{project}/targetHttpsProxies/{name}/setUrlMap"
]).format(**module.params),
{
u'urlMap': replace_resource_dict(module.params.get(u'url_map', {}), 'selfLink')
}
)
def delete(module, link, kind): def delete(module, link, kind):
@ -316,9 +371,9 @@ def resource_to_request(module):
return return_vals return return_vals
def fetch_resource(module, link, kind): def fetch_resource(module, link, kind, allow_not_found=True):
auth = GcpSession(module, 'compute') auth = GcpSession(module, 'compute')
return return_if_object(module, auth.get(link), kind) return return_if_object(module, auth.get(link), kind, allow_not_found)
def self_link(module): def self_link(module):
@ -329,9 +384,9 @@ def collection(module):
return "https://www.googleapis.com/compute/v1/projects/{project}/global/targetHttpsProxies".format(**module.params) return "https://www.googleapis.com/compute/v1/projects/{project}/global/targetHttpsProxies".format(**module.params)
def return_if_object(module, response, kind): def return_if_object(module, response, kind, allow_not_found=False):
# If not found, return nothing. # If not found, return nothing.
if response.status_code == 404: if allow_not_found and response.status_code == 404:
return None return None
# If no content, return nothing. # If no content, return nothing.
@ -346,8 +401,6 @@ def return_if_object(module, response, kind):
if navigate_hash(result, ['error', 'errors']): if navigate_hash(result, ['error', 'errors']):
module.fail_json(msg=navigate_hash(result, ['error', 'errors'])) module.fail_json(msg=navigate_hash(result, ['error', 'errors']))
if result['kind'] != kind:
module.fail_json(msg="Incorrect result: {kind}".format(**result))
return result return result

@ -56,7 +56,7 @@ EXAMPLES = '''
filters: filters:
- name = test_object - name = test_object
project: test_project project: test_project
auth_kind: service_account auth_kind: serviceaccount
service_account_file: "/tmp/auth.pem" service_account_file: "/tmp/auth.pem"
''' '''
@ -66,7 +66,7 @@ items:
returned: always returned: always
type: complex type: complex
contains: contains:
creation_timestamp: creationTimestamp:
description: description:
- Creation timestamp in RFC3339 text format. - Creation timestamp in RFC3339 text format.
returned: success returned: success
@ -91,7 +91,7 @@ items:
be a dash. be a dash.
returned: success returned: success
type: str type: str
quic_override: quicOverride:
description: description:
- Specifies the QUIC override policy for this resource. This determines whether the - Specifies the QUIC override policy for this resource. This determines whether the
load balancer will attempt to negotiate QUIC with clients or not. Can specify one load balancer will attempt to negotiate QUIC with clients or not. Can specify one
@ -100,13 +100,13 @@ items:
to specifying NONE. to specifying NONE.
returned: success returned: success
type: str type: str
ssl_certificates: sslCertificates:
description: description:
- A list of SslCertificate resources that are used to authenticate connections between - A list of SslCertificate resources that are used to authenticate connections between
users and the load balancer. Currently, exactly one SSL certificate must be specified. users and the load balancer. Currently, exactly one SSL certificate must be specified.
returned: success returned: success
type: list type: list
url_map: urlMap:
description: description:
- A reference to the UrlMap resource that defines the mapping from URL to the BackendService. - A reference to the UrlMap resource that defines the mapping from URL to the BackendService.
returned: success returned: success
@ -127,7 +127,7 @@ import json
def main(): def main():
module = GcpModule( module = GcpModule(
argument_spec=dict( argument_spec=dict(
filters=dict(type='list', elements='str'), filters=dict(type='list', elements='str')
) )
) )

@ -59,6 +59,11 @@ options:
the backup pool are unhealthy, the traffic will be directed back to the primary the backup pool are unhealthy, the traffic will be directed back to the primary
pool in the "force" mode, where traffic will be spread to the healthy instances pool in the "force" mode, where traffic will be spread to the healthy instances
with the best effort, or to all instances when no instance is healthy. with the best effort, or to all instances when no instance is healthy.
- 'This field represents a link to a TargetPool resource in GCP. It can be specified
in two ways. You can add `register: name-of-resource` to a gcp_compute_target_pool
task and then set this backup_pool field to "{{ name-of-resource }}" Alternatively,
you can set this backup_pool to a dictionary with the selfLink key where the value
is the selfLink of your TargetPool.'
required: false required: false
description: description:
description: description:
@ -84,6 +89,11 @@ options:
- A member instance in this pool is considered healthy if and only if the health checks - A member instance in this pool is considered healthy if and only if the health checks
pass. If not specified it means all member instances will be considered healthy pass. If not specified it means all member instances will be considered healthy
at all times. at all times.
- 'This field represents a link to a HttpHealthCheck resource in GCP. It can be specified
in two ways. You can add `register: name-of-resource` to a gcp_compute_http_health_check
task and then set this health_check field to "{{ name-of-resource }}" Alternatively,
you can set this health_check to a dictionary with the selfLink key where the value
is the selfLink of your HttpHealthCheck.'
required: false required: false
instances: instances:
description: description:
@ -125,13 +135,13 @@ EXAMPLES = '''
name: "test_object" name: "test_object"
region: us-west1 region: us-west1
project: "test_project" project: "test_project"
auth_kind: "service_account" auth_kind: "serviceaccount"
service_account_file: "/tmp/auth.pem" service_account_file: "/tmp/auth.pem"
state: present state: present
''' '''
RETURN = ''' RETURN = '''
backup_pool: backupPool:
description: description:
- This field is applicable only when the containing target pool is serving a forwarding - This field is applicable only when the containing target pool is serving a forwarding
rule as the primary pool, and its failoverRatio field is properly set to a value rule as the primary pool, and its failoverRatio field is properly set to a value
@ -146,7 +156,7 @@ RETURN = '''
with the best effort, or to all instances when no instance is healthy. with the best effort, or to all instances when no instance is healthy.
returned: success returned: success
type: dict type: dict
creation_timestamp: creationTimestamp:
description: description:
- Creation timestamp in RFC3339 text format. - Creation timestamp in RFC3339 text format.
returned: success returned: success
@ -156,7 +166,7 @@ RETURN = '''
- An optional description of this resource. - An optional description of this resource.
returned: success returned: success
type: str type: str
failover_ratio: failoverRatio:
description: description:
- This field is applicable only when the containing target pool is serving a forwarding - This field is applicable only when the containing target pool is serving a forwarding
rule as the primary pool (i.e., not as a backup pool to some other target pool). rule as the primary pool (i.e., not as a backup pool to some other target pool).
@ -171,7 +181,7 @@ RETURN = '''
or to all instances when no instance is healthy. or to all instances when no instance is healthy.
returned: success returned: success
type: str type: str
health_check: healthCheck:
description: description:
- A reference to a HttpHealthCheck resource. - A reference to a HttpHealthCheck resource.
- A member instance in this pool is considered healthy if and only if the health checks - A member instance in this pool is considered healthy if and only if the health checks
@ -200,7 +210,7 @@ RETURN = '''
be a dash. be a dash.
returned: success returned: success
type: str type: str
session_affinity: sessionAffinity:
description: description:
- 'Session affinity option. Must be one of these values: - NONE: Connections from - 'Session affinity option. Must be one of these values: - NONE: Connections from
the same client IP may go to any instance in the pool.' the same client IP may go to any instance in the pool.'
@ -259,7 +269,8 @@ def main():
if fetch: if fetch:
if state == 'present': if state == 'present':
if is_different(module, fetch): if is_different(module, fetch):
fetch = update(module, self_link(module), kind) update(module, self_link(module), kind)
fetch = fetch_resource(module, self_link(module), kind)
changed = True changed = True
else: else:
delete(module, self_link(module), kind) delete(module, self_link(module), kind)
@ -312,9 +323,9 @@ def resource_to_request(module):
return return_vals return return_vals
def fetch_resource(module, link, kind): def fetch_resource(module, link, kind, allow_not_found=True):
auth = GcpSession(module, 'compute') auth = GcpSession(module, 'compute')
return return_if_object(module, auth.get(link), kind) return return_if_object(module, auth.get(link), kind, allow_not_found)
def self_link(module): def self_link(module):
@ -325,9 +336,9 @@ def collection(module):
return "https://www.googleapis.com/compute/v1/projects/{project}/regions/{region}/targetPools".format(**module.params) return "https://www.googleapis.com/compute/v1/projects/{project}/regions/{region}/targetPools".format(**module.params)
def return_if_object(module, response, kind): def return_if_object(module, response, kind, allow_not_found=False):
# If not found, return nothing. # If not found, return nothing.
if response.status_code == 404: if allow_not_found and response.status_code == 404:
return None return None
# If no content, return nothing. # If no content, return nothing.
@ -344,8 +355,6 @@ def return_if_object(module, response, kind):
if navigate_hash(result, ['error', 'errors']): if navigate_hash(result, ['error', 'errors']):
module.fail_json(msg=navigate_hash(result, ['error', 'errors'])) module.fail_json(msg=navigate_hash(result, ['error', 'errors']))
if result['kind'] != kind:
module.fail_json(msg="Incorrect result: {kind}".format(**result))
return result return result

@ -61,7 +61,7 @@ EXAMPLES = '''
filters: filters:
- name = test_object - name = test_object
project: test_project project: test_project
auth_kind: service_account auth_kind: serviceaccount
service_account_file: "/tmp/auth.pem" service_account_file: "/tmp/auth.pem"
''' '''
@ -71,7 +71,7 @@ items:
returned: always returned: always
type: complex type: complex
contains: contains:
backup_pool: backupPool:
description: description:
- This field is applicable only when the containing target pool is serving a forwarding - This field is applicable only when the containing target pool is serving a forwarding
rule as the primary pool, and its failoverRatio field is properly set to a value rule as the primary pool, and its failoverRatio field is properly set to a value
@ -86,7 +86,7 @@ items:
with the best effort, or to all instances when no instance is healthy. with the best effort, or to all instances when no instance is healthy.
returned: success returned: success
type: dict type: dict
creation_timestamp: creationTimestamp:
description: description:
- Creation timestamp in RFC3339 text format. - Creation timestamp in RFC3339 text format.
returned: success returned: success
@ -96,7 +96,7 @@ items:
- An optional description of this resource. - An optional description of this resource.
returned: success returned: success
type: str type: str
failover_ratio: failoverRatio:
description: description:
- This field is applicable only when the containing target pool is serving a forwarding - This field is applicable only when the containing target pool is serving a forwarding
rule as the primary pool (i.e., not as a backup pool to some other target pool). rule as the primary pool (i.e., not as a backup pool to some other target pool).
@ -111,7 +111,7 @@ items:
or to all instances when no instance is healthy. or to all instances when no instance is healthy.
returned: success returned: success
type: str type: str
health_check: healthCheck:
description: description:
- A reference to a HttpHealthCheck resource. - A reference to a HttpHealthCheck resource.
- A member instance in this pool is considered healthy if and only if the health checks - A member instance in this pool is considered healthy if and only if the health checks
@ -140,7 +140,7 @@ items:
be a dash. be a dash.
returned: success returned: success
type: str type: str
session_affinity: sessionAffinity:
description: description:
- 'Session affinity option. Must be one of these values: - NONE: Connections from - 'Session affinity option. Must be one of these values: - NONE: Connections from
the same client IP may go to any instance in the pool.' the same client IP may go to any instance in the pool.'

@ -56,7 +56,7 @@ EXAMPLES = '''
filters: filters:
- name = test_object - name = test_object
project: test_project project: test_project
auth_kind: service_account auth_kind: serviceaccount
service_account_file: "/tmp/auth.pem" service_account_file: "/tmp/auth.pem"
''' '''
@ -66,7 +66,7 @@ items:
returned: always returned: always
type: complex type: complex
contains: contains:
creation_timestamp: creationTimestamp:
description: description:
- Creation timestamp in RFC3339 text format. - Creation timestamp in RFC3339 text format.
returned: success returned: success
@ -91,7 +91,7 @@ items:
be a dash. be a dash.
returned: success returned: success
type: str type: str
proxy_header: proxyHeader:
description: description:
- Specifies the type of proxy header to append before sending data to the backend, - Specifies the type of proxy header to append before sending data to the backend,
either NONE or PROXY_V1. The default is NONE. either NONE or PROXY_V1. The default is NONE.
@ -102,7 +102,7 @@ items:
- A reference to the BackendService resource. - A reference to the BackendService resource.
returned: success returned: success
type: dict type: dict
ssl_certificates: sslCertificates:
description: description:
- A list of SslCertificate resources that are used to authenticate connections between - A list of SslCertificate resources that are used to authenticate connections between
users and the load balancer. Currently, exactly one SSL certificate must be specified. users and the load balancer. Currently, exactly one SSL certificate must be specified.
@ -124,7 +124,7 @@ import json
def main(): def main():
module = GcpModule( module = GcpModule(
argument_spec=dict( argument_spec=dict(
filters=dict(type='list', elements='str'), filters=dict(type='list', elements='str')
) )
) )

@ -69,6 +69,11 @@ options:
service: service:
description: description:
- A reference to the BackendService resource. - A reference to the BackendService resource.
- 'This field represents a link to a BackendService resource in GCP. It can be specified
in two ways. You can add `register: name-of-resource` to a gcp_compute_backend_service
task and then set this service field to "{{ name-of-resource }}" Alternatively,
you can set this service to a dictionary with the selfLink key where the value is
the selfLink of your BackendService.'
required: true required: true
extends_documentation_fragment: gcp extends_documentation_fragment: gcp
notes: notes:
@ -124,13 +129,13 @@ EXAMPLES = '''
proxy_header: PROXY_V1 proxy_header: PROXY_V1
service: "{{ backendservice }}" service: "{{ backendservice }}"
project: "test_project" project: "test_project"
auth_kind: "service_account" auth_kind: "serviceaccount"
service_account_file: "/tmp/auth.pem" service_account_file: "/tmp/auth.pem"
state: present state: present
''' '''
RETURN = ''' RETURN = '''
creation_timestamp: creationTimestamp:
description: description:
- Creation timestamp in RFC3339 text format. - Creation timestamp in RFC3339 text format.
returned: success returned: success
@ -155,7 +160,7 @@ RETURN = '''
be a dash. be a dash.
returned: success returned: success
type: str type: str
proxy_header: proxyHeader:
description: description:
- Specifies the type of proxy header to append before sending data to the backend, - Specifies the type of proxy header to append before sending data to the backend,
either NONE or PROXY_V1. The default is NONE. either NONE or PROXY_V1. The default is NONE.
@ -206,7 +211,8 @@ def main():
if fetch: if fetch:
if state == 'present': if state == 'present':
if is_different(module, fetch): if is_different(module, fetch):
fetch = update(module, self_link(module), kind) update(module, self_link(module), kind, fetch)
fetch = fetch_resource(module, self_link(module), kind)
changed = True changed = True
else: else:
delete(module, self_link(module), kind) delete(module, self_link(module), kind)
@ -229,9 +235,43 @@ def create(module, link, kind):
return wait_for_operation(module, auth.post(link, resource_to_request(module))) return wait_for_operation(module, auth.post(link, resource_to_request(module)))
def update(module, link, kind): 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('proxyHeader') != request.get('proxyHeader'):
proxy_header_update(module, request, response)
if response.get('service') != request.get('service'):
service_update(module, request, response)
def proxy_header_update(module, request, response):
auth = GcpSession(module, 'compute')
auth.post(
''.join([
"https://www.googleapis.com/compute/v1/",
"projects/{project}/global/targetTcpProxies/{name}/setProxyHeader"
]).format(**module.params),
{
u'proxyHeader': module.params.get('proxy_header')
}
)
def service_update(module, request, response):
auth = GcpSession(module, 'compute') auth = GcpSession(module, 'compute')
return wait_for_operation(module, auth.put(link, resource_to_request(module))) auth.post(
''.join([
"https://www.googleapis.com/compute/v1/",
"projects/{project}/global/targetTcpProxies/{name}/setBackendService"
]).format(**module.params),
{
u'service': replace_resource_dict(module.params.get(u'service', {}), 'selfLink')
}
)
def delete(module, link, kind): def delete(module, link, kind):
@ -255,9 +295,9 @@ def resource_to_request(module):
return return_vals return return_vals
def fetch_resource(module, link, kind): def fetch_resource(module, link, kind, allow_not_found=True):
auth = GcpSession(module, 'compute') auth = GcpSession(module, 'compute')
return return_if_object(module, auth.get(link), kind) return return_if_object(module, auth.get(link), kind, allow_not_found)
def self_link(module): def self_link(module):
@ -268,9 +308,9 @@ def collection(module):
return "https://www.googleapis.com/compute/v1/projects/{project}/global/targetTcpProxies".format(**module.params) return "https://www.googleapis.com/compute/v1/projects/{project}/global/targetTcpProxies".format(**module.params)
def return_if_object(module, response, kind): def return_if_object(module, response, kind, allow_not_found=False):
# If not found, return nothing. # If not found, return nothing.
if response.status_code == 404: if allow_not_found and response.status_code == 404:
return None return None
# If no content, return nothing. # If no content, return nothing.
@ -285,8 +325,6 @@ def return_if_object(module, response, kind):
if navigate_hash(result, ['error', 'errors']): if navigate_hash(result, ['error', 'errors']):
module.fail_json(msg=navigate_hash(result, ['error', 'errors'])) module.fail_json(msg=navigate_hash(result, ['error', 'errors']))
if result['kind'] != kind:
module.fail_json(msg="Incorrect result: {kind}".format(**result))
return result return result

@ -56,7 +56,7 @@ EXAMPLES = '''
filters: filters:
- name = test_object - name = test_object
project: test_project project: test_project
auth_kind: service_account auth_kind: serviceaccount
service_account_file: "/tmp/auth.pem" service_account_file: "/tmp/auth.pem"
''' '''
@ -66,7 +66,7 @@ items:
returned: always returned: always
type: complex type: complex
contains: contains:
creation_timestamp: creationTimestamp:
description: description:
- Creation timestamp in RFC3339 text format. - Creation timestamp in RFC3339 text format.
returned: success returned: success
@ -91,7 +91,7 @@ items:
be a dash. be a dash.
returned: success returned: success
type: str type: str
proxy_header: proxyHeader:
description: description:
- Specifies the type of proxy header to append before sending data to the backend, - Specifies the type of proxy header to append before sending data to the backend,
either NONE or PROXY_V1. The default is NONE. either NONE or PROXY_V1. The default is NONE.
@ -118,7 +118,7 @@ import json
def main(): def main():
module = GcpModule( module = GcpModule(
argument_spec=dict( argument_spec=dict(
filters=dict(type='list', elements='str'), filters=dict(type='list', elements='str')
) )
) )

@ -63,6 +63,11 @@ options:
network: network:
description: description:
- The network this VPN gateway is accepting traffic for. - The network this VPN gateway is accepting traffic for.
- 'This field represents a link to a Network resource in GCP. It can be specified
in two ways. You can add `register: name-of-resource` to a gcp_compute_network 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: true
region: region:
description: description:
@ -99,13 +104,13 @@ EXAMPLES = '''
region: us-west1 region: us-west1
network: "{{ network }}" network: "{{ network }}"
project: "test_project" project: "test_project"
auth_kind: "service_account" auth_kind: "serviceaccount"
service_account_file: "/tmp/auth.pem" service_account_file: "/tmp/auth.pem"
state: present state: present
''' '''
RETURN = ''' RETURN = '''
creation_timestamp: creationTimestamp:
description: description:
- Creation timestamp in RFC3339 text format. - Creation timestamp in RFC3339 text format.
returned: success returned: success
@ -140,7 +145,7 @@ RETURN = '''
- A list of references to VpnTunnel resources associated to this VPN gateway. - A list of references to VpnTunnel resources associated to this VPN gateway.
returned: success returned: success
type: list type: list
forwarding_rules: forwardingRules:
description: description:
- A list of references to the ForwardingRule resources associated to this VPN gateway. - A list of references to the ForwardingRule resources associated to this VPN gateway.
returned: success returned: success
@ -190,7 +195,8 @@ def main():
if fetch: if fetch:
if state == 'present': if state == 'present':
if is_different(module, fetch): if is_different(module, fetch):
fetch = update(module, self_link(module), kind) update(module, self_link(module), kind)
fetch = fetch_resource(module, self_link(module), kind)
changed = True changed = True
else: else:
delete(module, self_link(module), kind) delete(module, self_link(module), kind)
@ -214,8 +220,7 @@ def create(module, link, kind):
def update(module, link, kind): def update(module, link, kind):
auth = GcpSession(module, 'compute') module.fail_json(msg="TargetVpnGateway cannot be edited")
return wait_for_operation(module, auth.put(link, resource_to_request(module)))
def delete(module, link, kind): def delete(module, link, kind):
@ -238,9 +243,9 @@ def resource_to_request(module):
return return_vals return return_vals
def fetch_resource(module, link, kind): def fetch_resource(module, link, kind, allow_not_found=True):
auth = GcpSession(module, 'compute') auth = GcpSession(module, 'compute')
return return_if_object(module, auth.get(link), kind) return return_if_object(module, auth.get(link), kind, allow_not_found)
def self_link(module): def self_link(module):
@ -251,9 +256,9 @@ def collection(module):
return "https://www.googleapis.com/compute/v1/projects/{project}/regions/{region}/targetVpnGateways".format(**module.params) return "https://www.googleapis.com/compute/v1/projects/{project}/regions/{region}/targetVpnGateways".format(**module.params)
def return_if_object(module, response, kind): def return_if_object(module, response, kind, allow_not_found=False):
# If not found, return nothing. # If not found, return nothing.
if response.status_code == 404: if allow_not_found and response.status_code == 404:
return None return None
# If no content, return nothing. # If no content, return nothing.
@ -268,8 +273,6 @@ def return_if_object(module, response, kind):
if navigate_hash(result, ['error', 'errors']): if navigate_hash(result, ['error', 'errors']):
module.fail_json(msg=navigate_hash(result, ['error', 'errors'])) module.fail_json(msg=navigate_hash(result, ['error', 'errors']))
if result['kind'] != kind:
module.fail_json(msg="Incorrect result: {kind}".format(**result))
return result return result

@ -61,7 +61,7 @@ EXAMPLES = '''
filters: filters:
- name = test_object - name = test_object
project: test_project project: test_project
auth_kind: service_account auth_kind: serviceaccount
service_account_file: "/tmp/auth.pem" service_account_file: "/tmp/auth.pem"
''' '''
@ -71,7 +71,7 @@ items:
returned: always returned: always
type: complex type: complex
contains: contains:
creation_timestamp: creationTimestamp:
description: description:
- Creation timestamp in RFC3339 text format. - Creation timestamp in RFC3339 text format.
returned: success returned: success
@ -106,7 +106,7 @@ items:
- A list of references to VpnTunnel resources associated to this VPN gateway. - A list of references to VpnTunnel resources associated to this VPN gateway.
returned: success returned: success
type: list type: list
forwarding_rules: forwardingRules:
description: description:
- A list of references to the ForwardingRule resources associated to this VPN gateway. - A list of references to the ForwardingRule resources associated to this VPN gateway.
returned: success returned: success

@ -50,6 +50,11 @@ options:
default_service: default_service:
description: description:
- A reference to BackendService resource if none of the hostRules match. - A reference to BackendService resource if none of the hostRules match.
- 'This field represents a link to a BackendService resource in GCP. It can be specified
in two ways. You can add `register: name-of-resource` to a gcp_compute_backend_service
task and then set this default_service field to "{{ name-of-resource }}" Alternatively,
you can set this default_service to a dictionary with the selfLink key where the
value is the selfLink of your BackendService.'
required: true required: true
description: description:
description: description:
@ -71,12 +76,12 @@ options:
- The list of host patterns to match. They must be valid hostnames, except * will - The list of host patterns to match. They must be valid hostnames, except * will
match any string of ([a-z0-9-.]*). In that case, * must be the first character and match any string of ([a-z0-9-.]*). In that case, * must be the first character and
must be followed in the pattern by either - or . must be followed in the pattern by either - or .
required: false required: true
path_matcher: path_matcher:
description: description:
- The name of the PathMatcher to use to match the path portion of the URL if the hostRule - The name of the PathMatcher to use to match the path portion of the URL if the hostRule
matches the URL's host portion. matches the URL's host portion.
required: false required: true
name: name:
description: description:
- Name of the resource. Provided by the client when the resource is created. The name - Name of the resource. Provided by the client when the resource is created. The name
@ -85,7 +90,7 @@ options:
which means the first character must be a lowercase letter, and all following characters which means the first character must be a lowercase letter, and all following characters
must be a dash, lowercase letter, or digit, except the last character, which cannot must be a dash, lowercase letter, or digit, except the last character, which cannot
be a dash. be a dash.
required: false required: true
path_matchers: path_matchers:
description: description:
- The list of named PathMatchers to use against the URL. - The list of named PathMatchers to use against the URL.
@ -95,7 +100,12 @@ options:
description: description:
- A reference to a BackendService resource. This will be used if none of the pathRules - A reference to a BackendService resource. This will be used if none of the pathRules
defined by this PathMatcher is matched by the URL's path portion. defined by this PathMatcher is matched by the URL's path portion.
required: false - 'This field represents a link to a BackendService resource in GCP. It can be specified
in two ways. You can add `register: name-of-resource` to a gcp_compute_backend_service
task and then set this default_service field to "{{ name-of-resource }}" Alternatively,
you can set this default_service to a dictionary with the selfLink key where the
value is the selfLink of your BackendService.'
required: true
description: description:
description: description:
- An optional description of this resource. - An optional description of this resource.
@ -103,7 +113,7 @@ options:
name: name:
description: description:
- The name to which this PathMatcher is referred by the HostRule. - The name to which this PathMatcher is referred by the HostRule.
required: false required: true
path_rules: path_rules:
description: description:
- The list of path rules. - The list of path rules.
@ -118,7 +128,12 @@ options:
service: service:
description: description:
- A reference to the BackendService resource if this rule is matched. - A reference to the BackendService resource if this rule is matched.
required: false - 'This field represents a link to a BackendService resource in GCP. It can be specified
in two ways. You can add `register: name-of-resource` to a gcp_compute_backend_service
task and then set this service field to "{{ name-of-resource }}" Alternatively,
you can set this service to a dictionary with the selfLink key where the value is
the selfLink of your BackendService.'
required: true
tests: tests:
description: description:
- The list of expected URL mappings. Request to update this UrlMap will succeed only - The list of expected URL mappings. Request to update this UrlMap will succeed only
@ -132,15 +147,20 @@ options:
host: host:
description: description:
- Host portion of the URL. - Host portion of the URL.
required: false required: true
path: path:
description: description:
- Path portion of the URL. - Path portion of the URL.
required: false required: true
service: service:
description: description:
- A reference to expected BackendService resource the given URL should be mapped to. - A reference to expected BackendService resource the given URL should be mapped to.
required: false - 'This field represents a link to a BackendService resource in GCP. It can be specified
in two ways. You can add `register: name-of-resource` to a gcp_compute_backend_service
task and then set this service field to "{{ name-of-resource }}" Alternatively,
you can set this service to a dictionary with the selfLink key where the value is
the selfLink of your BackendService.'
required: true
extends_documentation_fragment: gcp extends_documentation_fragment: gcp
''' '''
@ -187,18 +207,18 @@ EXAMPLES = '''
name: "test_object" name: "test_object"
default_service: "{{ backendservice }}" default_service: "{{ backendservice }}"
project: "test_project" project: "test_project"
auth_kind: "service_account" auth_kind: "serviceaccount"
service_account_file: "/tmp/auth.pem" service_account_file: "/tmp/auth.pem"
state: present state: present
''' '''
RETURN = ''' RETURN = '''
creation_timestamp: creationTimestamp:
description: description:
- Creation timestamp in RFC3339 text format. - Creation timestamp in RFC3339 text format.
returned: success returned: success
type: str type: str
default_service: defaultService:
description: description:
- A reference to BackendService resource if none of the hostRules match. - A reference to BackendService resource if none of the hostRules match.
returned: success returned: success
@ -209,7 +229,7 @@ RETURN = '''
the resource. the resource.
returned: success returned: success
type: str type: str
host_rules: hostRules:
description: description:
- The list of HostRules to use against the URL. - The list of HostRules to use against the URL.
returned: success returned: success
@ -228,7 +248,7 @@ RETURN = '''
must be followed in the pattern by either - or . must be followed in the pattern by either - or .
returned: success returned: success
type: list type: list
path_matcher: pathMatcher:
description: description:
- The name of the PathMatcher to use to match the path portion of the URL if the hostRule - The name of the PathMatcher to use to match the path portion of the URL if the hostRule
matches the URL's host portion. matches the URL's host portion.
@ -239,6 +259,12 @@ RETURN = '''
- The unique identifier for the resource. - The unique identifier for the resource.
returned: success returned: success
type: int type: int
fingerprint:
description:
- Fingerprint of this resource. This field is used internally during updates of this
resource.
returned: success
type: str
name: name:
description: description:
- Name of the resource. Provided by the client when the resource is created. The name - Name of the resource. Provided by the client when the resource is created. The name
@ -249,13 +275,13 @@ RETURN = '''
be a dash. be a dash.
returned: success returned: success
type: str type: str
path_matchers: pathMatchers:
description: description:
- The list of named PathMatchers to use against the URL. - The list of named PathMatchers to use against the URL.
returned: success returned: success
type: complex type: complex
contains: contains:
default_service: defaultService:
description: description:
- A reference to a BackendService resource. This will be used if none of the pathRules - A reference to a BackendService resource. This will be used if none of the pathRules
defined by this PathMatcher is matched by the URL's path portion. defined by this PathMatcher is matched by the URL's path portion.
@ -271,7 +297,7 @@ RETURN = '''
- The name to which this PathMatcher is referred by the HostRule. - The name to which this PathMatcher is referred by the HostRule.
returned: success returned: success
type: str type: str
path_rules: pathRules:
description: description:
- The list of path rules. - The list of path rules.
returned: success returned: success
@ -341,24 +367,24 @@ def main():
description=dict(type='str'), description=dict(type='str'),
host_rules=dict(type='list', elements='dict', options=dict( host_rules=dict(type='list', elements='dict', options=dict(
description=dict(type='str'), description=dict(type='str'),
hosts=dict(type='list', elements='str'), hosts=dict(required=True, type='list', elements='str'),
path_matcher=dict(type='str') path_matcher=dict(required=True, type='str')
)), )),
name=dict(type='str'), name=dict(required=True, type='str'),
path_matchers=dict(type='list', elements='dict', options=dict( path_matchers=dict(type='list', elements='dict', options=dict(
default_service=dict(type='dict'), default_service=dict(required=True, type='dict'),
description=dict(type='str'), description=dict(type='str'),
name=dict(type='str'), name=dict(required=True, type='str'),
path_rules=dict(type='list', elements='dict', options=dict( path_rules=dict(type='list', elements='dict', options=dict(
paths=dict(type='list', elements='str'), paths=dict(type='list', elements='str'),
service=dict(type='dict') service=dict(required=True, type='dict')
)) ))
)), )),
tests=dict(type='list', elements='dict', options=dict( tests=dict(type='list', elements='dict', options=dict(
description=dict(type='str'), description=dict(type='str'),
host=dict(type='str'), host=dict(required=True, type='str'),
path=dict(type='str'), path=dict(required=True, type='str'),
service=dict(type='dict') service=dict(required=True, type='dict')
)) ))
) )
) )
@ -375,7 +401,8 @@ def main():
if fetch: if fetch:
if state == 'present': if state == 'present':
if is_different(module, fetch): if is_different(module, fetch):
fetch = update(module, self_link(module), kind) update(module, self_link(module), kind)
fetch = fetch_resource(module, self_link(module), kind)
changed = True changed = True
else: else:
delete(module, self_link(module), kind) delete(module, self_link(module), kind)
@ -426,9 +453,9 @@ def resource_to_request(module):
return return_vals return return_vals
def fetch_resource(module, link, kind): def fetch_resource(module, link, kind, allow_not_found=True):
auth = GcpSession(module, 'compute') auth = GcpSession(module, 'compute')
return return_if_object(module, auth.get(link), kind) return return_if_object(module, auth.get(link), kind, allow_not_found)
def self_link(module): def self_link(module):
@ -439,9 +466,9 @@ def collection(module):
return "https://www.googleapis.com/compute/v1/projects/{project}/global/urlMaps".format(**module.params) return "https://www.googleapis.com/compute/v1/projects/{project}/global/urlMaps".format(**module.params)
def return_if_object(module, response, kind): def return_if_object(module, response, kind, allow_not_found=False):
# If not found, return nothing. # If not found, return nothing.
if response.status_code == 404: if allow_not_found and response.status_code == 404:
return None return None
# If no content, return nothing. # If no content, return nothing.
@ -456,8 +483,6 @@ def return_if_object(module, response, kind):
if navigate_hash(result, ['error', 'errors']): if navigate_hash(result, ['error', 'errors']):
module.fail_json(msg=navigate_hash(result, ['error', 'errors'])) module.fail_json(msg=navigate_hash(result, ['error', 'errors']))
if result['kind'] != kind:
module.fail_json(msg="Incorrect result: {kind}".format(**result))
return result return result
@ -489,7 +514,8 @@ def response_to_hash(module, response):
u'description': response.get(u'description'), u'description': response.get(u'description'),
u'hostRules': UrlMapHostRulesArray(response.get(u'hostRules', []), module).from_response(), u'hostRules': UrlMapHostRulesArray(response.get(u'hostRules', []), module).from_response(),
u'id': response.get(u'id'), u'id': response.get(u'id'),
u'name': response.get(u'name'), u'fingerprint': response.get(u'fingerprint'),
u'name': module.params.get('name'),
u'pathMatchers': UrlMapPathMatchersArray(response.get(u'pathMatchers', []), module).from_response(), u'pathMatchers': UrlMapPathMatchersArray(response.get(u'pathMatchers', []), module).from_response(),
u'tests': UrlMapTestsArray(response.get(u'tests', []), module).from_response() u'tests': UrlMapTestsArray(response.get(u'tests', []), module).from_response()
} }

@ -56,7 +56,7 @@ EXAMPLES = '''
filters: filters:
- name = test_object - name = test_object
project: test_project project: test_project
auth_kind: service_account auth_kind: serviceaccount
service_account_file: "/tmp/auth.pem" service_account_file: "/tmp/auth.pem"
''' '''
@ -66,12 +66,12 @@ items:
returned: always returned: always
type: complex type: complex
contains: contains:
creation_timestamp: creationTimestamp:
description: description:
- Creation timestamp in RFC3339 text format. - Creation timestamp in RFC3339 text format.
returned: success returned: success
type: str type: str
default_service: defaultService:
description: description:
- A reference to BackendService resource if none of the hostRules match. - A reference to BackendService resource if none of the hostRules match.
returned: success returned: success
@ -82,7 +82,7 @@ items:
the resource. the resource.
returned: success returned: success
type: str type: str
host_rules: hostRules:
description: description:
- The list of HostRules to use against the URL. - The list of HostRules to use against the URL.
returned: success returned: success
@ -101,7 +101,7 @@ items:
must be followed in the pattern by either - or . must be followed in the pattern by either - or .
returned: success returned: success
type: list type: list
path_matcher: pathMatcher:
description: description:
- The name of the PathMatcher to use to match the path portion of the URL if the hostRule - The name of the PathMatcher to use to match the path portion of the URL if the hostRule
matches the URL's host portion. matches the URL's host portion.
@ -112,6 +112,12 @@ items:
- The unique identifier for the resource. - The unique identifier for the resource.
returned: success returned: success
type: int type: int
fingerprint:
description:
- Fingerprint of this resource. This field is used internally during updates of this
resource.
returned: success
type: str
name: name:
description: description:
- Name of the resource. Provided by the client when the resource is created. The name - Name of the resource. Provided by the client when the resource is created. The name
@ -122,13 +128,13 @@ items:
be a dash. be a dash.
returned: success returned: success
type: str type: str
path_matchers: pathMatchers:
description: description:
- The list of named PathMatchers to use against the URL. - The list of named PathMatchers to use against the URL.
returned: success returned: success
type: complex type: complex
contains: contains:
default_service: defaultService:
description: description:
- A reference to a BackendService resource. This will be used if none of the pathRules - A reference to a BackendService resource. This will be used if none of the pathRules
defined by this PathMatcher is matched by the URL's path portion. defined by this PathMatcher is matched by the URL's path portion.
@ -144,7 +150,7 @@ items:
- The name to which this PathMatcher is referred by the HostRule. - The name to which this PathMatcher is referred by the HostRule.
returned: success returned: success
type: str type: str
path_rules: pathRules:
description: description:
- The list of path rules. - The list of path rules.
returned: success returned: success
@ -205,7 +211,7 @@ import json
def main(): def main():
module = GcpModule( module = GcpModule(
argument_spec=dict( argument_spec=dict(
filters=dict(type='list', elements='str'), filters=dict(type='list', elements='str')
) )
) )

@ -61,10 +61,20 @@ options:
target_vpn_gateway: target_vpn_gateway:
description: description:
- URL of the Target VPN gateway with which this VPN tunnel is associated. - URL of the Target VPN gateway with which this VPN tunnel is associated.
- 'This field represents a link to a TargetVpnGateway resource in GCP. It can be specified
in two ways. You can add `register: name-of-resource` to a gcp_compute_target_vpn_gateway
task and then set this target_vpn_gateway field to "{{ name-of-resource }}" Alternatively,
you can set this target_vpn_gateway to a dictionary with the selfLink key where
the value is the selfLink of your TargetVpnGateway.'
required: true required: true
router: router:
description: description:
- URL of router resource to be used for dynamic routing. - URL of router resource to be used for dynamic routing.
- 'This field represents a link to a Router resource in GCP. It can be specified in
two ways. You can add `register: name-of-resource` to a gcp_compute_router task
and then set this router field to "{{ name-of-resource }}" Alternatively, you can
set this router to a dictionary with the selfLink key where the value is the selfLink
of your Router.'
required: false required: false
peer_ip: peer_ip:
description: description:
@ -158,13 +168,13 @@ EXAMPLES = '''
router: "{{ router }}" router: "{{ router }}"
shared_secret: super secret shared_secret: super secret
project: "test_project" project: "test_project"
auth_kind: "service_account" auth_kind: "serviceaccount"
service_account_file: "/tmp/auth.pem" service_account_file: "/tmp/auth.pem"
state: present state: present
''' '''
RETURN = ''' RETURN = '''
creation_timestamp: creationTimestamp:
description: description:
- Creation timestamp in RFC3339 text format. - Creation timestamp in RFC3339 text format.
returned: success returned: success
@ -183,7 +193,7 @@ RETURN = '''
- An optional description of this resource. - An optional description of this resource.
returned: success returned: success
type: str type: str
target_vpn_gateway: targetVpnGateway:
description: description:
- URL of the Target VPN gateway with which this VPN tunnel is associated. - URL of the Target VPN gateway with which this VPN tunnel is associated.
returned: success returned: success
@ -192,30 +202,30 @@ RETURN = '''
description: description:
- URL of router resource to be used for dynamic routing. - URL of router resource to be used for dynamic routing.
returned: success returned: success
type: str type: dict
peer_ip: peerIp:
description: description:
- IP address of the peer VPN gateway. Only IPv4 is supported. - IP address of the peer VPN gateway. Only IPv4 is supported.
returned: success returned: success
type: str type: str
shared_secret: sharedSecret:
description: description:
- Shared secret used to set the secure session between the Cloud VPN gateway and the - Shared secret used to set the secure session between the Cloud VPN gateway and the
peer VPN gateway. peer VPN gateway.
returned: success returned: success
type: str type: str
shared_secret_hash: sharedSecretHash:
description: description:
- Hash of the shared secret. - Hash of the shared secret.
returned: success returned: success
type: str type: str
ike_version: ikeVersion:
description: description:
- IKE protocol version to use when establishing the VPN tunnel with peer VPN gateway. - IKE protocol version to use when establishing the VPN tunnel with peer VPN gateway.
- Acceptable IKE versions are 1 or 2. Default version is 2. - Acceptable IKE versions are 1 or 2. Default version is 2.
returned: success returned: success
type: int type: int
local_traffic_selector: localTrafficSelector:
description: description:
- Local traffic selector to use when establishing the VPN tunnel with peer VPN gateway. - Local traffic selector to use when establishing the VPN tunnel with peer VPN gateway.
The value should be a CIDR formatted string, for example `192.168.0.0/16`. The ranges The value should be a CIDR formatted string, for example `192.168.0.0/16`. The ranges
@ -223,7 +233,7 @@ RETURN = '''
- Only IPv4 is supported. - Only IPv4 is supported.
returned: success returned: success
type: list type: list
remote_traffic_selector: remoteTrafficSelector:
description: description:
- Remote traffic selector to use when establishing the VPN tunnel with peer VPN gateway. - Remote traffic selector to use when establishing the VPN tunnel with peer VPN gateway.
The value should be a CIDR formatted string, for example `192.168.0.0/16`. The ranges The value should be a CIDR formatted string, for example `192.168.0.0/16`. The ranges
@ -236,6 +246,12 @@ RETURN = '''
- Labels to apply to this VpnTunnel. - Labels to apply to this VpnTunnel.
returned: success returned: success
type: dict type: dict
labelFingerprint:
description:
- The fingerprint used for optimistic locking of this resource. Used internally during
updates.
returned: success
type: str
region: region:
description: description:
- The region where the tunnel is located. - The region where the tunnel is located.
@ -265,7 +281,7 @@ def main():
name=dict(required=True, type='str'), name=dict(required=True, type='str'),
description=dict(type='str'), description=dict(type='str'),
target_vpn_gateway=dict(required=True, type='dict'), target_vpn_gateway=dict(required=True, type='dict'),
router=dict(type='str'), router=dict(type='dict'),
peer_ip=dict(required=True, type='str'), peer_ip=dict(required=True, type='str'),
shared_secret=dict(required=True, type='str'), shared_secret=dict(required=True, type='str'),
ike_version=dict(default=2, type='int'), ike_version=dict(default=2, type='int'),
@ -288,7 +304,8 @@ def main():
if fetch: if fetch:
if state == 'present': if state == 'present':
if is_different(module, fetch): if is_different(module, fetch):
fetch = update(module, self_link(module), kind) update(module, self_link(module), kind, fetch)
fetch = fetch_resource(module, self_link(module), kind)
changed = True changed = True
else: else:
delete(module, self_link(module), kind) delete(module, self_link(module), kind)
@ -297,6 +314,7 @@ def main():
else: else:
if state == 'present': if state == 'present':
fetch = create(module, collection(module), kind) fetch = create(module, collection(module), kind)
labels_update(module, module.params, fetch)
changed = True changed = True
else: else:
fetch = {} fetch = {}
@ -311,9 +329,29 @@ def create(module, link, kind):
return wait_for_operation(module, auth.post(link, resource_to_request(module))) return wait_for_operation(module, auth.post(link, resource_to_request(module)))
def update(module, link, kind): 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('labels') != request.get('labels'):
labels_update(module, request, response)
def labels_update(module, request, response):
auth = GcpSession(module, 'compute') auth = GcpSession(module, 'compute')
return wait_for_operation(module, auth.put(link, resource_to_request(module))) auth.post(
''.join([
"https://www.googleapis.com/compute/v1/",
"projects/{project}/regions/{region}/vpnTunnels/{name}/setLabels"
]).format(**module.params),
{
u'labels': module.params.get('labels'),
u'labelFingerprint': response.get('labelFingerprint')
}
)
def delete(module, link, kind): def delete(module, link, kind):
@ -327,7 +365,7 @@ def resource_to_request(module):
u'name': module.params.get('name'), u'name': module.params.get('name'),
u'description': module.params.get('description'), u'description': module.params.get('description'),
u'targetVpnGateway': replace_resource_dict(module.params.get(u'target_vpn_gateway', {}), 'selfLink'), u'targetVpnGateway': replace_resource_dict(module.params.get(u'target_vpn_gateway', {}), 'selfLink'),
u'router': module.params.get('router'), u'router': replace_resource_dict(module.params.get(u'router', {}), 'selfLink'),
u'peerIp': module.params.get('peer_ip'), u'peerIp': module.params.get('peer_ip'),
u'sharedSecret': module.params.get('shared_secret'), u'sharedSecret': module.params.get('shared_secret'),
u'ikeVersion': module.params.get('ike_version'), u'ikeVersion': module.params.get('ike_version'),
@ -343,9 +381,9 @@ def resource_to_request(module):
return return_vals return return_vals
def fetch_resource(module, link, kind): def fetch_resource(module, link, kind, allow_not_found=True):
auth = GcpSession(module, 'compute') auth = GcpSession(module, 'compute')
return return_if_object(module, auth.get(link), kind) return return_if_object(module, auth.get(link), kind, allow_not_found)
def self_link(module): def self_link(module):
@ -356,9 +394,9 @@ def collection(module):
return "https://www.googleapis.com/compute/v1/projects/{project}/regions/{region}/vpnTunnels".format(**module.params) return "https://www.googleapis.com/compute/v1/projects/{project}/regions/{region}/vpnTunnels".format(**module.params)
def return_if_object(module, response, kind): def return_if_object(module, response, kind, allow_not_found=False):
# If not found, return nothing. # If not found, return nothing.
if response.status_code == 404: if allow_not_found and response.status_code == 404:
return None return None
# If no content, return nothing. # If no content, return nothing.
@ -373,8 +411,6 @@ def return_if_object(module, response, kind):
if navigate_hash(result, ['error', 'errors']): if navigate_hash(result, ['error', 'errors']):
module.fail_json(msg=navigate_hash(result, ['error', 'errors'])) module.fail_json(msg=navigate_hash(result, ['error', 'errors']))
if result['kind'] != kind:
module.fail_json(msg="Incorrect result: {kind}".format(**result))
return result return result
@ -405,14 +441,15 @@ def response_to_hash(module, response):
u'name': response.get(u'name'), u'name': response.get(u'name'),
u'description': module.params.get('description'), u'description': module.params.get('description'),
u'targetVpnGateway': replace_resource_dict(module.params.get(u'target_vpn_gateway', {}), 'selfLink'), u'targetVpnGateway': replace_resource_dict(module.params.get(u'target_vpn_gateway', {}), 'selfLink'),
u'router': module.params.get('router'), u'router': replace_resource_dict(module.params.get(u'router', {}), 'selfLink'),
u'peerIp': response.get(u'peerIp'), u'peerIp': response.get(u'peerIp'),
u'sharedSecret': response.get(u'sharedSecret'), u'sharedSecret': response.get(u'sharedSecret'),
u'sharedSecretHash': response.get(u'sharedSecretHash'), u'sharedSecretHash': response.get(u'sharedSecretHash'),
u'ikeVersion': response.get(u'ikeVersion'), u'ikeVersion': response.get(u'ikeVersion'),
u'localTrafficSelector': response.get(u'localTrafficSelector'), u'localTrafficSelector': response.get(u'localTrafficSelector'),
u'remoteTrafficSelector': response.get(u'remoteTrafficSelector'), u'remoteTrafficSelector': response.get(u'remoteTrafficSelector'),
u'labels': response.get(u'labels') u'labels': response.get(u'labels'),
u'labelFingerprint': response.get(u'labelFingerprint')
} }

@ -61,7 +61,7 @@ EXAMPLES = '''
filters: filters:
- name = test_object - name = test_object
project: test_project project: test_project
auth_kind: service_account auth_kind: serviceaccount
service_account_file: "/tmp/auth.pem" service_account_file: "/tmp/auth.pem"
''' '''
@ -71,7 +71,7 @@ items:
returned: always returned: always
type: complex type: complex
contains: contains:
creation_timestamp: creationTimestamp:
description: description:
- Creation timestamp in RFC3339 text format. - Creation timestamp in RFC3339 text format.
returned: success returned: success
@ -90,7 +90,7 @@ items:
- An optional description of this resource. - An optional description of this resource.
returned: success returned: success
type: str type: str
target_vpn_gateway: targetVpnGateway:
description: description:
- URL of the Target VPN gateway with which this VPN tunnel is associated. - URL of the Target VPN gateway with which this VPN tunnel is associated.
returned: success returned: success
@ -99,30 +99,30 @@ items:
description: description:
- URL of router resource to be used for dynamic routing. - URL of router resource to be used for dynamic routing.
returned: success returned: success
type: str type: dict
peer_ip: peerIp:
description: description:
- IP address of the peer VPN gateway. Only IPv4 is supported. - IP address of the peer VPN gateway. Only IPv4 is supported.
returned: success returned: success
type: str type: str
shared_secret: sharedSecret:
description: description:
- Shared secret used to set the secure session between the Cloud VPN gateway and the - Shared secret used to set the secure session between the Cloud VPN gateway and the
peer VPN gateway. peer VPN gateway.
returned: success returned: success
type: str type: str
shared_secret_hash: sharedSecretHash:
description: description:
- Hash of the shared secret. - Hash of the shared secret.
returned: success returned: success
type: str type: str
ike_version: ikeVersion:
description: description:
- IKE protocol version to use when establishing the VPN tunnel with peer VPN gateway. - IKE protocol version to use when establishing the VPN tunnel with peer VPN gateway.
- Acceptable IKE versions are 1 or 2. Default version is 2. - Acceptable IKE versions are 1 or 2. Default version is 2.
returned: success returned: success
type: int type: int
local_traffic_selector: localTrafficSelector:
description: description:
- Local traffic selector to use when establishing the VPN tunnel with peer VPN gateway. - Local traffic selector to use when establishing the VPN tunnel with peer VPN gateway.
The value should be a CIDR formatted string, for example `192.168.0.0/16`. The ranges The value should be a CIDR formatted string, for example `192.168.0.0/16`. The ranges
@ -130,7 +130,7 @@ items:
- Only IPv4 is supported. - Only IPv4 is supported.
returned: success returned: success
type: list type: list
remote_traffic_selector: remoteTrafficSelector:
description: description:
- Remote traffic selector to use when establishing the VPN tunnel with peer VPN gateway. - Remote traffic selector to use when establishing the VPN tunnel with peer VPN gateway.
The value should be a CIDR formatted string, for example `192.168.0.0/16`. The ranges The value should be a CIDR formatted string, for example `192.168.0.0/16`. The ranges
@ -143,6 +143,12 @@ items:
- Labels to apply to this VpnTunnel. - Labels to apply to this VpnTunnel.
returned: success returned: success
type: dict type: dict
labelFingerprint:
description:
- The fingerprint used for optimistic locking of this resource. Used internally during
updates.
returned: success
type: str
region: region:
description: description:
- The region where the tunnel is located. - The region where the tunnel is located.

@ -268,7 +268,7 @@ EXAMPLES = '''
disk_size_gb: 500 disk_size_gb: 500
zone: us-central1-a zone: us-central1-a
project: "test_project" project: "test_project"
auth_kind: "service_account" auth_kind: "serviceaccount"
service_account_file: "/tmp/auth.pem" service_account_file: "/tmp/auth.pem"
state: present state: present
''' '''
@ -286,7 +286,7 @@ RETURN = '''
- An optional description of this cluster. - An optional description of this cluster.
returned: success returned: success
type: str type: str
initial_node_count: initialNodeCount:
description: description:
- The number of nodes to create in this cluster. You must ensure that your Compute - The number of nodes to create in this cluster. You must ensure that your Compute
Engine resource quota is sufficient for this number of instances. You must also Engine resource quota is sufficient for this number of instances. You must also
@ -296,7 +296,7 @@ RETURN = '''
this and a nodePool at the same time. this and a nodePool at the same time.
returned: success returned: success
type: int type: int
node_config: nodeConfig:
description: description:
- Parameters used in creating the cluster's nodes. - Parameters used in creating the cluster's nodes.
- For requests, this field should only be used in lieu of a "nodePool" object, since - For requests, this field should only be used in lieu of a "nodePool" object, since
@ -307,19 +307,19 @@ RETURN = '''
returned: success returned: success
type: complex type: complex
contains: contains:
machine_type: machineType:
description: description:
- The name of a Google Compute Engine machine type (e.g. - The name of a Google Compute Engine machine type (e.g.
- n1-standard-1). If unspecified, the default machine type is n1-standard-1. - n1-standard-1). If unspecified, the default machine type is n1-standard-1.
returned: success returned: success
type: str type: str
disk_size_gb: diskSizeGb:
description: description:
- Size of the disk attached to each node, specified in GB. The smallest allowed disk - Size of the disk attached to each node, specified in GB. The smallest allowed disk
size is 10GB. If unspecified, the default disk size is 100GB. size is 10GB. If unspecified, the default disk size is 100GB.
returned: success returned: success
type: int type: int
oauth_scopes: oauthScopes:
description: description:
- The set of Google API scopes to be made available on all of the node VMs under the - The set of Google API scopes to be made available on all of the node VMs under the
"default" service account. "default" service account.
@ -332,7 +332,7 @@ RETURN = '''
enabled, in which case their required scopes will be added. enabled, in which case their required scopes will be added.
returned: success returned: success
type: list type: list
service_account: serviceAccount:
description: description:
- The Google Cloud Platform Service Account to be used by the node VMs. If no Service - The Google Cloud Platform Service Account to be used by the node VMs. If no Service
Account is specified, the "default" service account is used. Account is specified, the "default" service account is used.
@ -353,7 +353,7 @@ RETURN = '''
- 'Example: { "name": "wrench", "mass": "1.3kg", "count": "3" }.' - 'Example: { "name": "wrench", "mass": "1.3kg", "count": "3" }.'
returned: success returned: success
type: dict type: dict
image_type: imageType:
description: description:
- The image type to use for this node. Note that for a given image type, the latest - The image type to use for this node. Note that for a given image type, the latest
version of it will be used. version of it will be used.
@ -371,7 +371,7 @@ RETURN = '''
- 'Example: { "name": "wrench", "mass": "1.3kg", "count": "3" }.' - 'Example: { "name": "wrench", "mass": "1.3kg", "count": "3" }.'
returned: success returned: success
type: dict type: dict
local_ssd_count: localSsdCount:
description: description:
- The number of local SSD disks to be attached to the node. - The number of local SSD disks to be attached to the node.
- 'The limit for this value is dependant upon the maximum number of disks available - 'The limit for this value is dependant upon the maximum number of disks available
@ -392,7 +392,7 @@ RETURN = '''
for more inforamtion about preemptible VM instances.' for more inforamtion about preemptible VM instances.'
returned: success returned: success
type: bool type: bool
master_auth: masterAuth:
description: description:
- The authentication information for accessing the master endpoint. - The authentication information for accessing the master endpoint.
returned: success returned: success
@ -409,23 +409,23 @@ RETURN = '''
the master endpoint is open to the Internet, you should create a strong password. the master endpoint is open to the Internet, you should create a strong password.
returned: success returned: success
type: str type: str
cluster_ca_certificate: clusterCaCertificate:
description: description:
- Base64-encoded public certificate that is the root of trust for the cluster. - Base64-encoded public certificate that is the root of trust for the cluster.
returned: success returned: success
type: str type: str
client_certificate: clientCertificate:
description: description:
- Base64-encoded public certificate used by clients to authenticate to the cluster - Base64-encoded public certificate used by clients to authenticate to the cluster
endpoint. endpoint.
returned: success returned: success
type: str type: str
client_key: clientKey:
description: description:
- Base64-encoded private key used by clients to authenticate to the cluster endpoint. - Base64-encoded private key used by clients to authenticate to the cluster endpoint.
returned: success returned: success
type: str type: str
logging_service: loggingService:
description: description:
- 'The logging service the cluster should use to write logs. Currently available options: logging.googleapis.com - 'The logging service the cluster should use to write logs. Currently available options: logging.googleapis.com
- the Google Cloud Logging service.' - the Google Cloud Logging service.'
@ -433,7 +433,7 @@ RETURN = '''
- if left as an empty string,logging.googleapis.com will be used. - if left as an empty string,logging.googleapis.com will be used.
returned: success returned: success
type: str type: str
monitoring_service: monitoringService:
description: description:
- The monitoring service the cluster should use to write metrics. - The monitoring service the cluster should use to write metrics.
- 'Currently available options: monitoring.googleapis.com - the Google Cloud Monitoring - 'Currently available options: monitoring.googleapis.com - the Google Cloud Monitoring
@ -450,20 +450,20 @@ RETURN = '''
resource. resource.
returned: success returned: success
type: str type: str
cluster_ipv4_cidr: clusterIpv4Cidr:
description: description:
- The IP address range of the container pods in this cluster, in CIDR notation (e.g. - The IP address range of the container pods in this cluster, in CIDR notation (e.g.
10.96.0.0/14). Leave blank to have one automatically chosen or specify a /14 block 10.96.0.0/14). Leave blank to have one automatically chosen or specify a /14 block
in 10.0.0.0/8. in 10.0.0.0/8.
returned: success returned: success
type: str type: str
addons_config: addonsConfig:
description: description:
- Configurations for the various addons available to run in the cluster. - Configurations for the various addons available to run in the cluster.
returned: success returned: success
type: complex type: complex
contains: contains:
http_load_balancing: httpLoadBalancing:
description: description:
- Configuration for the HTTP (L7) load balancing controller addon, which makes it - Configuration for the HTTP (L7) load balancing controller addon, which makes it
easy to set up HTTP load balancers for services in a cluster. easy to set up HTTP load balancers for services in a cluster.
@ -476,7 +476,7 @@ RETURN = '''
it runs a small pod in the cluster that manages the load balancers. it runs a small pod in the cluster that manages the load balancers.
returned: success returned: success
type: bool type: bool
horizontal_pod_autoscaling: horizontalPodAutoscaling:
description: description:
- Configuration for the horizontal pod autoscaling feature, which increases or decreases - Configuration for the horizontal pod autoscaling feature, which increases or decreases
the number of replica pods a replication controller has based on the resource usage the number of replica pods a replication controller has based on the resource usage
@ -509,48 +509,48 @@ RETURN = '''
the masterAuth property of this resource for username and password information. the masterAuth property of this resource for username and password information.
returned: success returned: success
type: str type: str
initial_cluster_version: initialClusterVersion:
description: description:
- The software version of the master endpoint and kubelets used in the cluster when - The software version of the master endpoint and kubelets used in the cluster when
it was first created. The version can be upgraded over time. it was first created. The version can be upgraded over time.
returned: success returned: success
type: str type: str
current_master_version: currentMasterVersion:
description: description:
- The current software version of the master endpoint. - The current software version of the master endpoint.
returned: success returned: success
type: str type: str
current_node_version: currentNodeVersion:
description: description:
- The current version of the node software components. If they are currently at multiple - The current version of the node software components. If they are currently at multiple
versions because they're in the process of being upgraded, this reflects the minimum versions because they're in the process of being upgraded, this reflects the minimum
version of all nodes. version of all nodes.
returned: success returned: success
type: str type: str
create_time: createTime:
description: description:
- The time the cluster was created, in RFC3339 text format. - The time the cluster was created, in RFC3339 text format.
returned: success returned: success
type: str type: str
node_ipv4_cidr_size: nodeIpv4CidrSize:
description: description:
- The size of the address space on each node for hosting containers. - The size of the address space on each node for hosting containers.
- This is provisioned from within the container_ipv4_cidr range. - This is provisioned from within the container_ipv4_cidr range.
returned: success returned: success
type: int type: int
services_ipv4_cidr: servicesIpv4Cidr:
description: description:
- The IP address range of the Kubernetes services in this cluster, in CIDR notation - The IP address range of the Kubernetes services in this cluster, in CIDR notation
(e.g. 1.2.3.4/29). Service addresses are typically put in the last /16 from the (e.g. 1.2.3.4/29). Service addresses are typically put in the last /16 from the
container CIDR. container CIDR.
returned: success returned: success
type: str type: str
current_node_count: currentNodeCount:
description: description:
- The number of nodes currently in the cluster. - The number of nodes currently in the cluster.
returned: success returned: success
type: int type: int
expire_time: expireTime:
description: description:
- The time the cluster will be automatically deleted in RFC3339 text format. - The time the cluster will be automatically deleted in RFC3339 text format.
returned: success returned: success
@ -632,7 +632,8 @@ def main():
if fetch: if fetch:
if state == 'present': if state == 'present':
if is_different(module, fetch): if is_different(module, fetch):
fetch = update(module, self_link(module)) update(module, self_link(module))
fetch = fetch_resource(module, self_link(module))
changed = True changed = True
else: else:
delete(module, self_link(module)) delete(module, self_link(module))
@ -689,9 +690,9 @@ def resource_to_request(module):
return return_vals return return_vals
def fetch_resource(module, link): def fetch_resource(module, link, allow_not_found=True):
auth = GcpSession(module, 'container') auth = GcpSession(module, 'container')
return return_if_object(module, auth.get(link)) return return_if_object(module, auth.get(link), allow_not_found)
def self_link(module): def self_link(module):
@ -702,9 +703,9 @@ def collection(module):
return "https://container.googleapis.com/v1/projects/{project}/zones/{zone}/clusters".format(**module.params) return "https://container.googleapis.com/v1/projects/{project}/zones/{zone}/clusters".format(**module.params)
def return_if_object(module, response): def return_if_object(module, response, allow_not_found=False):
# If not found, return nothing. # If not found, return nothing.
if response.status_code == 404: if allow_not_found and response.status_code == 404:
return None return None
# If no content, return nothing. # If no content, return nothing.

@ -198,6 +198,11 @@ options:
cluster: cluster:
description: description:
- The cluster this node pool belongs to. - The cluster this node pool belongs to.
- 'This field represents a link to a Cluster resource in GCP. It can be specified
in two ways. You can add `register: name-of-resource` to a gcp_container_cluster
task and then set this cluster field to "{{ name-of-resource }}" Alternatively,
you can set this cluster to a dictionary with the name key where the value is the
name of your Cluster.'
required: true required: true
zone: zone:
description: description:
@ -225,7 +230,7 @@ EXAMPLES = '''
cluster: "{{ cluster }}" cluster: "{{ cluster }}"
zone: us-central1-a zone: us-central1-a
project: "test_project" project: "test_project"
auth_kind: "service_account" auth_kind: "serviceaccount"
service_account_file: "/tmp/auth.pem" service_account_file: "/tmp/auth.pem"
state: present state: present
''' '''
@ -242,19 +247,19 @@ RETURN = '''
returned: success returned: success
type: complex type: complex
contains: contains:
machine_type: machineType:
description: description:
- The name of a Google Compute Engine machine type (e.g. - The name of a Google Compute Engine machine type (e.g.
- n1-standard-1). If unspecified, the default machine type is n1-standard-1. - n1-standard-1). If unspecified, the default machine type is n1-standard-1.
returned: success returned: success
type: str type: str
disk_size_gb: diskSizeGb:
description: description:
- Size of the disk attached to each node, specified in GB. The smallest allowed disk - Size of the disk attached to each node, specified in GB. The smallest allowed disk
size is 10GB. If unspecified, the default disk size is 100GB. size is 10GB. If unspecified, the default disk size is 100GB.
returned: success returned: success
type: int type: int
oauth_scopes: oauthScopes:
description: description:
- The set of Google API scopes to be made available on all of the node VMs under the - The set of Google API scopes to be made available on all of the node VMs under the
"default" service account. "default" service account.
@ -267,7 +272,7 @@ RETURN = '''
enabled, in which case their required scopes will be added. enabled, in which case their required scopes will be added.
returned: success returned: success
type: list type: list
service_account: serviceAccount:
description: description:
- The Google Cloud Platform Service Account to be used by the node VMs. If no Service - The Google Cloud Platform Service Account to be used by the node VMs. If no Service
Account is specified, the "default" service account is used. Account is specified, the "default" service account is used.
@ -288,7 +293,7 @@ RETURN = '''
- 'Example: { "name": "wrench", "mass": "1.3kg", "count": "3" }.' - 'Example: { "name": "wrench", "mass": "1.3kg", "count": "3" }.'
returned: success returned: success
type: dict type: dict
image_type: imageType:
description: description:
- The image type to use for this node. Note that for a given image type, the latest - The image type to use for this node. Note that for a given image type, the latest
version of it will be used. version of it will be used.
@ -306,7 +311,7 @@ RETURN = '''
- 'Example: { "name": "wrench", "mass": "1.3kg", "count": "3" }.' - 'Example: { "name": "wrench", "mass": "1.3kg", "count": "3" }.'
returned: success returned: success
type: dict type: dict
local_ssd_count: localSsdCount:
description: description:
- The number of local SSD disks to be attached to the node. - The number of local SSD disks to be attached to the node.
- 'The limit for this value is dependant upon the maximum number of disks available - 'The limit for this value is dependant upon the maximum number of disks available
@ -327,7 +332,7 @@ RETURN = '''
for more inforamtion about preemptible VM instances.' for more inforamtion about preemptible VM instances.'
returned: success returned: success
type: bool type: bool
initial_node_count: initialNodeCount:
description: description:
- The initial node count for the pool. You must ensure that your Compute Engine resource - The initial node count for the pool. You must ensure that your Compute Engine resource
quota is sufficient for this number of instances. You must also have available firewall quota is sufficient for this number of instances. You must also have available firewall
@ -351,12 +356,12 @@ RETURN = '''
- Is autoscaling enabled for this node pool. - Is autoscaling enabled for this node pool.
returned: success returned: success
type: bool type: bool
min_node_count: minNodeCount:
description: description:
- Minimum number of nodes in the NodePool. Must be >= 1 and <= maxNodeCount. - Minimum number of nodes in the NodePool. Must be >= 1 and <= maxNodeCount.
returned: success returned: success
type: int type: int
max_node_count: maxNodeCount:
description: description:
- Maximum number of nodes in the NodePool. Must be >= minNodeCount. - Maximum number of nodes in the NodePool. Must be >= minNodeCount.
- There has to enough quota to scale up the cluster. - There has to enough quota to scale up the cluster.
@ -368,27 +373,27 @@ RETURN = '''
returned: success returned: success
type: complex type: complex
contains: contains:
auto_upgrade: autoUpgrade:
description: description:
- A flag that specifies whether node auto-upgrade is enabled for the node pool. If - A flag that specifies whether node auto-upgrade is enabled for the node pool. If
enabled, node auto-upgrade helps keep the nodes in your node pool up to date with enabled, node auto-upgrade helps keep the nodes in your node pool up to date with
the latest release version of Kubernetes. the latest release version of Kubernetes.
returned: success returned: success
type: bool type: bool
auto_repair: autoRepair:
description: description:
- A flag that specifies whether the node auto-repair is enabled for the node pool. - A flag that specifies whether the node auto-repair is enabled for the node pool.
If enabled, the nodes in this node pool will be monitored and, if they fail health If enabled, the nodes in this node pool will be monitored and, if they fail health
checks too many times, an automatic repair action will be triggered. checks too many times, an automatic repair action will be triggered.
returned: success returned: success
type: bool type: bool
upgrade_options: upgradeOptions:
description: description:
- Specifies the Auto Upgrade knobs for the node pool. - Specifies the Auto Upgrade knobs for the node pool.
returned: success returned: success
type: complex type: complex
contains: contains:
auto_upgrade_start_time: autoUpgradeStartTime:
description: description:
- This field is set when upgrades are about to commence with the approximate start - This field is set when upgrades are about to commence with the approximate start
time for the upgrades, in RFC3339 text format. time for the upgrades, in RFC3339 text format.
@ -474,7 +479,8 @@ def main():
if fetch: if fetch:
if state == 'present': if state == 'present':
if is_different(module, fetch): if is_different(module, fetch):
fetch = update(module, self_link(module)) update(module, self_link(module))
fetch = fetch_resource(module, self_link(module))
changed = True changed = True
else: else:
delete(module, self_link(module)) delete(module, self_link(module))
@ -524,9 +530,9 @@ def resource_to_request(module):
return return_vals return return_vals
def fetch_resource(module, link): def fetch_resource(module, link, allow_not_found=True):
auth = GcpSession(module, 'container') auth = GcpSession(module, 'container')
return return_if_object(module, auth.get(link)) return return_if_object(module, auth.get(link), allow_not_found)
def self_link(module): def self_link(module):
@ -548,9 +554,9 @@ def collection(module):
return "https://container.googleapis.com/v1/projects/{project}/zones/{zone}/clusters/{cluster}/nodePools".format(**res) return "https://container.googleapis.com/v1/projects/{project}/zones/{zone}/clusters/{cluster}/nodePools".format(**res)
def return_if_object(module, response): def return_if_object(module, response, allow_not_found=False):
# If not found, return nothing. # If not found, return nothing.
if response.status_code == 404: if allow_not_found and response.status_code == 404:
return None return None
# If no content, return nothing. # If no content, return nothing.

@ -77,7 +77,7 @@ EXAMPLES = '''
dns_name: test.somewild2.example.com. dns_name: test.somewild2.example.com.
description: test zone description: test zone
project: "test_project" project: "test_project"
auth_kind: "service_account" auth_kind: "serviceaccount"
service_account_file: "/tmp/auth.pem" service_account_file: "/tmp/auth.pem"
state: present state: present
''' '''
@ -89,7 +89,7 @@ RETURN = '''
user's convenience. Has no effect on the managed zone's function. user's convenience. Has no effect on the managed zone's function.
returned: success returned: success
type: str type: str
dns_name: dnsName:
description: description:
- The DNS name of this managed zone, for instance "example.com.". - The DNS name of this managed zone, for instance "example.com.".
returned: success returned: success
@ -105,20 +105,20 @@ RETURN = '''
- Must be unique within the project. - Must be unique within the project.
returned: success returned: success
type: str type: str
name_servers: nameServers:
description: description:
- Delegate your managed_zone to these virtual name servers; defined by the server - Delegate your managed_zone to these virtual name servers; defined by the server
. .
returned: success returned: success
type: list type: list
name_server_set: nameServerSet:
description: description:
- Optionally specifies the NameServerSet for this ManagedZone. A NameServerSet is - Optionally specifies the NameServerSet for this ManagedZone. A NameServerSet is
a set of DNS name servers that all host the same ManagedZones. Most users will leave a set of DNS name servers that all host the same ManagedZones. Most users will leave
this field unset. this field unset.
returned: success returned: success
type: list type: list
creation_time: creationTime:
description: description:
- The time that this resource was created on the server. - The time that this resource was created on the server.
- This is in RFC3339 text format. - This is in RFC3339 text format.
@ -163,7 +163,8 @@ def main():
if fetch: if fetch:
if state == 'present': if state == 'present':
if is_different(module, fetch): if is_different(module, fetch):
fetch = update(module, self_link(module), kind) update(module, self_link(module), kind)
fetch = fetch_resource(module, self_link(module), kind)
changed = True changed = True
else: else:
delete(module, self_link(module), kind) delete(module, self_link(module), kind)
@ -211,9 +212,9 @@ def resource_to_request(module):
return return_vals return return_vals
def fetch_resource(module, link, kind): def fetch_resource(module, link, kind, allow_not_found=True):
auth = GcpSession(module, 'dns') auth = GcpSession(module, 'dns')
return return_if_object(module, auth.get(link), kind) return return_if_object(module, auth.get(link), kind, allow_not_found)
def self_link(module): def self_link(module):
@ -224,9 +225,9 @@ def collection(module):
return "https://www.googleapis.com/dns/v1/projects/{project}/managedZones".format(**module.params) return "https://www.googleapis.com/dns/v1/projects/{project}/managedZones".format(**module.params)
def return_if_object(module, response, kind): def return_if_object(module, response, kind, allow_not_found=False):
# If not found, return nothing. # If not found, return nothing.
if response.status_code == 404: if allow_not_found and response.status_code == 404:
return None return None
# If no content, return nothing. # If no content, return nothing.
@ -241,8 +242,6 @@ def return_if_object(module, response, kind):
if navigate_hash(result, ['error', 'errors']): if navigate_hash(result, ['error', 'errors']):
module.fail_json(msg=navigate_hash(result, ['error', 'errors'])) module.fail_json(msg=navigate_hash(result, ['error', 'errors']))
if result['kind'] != kind:
module.fail_json(msg="Incorrect result: {kind}".format(**result))
return result return result

@ -71,6 +71,11 @@ options:
description: description:
- Identifies the managed zone addressed by this request. - Identifies the managed zone addressed by this request.
- Can be the managed zone name or id. - Can be the managed zone name or id.
- 'This field represents a link to a ManagedZone resource in GCP. It can be specified
in two ways. You can add `register: name-of-resource` to a gcp_dns_managed_zone
task and then set this managed_zone field to "{{ name-of-resource }}" Alternatively,
you can set this managed_zone to a dictionary with the name key where the value
is the name of your ManagedZone.'
required: true required: true
extends_documentation_fragment: gcp extends_documentation_fragment: gcp
''' '''
@ -97,7 +102,7 @@ EXAMPLES = '''
- 10.1.2.3 - 10.1.2.3
- 40.5.6.7 - 40.5.6.7
project: "test_project" project: "test_project"
auth_kind: "service_account" auth_kind: "serviceaccount"
service_account_file: "/tmp/auth.pem" service_account_file: "/tmp/auth.pem"
state: present state: present
''' '''
@ -174,7 +179,8 @@ def main():
if fetch: if fetch:
if state == 'present': if state == 'present':
if is_different(module, fetch): if is_different(module, fetch):
fetch = update(module, self_link(module), kind, fetch) update(module, self_link(module), kind, fetch)
fetch = fetch_resource(module, self_link(module), kind)
changed = True changed = True
else: else:
delete(module, self_link(module), kind, fetch) delete(module, self_link(module), kind, fetch)
@ -238,9 +244,9 @@ def resource_to_request(module):
return return_vals return return_vals
def fetch_resource(module, link, kind): def fetch_resource(module, link, kind, allow_not_found=True):
auth = GcpSession(module, 'dns') auth = GcpSession(module, 'dns')
return return_if_object(module, auth.get(link), kind) return return_if_object(module, auth.get(link), kind, allow_not_found)
def fetch_wrapped_resource(module, kind, wrap_kind, wrap_path): def fetch_wrapped_resource(module, kind, wrap_kind, wrap_path):
@ -269,17 +275,17 @@ def self_link(module):
return "https://www.googleapis.com/dns/v1/projects/{project}/managedZones/{managed_zone}/rrsets?name={name}&type={type}".format(**res) return "https://www.googleapis.com/dns/v1/projects/{project}/managedZones/{managed_zone}/rrsets?name={name}&type={type}".format(**res)
def collection(module, extra_url=''): def collection(module):
res = { res = {
'project': module.params['project'], 'project': module.params['project'],
'managed_zone': replace_resource_dict(module.params['managed_zone'], 'name') 'managed_zone': replace_resource_dict(module.params['managed_zone'], 'name')
} }
return "https://www.googleapis.com/dns/v1/projects/{project}/managedZones/{managed_zone}/changes".format(**res) + extra_url return "https://www.googleapis.com/dns/v1/projects/{project}/managedZones/{managed_zone}/changes".format(**res)
def return_if_object(module, response, kind): def return_if_object(module, response, kind, allow_not_found=False):
# If not found, return nothing. # If not found, return nothing.
if response.status_code == 404: if allow_not_found and response.status_code == 404:
return None return None
# If no content, return nothing. # If no content, return nothing.
@ -294,8 +300,6 @@ def return_if_object(module, response, kind):
if navigate_hash(result, ['error', 'errors']): if navigate_hash(result, ['error', 'errors']):
module.fail_json(msg=navigate_hash(result, ['error', 'errors'])) module.fail_json(msg=navigate_hash(result, ['error', 'errors']))
if result['kind'] != kind:
module.fail_json(msg="Incorrect result: {kind}".format(**result))
return result return result
@ -436,7 +440,7 @@ def wait_for_change_to_complete(change_id, module):
def get_change_status(change_id, module): def get_change_status(change_id, module):
auth = GcpSession(module, 'dns') auth = GcpSession(module, 'dns')
link = collection(module, "/%s" % change_id) link = collection(module) + "/%s" % change_id
return return_if_change_object(module, auth.get(link))['status'] return return_if_change_object(module, auth.get(link))['status']

@ -54,6 +54,11 @@ options:
topic: topic:
description: description:
- A reference to a Topic resource. - A reference to a Topic resource.
- 'This field represents a link to a Topic resource in GCP. It can be specified in
two ways. You can add `register: name-of-resource` to a gcp_pubsub_topic task and
then set this topic field to "{{ name-of-resource }}" Alternatively, you can set
this topic to a dictionary with the name key where the value is the name of your
Topic.'
required: false required: false
push_config: push_config:
description: description:
@ -105,7 +110,7 @@ EXAMPLES = '''
push_endpoint: https://myapp.graphite.cloudnativeapp.com/webhook/sub1 push_endpoint: https://myapp.graphite.cloudnativeapp.com/webhook/sub1
ack_deadline_seconds: 300 ack_deadline_seconds: 300
project: "test_project" project: "test_project"
auth_kind: "service_account" auth_kind: "serviceaccount"
service_account_file: "/tmp/auth.pem" service_account_file: "/tmp/auth.pem"
state: present state: present
''' '''
@ -121,7 +126,7 @@ RETURN = '''
- A reference to a Topic resource. - A reference to a Topic resource.
returned: success returned: success
type: dict type: dict
push_config: pushConfig:
description: description:
- If push delivery is used with this subscription, this field is used to configure - If push delivery is used with this subscription, this field is used to configure
it. An empty pushConfig signifies that the subscriber will pull and ack messages it. An empty pushConfig signifies that the subscriber will pull and ack messages
@ -129,13 +134,13 @@ RETURN = '''
returned: success returned: success
type: complex type: complex
contains: contains:
push_endpoint: pushEndpoint:
description: description:
- A URL locating the endpoint to which messages should be pushed. - A URL locating the endpoint to which messages should be pushed.
- For example, a Webhook endpoint might use "U(https://example.com/push".) - For example, a Webhook endpoint might use "U(https://example.com/push".)
returned: success returned: success
type: str type: str
ack_deadline_seconds: ackDeadlineSeconds:
description: description:
- This value is the maximum time after a subscriber receives a message before the - This value is the maximum time after a subscriber receives a message before the
subscriber should acknowledge the message. After message delivery but before the subscriber should acknowledge the message. After message delivery but before the
@ -193,7 +198,8 @@ def main():
if fetch: if fetch:
if state == 'present': if state == 'present':
if is_different(module, fetch): if is_different(module, fetch):
fetch = update(module, self_link(module)) update(module, self_link(module))
fetch = fetch_resource(module, self_link(module))
changed = True changed = True
else: else:
delete(module, self_link(module)) delete(module, self_link(module))
@ -241,9 +247,9 @@ def resource_to_request(module):
return return_vals return return_vals
def fetch_resource(module, link): def fetch_resource(module, link, allow_not_found=True):
auth = GcpSession(module, 'pubsub') auth = GcpSession(module, 'pubsub')
return return_if_object(module, auth.get(link)) return return_if_object(module, auth.get(link), allow_not_found)
def self_link(module): def self_link(module):
@ -254,9 +260,9 @@ def collection(module):
return "https://pubsub.googleapis.com/v1/projects/{project}/subscriptions".format(**module.params) return "https://pubsub.googleapis.com/v1/projects/{project}/subscriptions".format(**module.params)
def return_if_object(module, response): def return_if_object(module, response, allow_not_found=False):
# If not found, return nothing. # If not found, return nothing.
if response.status_code == 404: if allow_not_found and response.status_code == 404:
return None return None
# If no content, return nothing. # If no content, return nothing.
@ -319,7 +325,7 @@ def decode_request(response, module):
def encode_request(request, module): def encode_request(request, module):
request['topic'] = '/'.join(['projects', module.params['project'], request['topic'] = '/'.join(['projects', module.params['project'],
'topics', module.params['topic']]) 'topics', module.params['topic']['name']])
request['name'] = '/'.join(['projects', module.params['project'], request['name'] = '/'.join(['projects', module.params['project'],
'subscriptions', module.params['name']]) 'subscriptions', module.params['name']])

@ -58,7 +58,7 @@ EXAMPLES = '''
gcp_pubsub_topic: gcp_pubsub_topic:
name: test-topic1 name: test-topic1
project: "test_project" project: "test_project"
auth_kind: "service_account" auth_kind: "serviceaccount"
service_account_file: "/tmp/auth.pem" service_account_file: "/tmp/auth.pem"
state: present state: present
''' '''
@ -104,7 +104,8 @@ def main():
if fetch: if fetch:
if state == 'present': if state == 'present':
if is_different(module, fetch): if is_different(module, fetch):
fetch = update(module, self_link(module)) update(module, self_link(module))
fetch = fetch_resource(module, self_link(module))
changed = True changed = True
else: else:
delete(module, self_link(module)) delete(module, self_link(module))
@ -150,9 +151,9 @@ def resource_to_request(module):
return return_vals return return_vals
def fetch_resource(module, link): def fetch_resource(module, link, allow_not_found=True):
auth = GcpSession(module, 'pubsub') auth = GcpSession(module, 'pubsub')
return return_if_object(module, auth.get(link)) return return_if_object(module, auth.get(link), allow_not_found)
def self_link(module): def self_link(module):
@ -163,9 +164,9 @@ def collection(module):
return "https://pubsub.googleapis.com/v1/projects/{project}/topics".format(**module.params) return "https://pubsub.googleapis.com/v1/projects/{project}/topics".format(**module.params)
def return_if_object(module, response): def return_if_object(module, response, allow_not_found=False):
# If not found, return nothing. # If not found, return nothing.
if response.status_code == 404: if allow_not_found and response.status_code == 404:
return None return None
# If no content, return nothing. # If no content, return nothing.

@ -61,6 +61,11 @@ options:
instance: instance:
description: description:
- The instance to create the database on. - The instance to create the database on.
- 'This field represents a link to a Instance resource in GCP. It can be specified
in two ways. You can add `register: name-of-resource` to a gcp_spanner_instance
task and then set this instance field to "{{ name-of-resource }}" Alternatively,
you can set this instance to a dictionary with the name key where the value is the
name of your Instance.'
required: true required: true
extends_documentation_fragment: gcp extends_documentation_fragment: gcp
''' '''
@ -85,7 +90,7 @@ EXAMPLES = '''
name: webstore name: webstore
instance: "{{ instance }}" instance: "{{ instance }}"
project: "test_project" project: "test_project"
auth_kind: "service_account" auth_kind: "serviceaccount"
service_account_file: "/tmp/auth.pem" service_account_file: "/tmp/auth.pem"
state: present state: present
''' '''
@ -98,7 +103,7 @@ RETURN = '''
The final segment of the name must be between 6 and 30 characters in length. The final segment of the name must be between 6 and 30 characters in length.
returned: success returned: success
type: str type: str
extra_statements: extraStatements:
description: description:
- 'An optional list of DDL statements to run inside the newly created database. Statements - 'An optional list of DDL statements to run inside the newly created database. Statements
can create tables, indexes, etc. These statements execute atomically with the creation can create tables, indexes, etc. These statements execute atomically with the creation
@ -147,7 +152,8 @@ def main():
if fetch: if fetch:
if state == 'present': if state == 'present':
if is_different(module, fetch): if is_different(module, fetch):
fetch = update(module, self_link(module)) update(module, self_link(module))
fetch = fetch_resource(module, self_link(module))
changed = True changed = True
else: else:
delete(module, self_link(module)) delete(module, self_link(module))
@ -194,9 +200,9 @@ def resource_to_request(module):
return return_vals return return_vals
def fetch_resource(module, link): def fetch_resource(module, link, allow_not_found=True):
auth = GcpSession(module, 'spanner') auth = GcpSession(module, 'spanner')
return return_if_object(module, auth.get(link)) return return_if_object(module, auth.get(link), allow_not_found)
def self_link(module): def self_link(module):
@ -216,9 +222,9 @@ def collection(module):
return "https://spanner.googleapis.com/v1/projects/{project}/instances/{instance}/databases".format(**res) return "https://spanner.googleapis.com/v1/projects/{project}/instances/{instance}/databases".format(**res)
def return_if_object(module, response): def return_if_object(module, response, allow_not_found=False):
# If not found, return nothing. # If not found, return nothing.
if response.status_code == 404: if allow_not_found and response.status_code == 404:
return None return None
# If no content, return nothing. # If no content, return nothing.

@ -99,7 +99,7 @@ EXAMPLES = '''
cost_center: ti-1700004 cost_center: ti-1700004
config: regional-us-central1 config: regional-us-central1
project: "test_project" project: "test_project"
auth_kind: "service_account" auth_kind: "serviceaccount"
service_account_file: "/tmp/auth.pem" service_account_file: "/tmp/auth.pem"
state: present state: present
''' '''
@ -117,13 +117,13 @@ RETURN = '''
- A reference to the instance configuration. - A reference to the instance configuration.
returned: success returned: success
type: str type: str
display_name: displayName:
description: description:
- The descriptive name for this instance as it appears in UIs. Must be unique per - The descriptive name for this instance as it appears in UIs. Must be unique per
project and between 4 and 30 characters in length. project and between 4 and 30 characters in length.
returned: success returned: success
type: str type: str
node_count: nodeCount:
description: description:
- The number of nodes allocated to this instance. - The number of nodes allocated to this instance.
returned: success returned: success
@ -189,7 +189,8 @@ def main():
if fetch: if fetch:
if state == 'present': if state == 'present':
if is_different(module, fetch): if is_different(module, fetch):
fetch = update(module, self_link(module)) update(module, self_link(module))
fetch = fetch_resource(module, self_link(module))
changed = True changed = True
else: else:
delete(module, self_link(module)) delete(module, self_link(module))
@ -238,9 +239,9 @@ def resource_to_request(module):
return return_vals return return_vals
def fetch_resource(module, link): def fetch_resource(module, link, allow_not_found=True):
auth = GcpSession(module, 'spanner') auth = GcpSession(module, 'spanner')
return return_if_object(module, auth.get(link)) return return_if_object(module, auth.get(link), allow_not_found)
def self_link(module): def self_link(module):
@ -251,9 +252,9 @@ def collection(module):
return "https://spanner.googleapis.com/v1/projects/{project}/instances".format(**module.params) return "https://spanner.googleapis.com/v1/projects/{project}/instances".format(**module.params)
def return_if_object(module, response): def return_if_object(module, response, allow_not_found=False):
# If not found, return nothing. # If not found, return nothing.
if response.status_code == 404: if allow_not_found and response.status_code == 404:
return None return None
# If no content, return nothing. # If no content, return nothing.

@ -62,6 +62,11 @@ options:
instance: instance:
description: description:
- The name of the Cloud SQL instance. This does not include the project ID. - The name of the Cloud SQL instance. This does not include the project ID.
- 'This field represents a link to a Instance resource in GCP. It can be specified
in two ways. You can add `register: name-of-resource` to a gcp_sql_instance task
and then set this instance field to "{{ name-of-resource }}" Alternatively, you
can set this instance to a dictionary with the name key where the value is the name
of your Instance.'
required: true required: true
extends_documentation_fragment: gcp extends_documentation_fragment: gcp
''' '''
@ -89,7 +94,7 @@ EXAMPLES = '''
charset: utf8 charset: utf8
instance: "{{ instance }}" instance: "{{ instance }}"
project: "test_project" project: "test_project"
auth_kind: "service_account" auth_kind: "serviceaccount"
service_account_file: "/tmp/auth.pem" service_account_file: "/tmp/auth.pem"
state: present state: present
''' '''
@ -156,7 +161,8 @@ def main():
if fetch: if fetch:
if state == 'present': if state == 'present':
if is_different(module, fetch): if is_different(module, fetch):
fetch = update(module, self_link(module), kind) update(module, self_link(module), kind)
fetch = fetch_resource(module, self_link(module), kind)
changed = True changed = True
else: else:
delete(module, self_link(module), kind) delete(module, self_link(module), kind)
@ -204,9 +210,9 @@ def resource_to_request(module):
return return_vals return return_vals
def fetch_resource(module, link, kind): def fetch_resource(module, link, kind, allow_not_found=True):
auth = GcpSession(module, 'sql') auth = GcpSession(module, 'sql')
return return_if_object(module, auth.get(link), kind) return return_if_object(module, auth.get(link), kind, allow_not_found)
def self_link(module): def self_link(module):
@ -226,7 +232,7 @@ def collection(module):
return "https://www.googleapis.com/sql/v1beta4/projects/{project}/instances/{instance}/databases".format(**res) return "https://www.googleapis.com/sql/v1beta4/projects/{project}/instances/{instance}/databases".format(**res)
def return_if_object(module, response, kind): def return_if_object(module, response, kind, allow_not_found=False):
# If not found, return nothing. # If not found, return nothing.
if response.status_code == 404: if response.status_code == 404:
return None return None

@ -246,6 +246,12 @@ options:
instances, this field determines whether the instance is Second Generation (recommended) instances, this field determines whether the instance is Second Generation (recommended)
or First Generation. or First Generation.
required: false required: false
settings_version:
description:
- The version of instance settings. This is a required field for update method to
make sure concurrent updates are handled properly. During update, use the most
recent settingsVersion value for this instance and do not try to update this value.
required: false
extends_documentation_fragment: gcp extends_documentation_fragment: gcp
''' '''
@ -261,25 +267,25 @@ EXAMPLES = '''
tier: db-n1-standard-1 tier: db-n1-standard-1
region: us-central1 region: us-central1
project: "test_project" project: "test_project"
auth_kind: "service_account" auth_kind: "serviceaccount"
service_account_file: "/tmp/auth.pem" service_account_file: "/tmp/auth.pem"
state: present state: present
''' '''
RETURN = ''' RETURN = '''
backend_type: backendType:
description: description:
- "* FIRST_GEN: First Generation instance. MySQL only." - "* FIRST_GEN: First Generation instance. MySQL only."
- "* SECOND_GEN: Second Generation instance or PostgreSQL instance." - "* SECOND_GEN: Second Generation instance or PostgreSQL instance."
- "* EXTERNAL: A database server that is not managed by Google." - "* EXTERNAL: A database server that is not managed by Google."
returned: success returned: success
type: str type: str
connection_name: connectionName:
description: description:
- Connection name of the Cloud SQL instance used in connection strings. - Connection name of the Cloud SQL instance used in connection strings.
returned: success returned: success
type: str type: str
database_version: databaseVersion:
description: description:
- The database engine type and version. For First Generation instances, can be MYSQL_5_5, - The database engine type and version. For First Generation instances, can be MYSQL_5_5,
or MYSQL_5_6. For Second Generation instances, can be MYSQL_5_6 or MYSQL_5_7. Defaults or MYSQL_5_6. For Second Generation instances, can be MYSQL_5_6 or MYSQL_5_7. Defaults
@ -288,7 +294,7 @@ RETURN = '''
after instance creation.' after instance creation.'
returned: success returned: success
type: str type: str
failover_replica: failoverReplica:
description: description:
- The name and status of the failover replica. This property is applicable only to - The name and status of the failover replica. This property is applicable only to
Second Generation instances. Second Generation instances.
@ -309,7 +315,7 @@ RETURN = '''
property is applicable only to Second Generation instances. property is applicable only to Second Generation instances.
returned: success returned: success
type: str type: str
instance_type: instanceType:
description: description:
- The instance type. This can be one of the following. - The instance type. This can be one of the following.
- "* CLOUD_SQL_INSTANCE: A Cloud SQL instance that is not replicating from a master." - "* CLOUD_SQL_INSTANCE: A Cloud SQL instance that is not replicating from a master."
@ -317,18 +323,18 @@ RETURN = '''
- "* READ_REPLICA_INSTANCE: A Cloud SQL instance configured as a read-replica." - "* READ_REPLICA_INSTANCE: A Cloud SQL instance configured as a read-replica."
returned: success returned: success
type: str type: str
ip_addresses: ipAddresses:
description: description:
- The assigned IP addresses for the instance. - The assigned IP addresses for the instance.
returned: success returned: success
type: complex type: complex
contains: contains:
ip_address: ipAddress:
description: description:
- The IP address assigned. - The IP address assigned.
returned: success returned: success
type: str type: str
time_to_retire: timeToRetire:
description: description:
- The due time for this IP to be retired in RFC 3339 format, for example 2012-11-15T16:19:00.094Z. - The due time for this IP to be retired in RFC 3339 format, for example 2012-11-15T16:19:00.094Z.
This field is only available when the IP is scheduled to be retired. This field is only available when the IP is scheduled to be retired.
@ -341,18 +347,18 @@ RETURN = '''
from the instance, if supported. from the instance, if supported.
returned: success returned: success
type: str type: str
ipv6_address: ipv6Address:
description: description:
- The IPv6 address assigned to the instance. This property is applicable only to First - The IPv6 address assigned to the instance. This property is applicable only to First
Generation instances. Generation instances.
returned: success returned: success
type: str type: str
master_instance_name: masterInstanceName:
description: description:
- The name of the instance which will act as master in the replication setup. - The name of the instance which will act as master in the replication setup.
returned: success returned: success
type: str type: str
max_disk_size: maxDiskSize:
description: description:
- The maximum disk size of the instance in bytes. - The maximum disk size of the instance in bytes.
returned: success returned: success
@ -368,13 +374,13 @@ RETURN = '''
instance type (First Generation or Second Generation/PostgreSQL). instance type (First Generation or Second Generation/PostgreSQL).
returned: success returned: success
type: str type: str
replica_configuration: replicaConfiguration:
description: description:
- Configuration specific to failover replicas and read replicas. - Configuration specific to failover replicas and read replicas.
returned: success returned: success
type: complex type: complex
contains: contains:
failover_target: failoverTarget:
description: description:
- Specifies if the replica is the failover target. If the field is set to true the - Specifies if the replica is the failover target. If the field is set to true the
replica will be designated as a failover replica. replica will be designated as a failover replica.
@ -384,7 +390,7 @@ RETURN = '''
in different zone with the master instance. in different zone with the master instance.
returned: success returned: success
type: bool type: bool
mysql_replica_configuration: mysqlReplicaConfiguration:
description: description:
- MySQL specific configuration when replicating from a MySQL on-premises master. Replication - MySQL specific configuration when replicating from a MySQL on-premises master. Replication
configuration information such as the username, password, certificates, and keys configuration information such as the username, password, certificates, and keys
@ -394,28 +400,28 @@ RETURN = '''
returned: success returned: success
type: complex type: complex
contains: contains:
ca_certificate: caCertificate:
description: description:
- PEM representation of the trusted CA's x509 certificate. - PEM representation of the trusted CA's x509 certificate.
returned: success returned: success
type: str type: str
client_certificate: clientCertificate:
description: description:
- PEM representation of the slave's x509 certificate . - PEM representation of the slave's x509 certificate .
returned: success returned: success
type: str type: str
client_key: clientKey:
description: description:
- PEM representation of the slave's private key. The corresponsing public key is encoded - PEM representation of the slave's private key. The corresponsing public key is encoded
in the client's asf asd certificate. in the client's asf asd certificate.
returned: success returned: success
type: str type: str
connect_retry_interval: connectRetryInterval:
description: description:
- Seconds to wait between connect retries. MySQL's default is 60 seconds. - Seconds to wait between connect retries. MySQL's default is 60 seconds.
returned: success returned: success
type: int type: int
dump_file_path: dumpFilePath:
description: description:
- Path to a SQL dump file in Google Cloud Storage from which the slave instance is - Path to a SQL dump file in Google Cloud Storage from which the slave instance is
to be created. The URI is in the form gs://bucketName/fileName. Compressed gzip to be created. The URI is in the form gs://bucketName/fileName. Compressed gzip
@ -424,7 +430,7 @@ RETURN = '''
when using mysqldump. when using mysqldump.
returned: success returned: success
type: str type: str
master_heartbeat_period: masterHeartbeatPeriod:
description: description:
- Interval in milliseconds between replication heartbeats. - Interval in milliseconds between replication heartbeats.
returned: success returned: success
@ -434,7 +440,7 @@ RETURN = '''
- The password for the replication connection. - The password for the replication connection.
returned: success returned: success
type: str type: str
ssl_cipher: sslCipher:
description: description:
- A list of permissible ciphers to use for SSL encryption. - A list of permissible ciphers to use for SSL encryption.
returned: success returned: success
@ -444,18 +450,18 @@ RETURN = '''
- The username for the replication connection. - The username for the replication connection.
returned: success returned: success
type: str type: str
verify_server_certificate: verifyServerCertificate:
description: description:
- Whether or not to check the master's Common Name value in the certificate that it - Whether or not to check the master's Common Name value in the certificate that it
sends during the SSL handshake. sends during the SSL handshake.
returned: success returned: success
type: bool type: bool
replica_names: replicaNames:
description: description:
- The replicas of the instance. - The replicas of the instance.
returned: success returned: success
type: list type: list
service_account_email_address: serviceAccountEmailAddress:
description: description:
- The service account email address assigned to the instance. This property is applicable - The service account email address assigned to the instance. This property is applicable
only to Second Generation instances. only to Second Generation instances.
@ -467,7 +473,7 @@ RETURN = '''
returned: success returned: success
type: complex type: complex
contains: contains:
ip_configuration: ipConfiguration:
description: description:
- The settings for IP Management. This allows to enable or disable the instance IP - 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 and manage which external networks can connect to the instance. The IPv4 address
@ -475,19 +481,19 @@ RETURN = '''
returned: success returned: success
type: complex type: complex
contains: contains:
ipv4_enabled: ipv4Enabled:
description: description:
- Whether the instance should be assigned an IP address or not. - Whether the instance should be assigned an IP address or not.
returned: success returned: success
type: bool type: bool
authorized_networks: authorizedNetworks:
description: description:
- The list of external networks that are allowed to connect to the instance using - The list of external networks that are allowed to connect to the instance using
the IP. In CIDR notation, also known as 'slash' notation (e.g. 192.168.100.0/24). the IP. In CIDR notation, also known as 'slash' notation (e.g. 192.168.100.0/24).
returned: success returned: success
type: complex type: complex
contains: contains:
expiration_time: expirationTime:
description: description:
- The time when this access control entry expires in RFC 3339 format, for example - The time when this access control entry expires in RFC 3339 format, for example
2012-11-15T16:19:00.094Z. 2012-11-15T16:19:00.094Z.
@ -505,7 +511,7 @@ RETURN = '''
or subnet here. or subnet here.
returned: success returned: success
type: str type: str
require_ssl: requireSsl:
description: description:
- Whether the mysqld should default to 'REQUIRE X509' for users connecting over IP. - Whether the mysqld should default to 'REQUIRE X509' for users connecting over IP.
returned: success returned: success
@ -517,6 +523,13 @@ RETURN = '''
or First Generation. or First Generation.
returned: success returned: success
type: str type: str
settingsVersion:
description:
- The version of instance settings. This is a required field for update method to
make sure concurrent updates are handled properly. During update, use the most
recent settingsVersion value for this instance and do not try to update this value.
returned: success
type: int
''' '''
################################################################################ ################################################################################
@ -578,7 +591,8 @@ def main():
)), )),
require_ssl=dict(type='bool') require_ssl=dict(type='bool')
)), )),
tier=dict(type='str') tier=dict(type='str'),
settings_version=dict(type='int')
)) ))
) )
) )
@ -595,7 +609,8 @@ def main():
if fetch: if fetch:
if state == 'present': if state == 'present':
if is_different(module, fetch): if is_different(module, fetch):
fetch = update(module, self_link(module), kind, fetch) update(module, self_link(module), kind, fetch)
fetch = fetch_resource(module, self_link(module), kind)
changed = True changed = True
else: else:
delete(module, self_link(module), kind, fetch) delete(module, self_link(module), kind, fetch)
@ -652,9 +667,9 @@ def resource_to_request(module):
return return_vals return return_vals
def fetch_resource(module, link, kind): def fetch_resource(module, link, kind, allow_not_found=True):
auth = GcpSession(module, 'sql') auth = GcpSession(module, 'sql')
return return_if_object(module, auth.get(link), kind) return return_if_object(module, auth.get(link), kind, allow_not_found)
def self_link(module): def self_link(module):
@ -665,7 +680,7 @@ def collection(module):
return "https://www.googleapis.com/sql/v1beta4/projects/{project}/instances".format(**module.params) return "https://www.googleapis.com/sql/v1beta4/projects/{project}/instances".format(**module.params)
def return_if_object(module, response, kind): def return_if_object(module, response, kind, allow_not_found=False):
# If not found, return nothing. # If not found, return nothing.
if response.status_code == 404: if response.status_code == 404:
return None return None
@ -895,13 +910,15 @@ class InstanceSettings(object):
def to_request(self): def to_request(self):
return remove_nones_from_dict({ return remove_nones_from_dict({
u'ipConfiguration': InstanceIpConfiguration(self.request.get('ip_configuration', {}), self.module).to_request(), u'ipConfiguration': InstanceIpConfiguration(self.request.get('ip_configuration', {}), self.module).to_request(),
u'tier': self.request.get('tier') u'tier': self.request.get('tier'),
u'settingsVersion': self.request.get('settings_version')
}) })
def from_response(self): def from_response(self):
return remove_nones_from_dict({ return remove_nones_from_dict({
u'ipConfiguration': InstanceIpConfiguration(self.request.get(u'ipConfiguration', {}), self.module).from_response(), u'ipConfiguration': InstanceIpConfiguration(self.request.get(u'ipConfiguration', {}), self.module).from_response(),
u'tier': self.request.get(u'tier') u'tier': self.request.get(u'tier'),
u'settingsVersion': self.request.get(u'settingsVersion')
}) })

@ -59,6 +59,11 @@ options:
instance: instance:
description: description:
- The name of the Cloud SQL instance. This does not include the project ID. - The name of the Cloud SQL instance. This does not include the project ID.
- 'This field represents a link to a Instance resource in GCP. It can be specified
in two ways. You can add `register: name-of-resource` to a gcp_sql_instance task
and then set this instance field to "{{ name-of-resource }}" Alternatively, you
can set this instance to a dictionary with the name key where the value is the name
of your Instance.'
required: true required: true
password: password:
description: description:
@ -91,7 +96,7 @@ EXAMPLES = '''
password: secret-password password: secret-password
instance: "{{ instance }}" instance: "{{ instance }}"
project: "test_project" project: "test_project"
auth_kind: "service_account" auth_kind: "serviceaccount"
service_account_file: "/tmp/auth.pem" service_account_file: "/tmp/auth.pem"
state: present state: present
''' '''
@ -161,7 +166,8 @@ def main():
if fetch: if fetch:
if state == 'present': if state == 'present':
if is_different(module, fetch): if is_different(module, fetch):
fetch = update(module, self_link(module), kind) update(module, self_link(module), kind)
fetch = fetch_resource(module, self_link(module), kind)
changed = True changed = True
else: else:
delete(module, self_link(module), kind) delete(module, self_link(module), kind)
@ -231,9 +237,9 @@ def unwrap_resource(result, module):
return None return None
def fetch_resource(module, link, kind): def fetch_resource(module, link, kind, allow_not_found=True):
auth = GcpSession(module, 'sql') auth = GcpSession(module, 'sql')
return return_if_object(module, auth.get(link), kind) return return_if_object(module, auth.get(link), kind, allow_not_found)
def fetch_wrapped_resource(module, kind, wrap_kind, wrap_path): def fetch_wrapped_resource(module, kind, wrap_kind, wrap_path):
@ -270,7 +276,7 @@ def collection(module):
return "https://www.googleapis.com/sql/v1beta4/projects/{project}/instances/{instance}/users".format(**res) return "https://www.googleapis.com/sql/v1beta4/projects/{project}/instances/{instance}/users".format(**res)
def return_if_object(module, response, kind): def return_if_object(module, response, kind, allow_not_found=False):
# If not found, return nothing. # If not found, return nothing.
if response.status_code == 404: if response.status_code == 404:
return None return None

@ -59,6 +59,11 @@ options:
bucket: bucket:
description: description:
- The name of the bucket. - The name of the bucket.
- 'This field represents a link to a Bucket resource in GCP. It can be specified in
two ways. You can add `register: name-of-resource` to a gcp_storage_bucket task
and then set this bucket field to "{{ name-of-resource }}" Alternatively, you can
set this bucket to a dictionary with the name key where the value is the name of
your Bucket.'
required: true required: true
domain: domain:
description: description:
@ -139,6 +144,11 @@ options:
bucket: bucket:
description: description:
- The name of the bucket. - The name of the bucket.
- 'This field represents a link to a Bucket resource in GCP. It can be specified in
two ways. You can add `register: name-of-resource` to a gcp_storage_bucket task
and then set this bucket field to "{{ name-of-resource }}" Alternatively, you can
set this bucket to a dictionary with the name key where the value is the name of
your Bucket.'
required: true required: true
domain: domain:
description: description:
@ -358,7 +368,7 @@ EXAMPLES = '''
gcp_storage_bucket: gcp_storage_bucket:
name: ansible-storage-module name: ansible-storage-module
project: "test_project" project: "test_project"
auth_kind: "service_account" auth_kind: "serviceaccount"
service_account_file: "/tmp/auth.pem" service_account_file: "/tmp/auth.pem"
state: present state: present
''' '''
@ -396,7 +406,7 @@ RETURN = '''
entity would be domain-example.com. entity would be domain-example.com.
returned: success returned: success
type: str type: str
entity_id: entityId:
description: description:
- The ID for the entity. - The ID for the entity.
returned: success returned: success
@ -406,13 +416,13 @@ RETURN = '''
- The ID of the access-control entry. - The ID of the access-control entry.
returned: success returned: success
type: str type: str
project_team: projectTeam:
description: description:
- The project team associated with the entity. - The project team associated with the entity.
returned: success returned: success
type: complex type: complex
contains: contains:
project_number: projectNumber:
description: description:
- The project team associated with the entity. - The project team associated with the entity.
returned: success returned: success
@ -433,7 +443,7 @@ RETURN = '''
returned: success returned: success
type: complex type: complex
contains: contains:
max_age_seconds: maxAgeSeconds:
description: description:
- The value, in seconds, to return in the Access-Control-Max-Age header used in preflight - The value, in seconds, to return in the Access-Control-Max-Age header used in preflight
responses. responses.
@ -451,13 +461,13 @@ RETURN = '''
- 'Note: "*" is permitted in the list of origins, and means "any Origin".' - 'Note: "*" is permitted in the list of origins, and means "any Origin".'
returned: success returned: success
type: list type: list
response_header: responseHeader:
description: description:
- The list of HTTP headers other than the simple response headers to give permission - The list of HTTP headers other than the simple response headers to give permission
for the user-agent to share across domains. for the user-agent to share across domains.
returned: success returned: success
type: list type: list
default_object_acl: defaultObjectAcl:
description: description:
- Default access controls to apply to new objects when no ACL is provided. - Default access controls to apply to new objects when no ACL is provided.
returned: success returned: success
@ -489,7 +499,7 @@ RETURN = '''
entity would be domain-example.com. entity would be domain-example.com.
returned: success returned: success
type: str type: str
entity_id: entityId:
description: description:
- The ID for the entity. - The ID for the entity.
returned: success returned: success
@ -509,13 +519,13 @@ RETURN = '''
- The name of the object, if applied to an object. - The name of the object, if applied to an object.
returned: success returned: success
type: str type: str
project_team: projectTeam:
description: description:
- The project team associated with the entity. - The project team associated with the entity.
returned: success returned: success
type: complex type: complex
contains: contains:
project_number: projectNumber:
description: description:
- The project team associated with the entity. - The project team associated with the entity.
returned: success returned: success
@ -555,7 +565,7 @@ RETURN = '''
returned: success returned: success
type: complex type: complex
contains: contains:
storage_class: storageClass:
description: description:
- Target storage class. Required iff the type of the action is SetStorageClass. - Target storage class. Required iff the type of the action is SetStorageClass.
returned: success returned: success
@ -571,32 +581,32 @@ RETURN = '''
returned: success returned: success
type: complex type: complex
contains: contains:
age_days: ageDays:
description: description:
- Age of an object (in days). This condition is satisfied when an object reaches the - Age of an object (in days). This condition is satisfied when an object reaches the
specified age. specified age.
returned: success returned: success
type: int type: int
created_before: createdBefore:
description: description:
- A date in RFC 3339 format with only the date part (for instance, "2013-01-15"). - 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 This condition is satisfied when an object is created before midnight of the specified
date in UTC. date in UTC.
returned: success returned: success
type: str type: str
is_live: isLive:
description: description:
- Relevant only for versioned objects. If the value is true, this condition matches - Relevant only for versioned objects. If the value is true, this condition matches
live objects; if the value is false, it matches archived objects. live objects; if the value is false, it matches archived objects.
returned: success returned: success
type: bool type: bool
matches_storage_class: matchesStorageClass:
description: description:
- Objects having any of the storage classes specified by this condition will be matched. - Objects having any of the storage classes specified by this condition will be matched.
Values include MULTI_REGIONAL, REGIONAL, NEARLINE, COLDLINE, STANDARD, and DURABLE_REDUCED_AVAILABILITY. Values include MULTI_REGIONAL, REGIONAL, NEARLINE, COLDLINE, STANDARD, and DURABLE_REDUCED_AVAILABILITY.
returned: success returned: success
type: list type: list
num_newer_versions: numNewerVersions:
description: description:
- Relevant only for versioned objects. If the value is N, this condition is satisfied - 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 when there are at least N versions (including the live version) newer than this
@ -617,12 +627,12 @@ RETURN = '''
returned: success returned: success
type: complex type: complex
contains: contains:
log_bucket: logBucket:
description: description:
- The destination bucket where the current bucket's logs should be placed. - The destination bucket where the current bucket's logs should be placed.
returned: success returned: success
type: str type: str
log_object_prefix: logObjectPrefix:
description: description:
- A prefix for log object names. - A prefix for log object names.
returned: success returned: success
@ -648,17 +658,17 @@ RETURN = '''
- The entity, in the form project-owner-projectId. - The entity, in the form project-owner-projectId.
returned: success returned: success
type: str type: str
entity_id: entityId:
description: description:
- The ID for the entity. - The ID for the entity.
returned: success returned: success
type: str type: str
project_number: projectNumber:
description: description:
- The project number of the project the bucket belongs to. - The project number of the project the bucket belongs to.
returned: success returned: success
type: int type: int
storage_class: storageClass:
description: description:
- The bucket's default storage class, used whenever no storageClass is specified for - The bucket's default storage class, used whenever no storageClass is specified for
a newly-created object. This defines how objects in the bucket are stored and determines a newly-created object. This defines how objects in the bucket are stored and determines
@ -668,7 +678,7 @@ RETURN = '''
For more information, see storage classes. For more information, see storage classes.
returned: success returned: success
type: str type: str
time_created: timeCreated:
description: description:
- The creation time of the bucket in RFC 3339 format. - The creation time of the bucket in RFC 3339 format.
returned: success returned: success
@ -696,14 +706,14 @@ RETURN = '''
returned: success returned: success
type: complex type: complex
contains: contains:
main_page_suffix: mainPageSuffix:
description: description:
- If the requested object path is missing, the service will ensure the path has a - If the requested object path is missing, the service will ensure the path has a
trailing '/', append this suffix, and attempt to retrieve the resulting object. trailing '/', append this suffix, and attempt to retrieve the resulting object.
This allows the creation of index.html objects to represent directory pages. This allows the creation of index.html objects to represent directory pages.
returned: success returned: success
type: str type: str
not_found_page: notFoundPage:
description: description:
- If the requested object path is missing, and any mainPageSuffix object is missing, - 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 if applicable, the service will return the named object from this bucket as the
@ -715,7 +725,7 @@ RETURN = '''
- A valid API project identifier. - A valid API project identifier.
returned: success returned: success
type: str type: str
predefined_default_object_acl: predefinedDefaultObjectAcl:
description: description:
- Apply a predefined set of default object access controls to this bucket. - Apply a predefined set of default object access controls to this bucket.
- 'Acceptable values are: - "authenticatedRead": Object owner gets OWNER access, - 'Acceptable values are: - "authenticatedRead": Object owner gets OWNER access,
@ -840,7 +850,8 @@ def main():
if fetch: if fetch:
if state == 'present': if state == 'present':
if is_different(module, fetch): if is_different(module, fetch):
fetch = update(module, self_link(module), kind) update(module, self_link(module), kind)
fetch = fetch_resource(module, self_link(module), kind)
changed = True changed = True
else: else:
delete(module, self_link(module), kind) delete(module, self_link(module), kind)
@ -899,9 +910,9 @@ def resource_to_request(module):
return return_vals return return_vals
def fetch_resource(module, link, kind): def fetch_resource(module, link, kind, allow_not_found=True):
auth = GcpSession(module, 'storage') auth = GcpSession(module, 'storage')
return return_if_object(module, auth.get(link), kind) return return_if_object(module, auth.get(link), kind, allow_not_found)
def self_link(module): def self_link(module):
@ -912,9 +923,9 @@ def collection(module):
return "https://www.googleapis.com/storage/v1/b?project={project}".format(**module.params) return "https://www.googleapis.com/storage/v1/b?project={project}".format(**module.params)
def return_if_object(module, response, kind): def return_if_object(module, response, kind, allow_not_found=False):
# If not found, return nothing. # If not found, return nothing.
if response.status_code == 404: if allow_not_found and response.status_code == 404:
return None return None
# If no content, return nothing. # If no content, return nothing.
@ -929,8 +940,6 @@ def return_if_object(module, response, kind):
if navigate_hash(result, ['error', 'errors']): if navigate_hash(result, ['error', 'errors']):
module.fail_json(msg=navigate_hash(result, ['error', 'errors'])) module.fail_json(msg=navigate_hash(result, ['error', 'errors']))
if result['kind'] != kind:
module.fail_json(msg="Incorrect result: {kind}".format(**result))
return result return result

@ -58,6 +58,11 @@ options:
bucket: bucket:
description: description:
- The name of the bucket. - The name of the bucket.
- 'This field represents a link to a Bucket resource in GCP. It can be specified in
two ways. You can add `register: name-of-resource` to a gcp_storage_bucket task
and then set this bucket field to "{{ name-of-resource }}" Alternatively, you can
set this bucket to a dictionary with the name key where the value is the name of
your Bucket.'
required: true required: true
entity: entity:
description: description:
@ -111,7 +116,7 @@ EXAMPLES = '''
entity: user-alexstephen@google.com entity: user-alexstephen@google.com
role: WRITER role: WRITER
project: "test_project" project: "test_project"
auth_kind: "service_account" auth_kind: "serviceaccount"
service_account_file: "/tmp/auth.pem" service_account_file: "/tmp/auth.pem"
state: present state: present
''' '''
@ -143,7 +148,7 @@ RETURN = '''
entity would be domain-example.com. entity would be domain-example.com.
returned: success returned: success
type: str type: str
entity_id: entityId:
description: description:
- The ID for the entity. - The ID for the entity.
returned: success returned: success
@ -153,13 +158,13 @@ RETURN = '''
- The ID of the access-control entry. - The ID of the access-control entry.
returned: success returned: success
type: str type: str
project_team: projectTeam:
description: description:
- The project team associated with the entity. - The project team associated with the entity.
returned: success returned: success
type: complex type: complex
contains: contains:
project_number: projectNumber:
description: description:
- The project team associated with the entity. - The project team associated with the entity.
returned: success returned: success
@ -217,7 +222,8 @@ def main():
if fetch: if fetch:
if state == 'present': if state == 'present':
if is_different(module, fetch): if is_different(module, fetch):
fetch = update(module, self_link(module), kind) update(module, self_link(module), kind)
fetch = fetch_resource(module, self_link(module), kind)
changed = True changed = True
else: else:
delete(module, self_link(module), kind) delete(module, self_link(module), kind)
@ -267,9 +273,9 @@ def resource_to_request(module):
return return_vals return return_vals
def fetch_resource(module, link, kind): def fetch_resource(module, link, kind, allow_not_found=True):
auth = GcpSession(module, 'storage') auth = GcpSession(module, 'storage')
return return_if_object(module, auth.get(link), kind) return return_if_object(module, auth.get(link), kind, allow_not_found)
def self_link(module): def self_link(module):
@ -280,9 +286,9 @@ def collection(module):
return "https://www.googleapis.com/storage/v1/b/{bucket}/acl".format(**module.params) return "https://www.googleapis.com/storage/v1/b/{bucket}/acl".format(**module.params)
def return_if_object(module, response, kind): def return_if_object(module, response, kind, allow_not_found=False):
# If not found, return nothing. # If not found, return nothing.
if response.status_code == 404: if allow_not_found and response.status_code == 404:
return None return None
# If no content, return nothing. # If no content, return nothing.
@ -297,8 +303,6 @@ def return_if_object(module, response, kind):
if navigate_hash(result, ['error', 'errors']): if navigate_hash(result, ['error', 'errors']):
module.fail_json(msg=navigate_hash(result, ['error', 'errors'])) module.fail_json(msg=navigate_hash(result, ['error', 'errors']))
if result['kind'] != kind:
module.fail_json(msg="Incorrect result: {kind}".format(**result))
return result return result

@ -53,7 +53,7 @@
gcp_container_node_pool_facts: gcp_container_node_pool_facts:
filters: filters:
- name = {{ resource_name }} - name = {{ resource_name }}
cluster: {{ cluster }} cluster: "{{ cluster }}"
zone: us-central1-a zone: us-central1-a
project: "{{ gcp_project }}" project: "{{ gcp_project }}"
auth_kind: "{{ gcp_cred_kind }}" auth_kind: "{{ gcp_cred_kind }}"
@ -101,7 +101,7 @@
gcp_container_node_pool_facts: gcp_container_node_pool_facts:
filters: filters:
- name = {{ resource_name }} - name = {{ resource_name }}
cluster: {{ cluster }} cluster: "{{ cluster }}"
zone: us-central1-a zone: us-central1-a
project: "{{ gcp_project }}" project: "{{ gcp_project }}"
auth_kind: "{{ gcp_cred_kind }}" auth_kind: "{{ gcp_cred_kind }}"

@ -39,13 +39,18 @@
- result.changed == true - result.changed == true
- "result.kind == 'dns#managedZone'" - "result.kind == 'dns#managedZone'"
- name: verify that managed_zone was created - name: verify that managed_zone was created
shell: | gcp_dns_managed_zone_facts:
gcloud dns managed-zones describe --project="{{ gcp_project }}" "{{ resource_name }}" dns_name: test.somewild2.example.com.
project: "{{ gcp_project }}"
auth_kind: "{{ gcp_cred_kind }}"
service_account_file: "{{ gcp_cred_file }}"
scopes:
- https://www.googleapis.com/auth/ndev.clouddns.readwrite
register: results register: results
- name: verify that command succeeded - name: verify that command succeeded
assert: assert:
that: that:
- results.rc == 0 - results['items'] | length == 1
# ---------------------------------------------------------------------------- # ----------------------------------------------------------------------------
- name: create a managed zone that already exists - name: create a managed zone that already exists
gcp_dns_managed_zone: gcp_dns_managed_zone:
@ -79,15 +84,18 @@
- result.changed == true - result.changed == true
- result.has_key('kind') == False - result.has_key('kind') == False
- name: verify that managed_zone was deleted - name: verify that managed_zone was deleted
shell: | gcp_dns_managed_zone_facts:
gcloud dns managed-zones describe --project="{{ gcp_project }}" "{{ resource_name }}" dns_name: test.somewild2.example.com.
project: "{{ gcp_project }}"
auth_kind: "{{ gcp_cred_kind }}"
service_account_file: "{{ gcp_cred_file }}"
scopes:
- https://www.googleapis.com/auth/ndev.clouddns.readwrite
register: results register: results
failed_when: results.rc == 0
- name: verify that command succeeded - name: verify that command succeeded
assert: assert:
that: that:
- results.rc == 1 - results['items'] | length == 0
- "\"{{ resource_name }} was not found.\" in results.stderr"
# ---------------------------------------------------------------------------- # ----------------------------------------------------------------------------
- name: delete a managed zone that does not exist - name: delete a managed zone that does not exist
gcp_dns_managed_zone: gcp_dns_managed_zone:

@ -56,6 +56,19 @@
that: that:
- result.changed == true - result.changed == true
- "result.kind == 'dns#resourceRecordSet'" - "result.kind == 'dns#resourceRecordSet'"
- name: verify that resource_record_set was created
gcp_dns_resource_record_set_facts:
managed_zone: "{{ managed_zone }}"
project: "{{ gcp_project }}"
auth_kind: "{{ gcp_cred_kind }}"
service_account_file: "{{ gcp_cred_file }}"
scopes:
- https://www.googleapis.com/auth/ndev.clouddns.readwrite
register: results
- name: verify that command succeeded
assert:
that:
- results['items'] | length >= 2
# ---------------------------------------------------------------------------- # ----------------------------------------------------------------------------
- name: create a resource record set that already exists - name: create a resource record set that already exists
gcp_dns_resource_record_set: gcp_dns_resource_record_set:
@ -96,6 +109,19 @@
that: that:
- result.changed == true - result.changed == true
- result.has_key('kind') == False - result.has_key('kind') == False
- name: verify that resource_record_set was deleted
gcp_dns_resource_record_set_facts:
managed_zone: "{{ managed_zone }}"
project: "{{ gcp_project }}"
auth_kind: "{{ gcp_cred_kind }}"
service_account_file: "{{ gcp_cred_file }}"
scopes:
- https://www.googleapis.com/auth/ndev.clouddns.readwrite
register: results
- name: verify that command succeeded
assert:
that:
- results['items'] | length >= 2
# ---------------------------------------------------------------------------- # ----------------------------------------------------------------------------
- name: delete a resource record set that does not exist - name: delete a resource record set that does not exist
gcp_dns_resource_record_set: gcp_dns_resource_record_set:

@ -50,13 +50,17 @@
that: that:
- result.changed == true - result.changed == true
- name: verify that subscription was created - name: verify that subscription was created
shell: | gcp_pubsub_subscription_facts:
gcloud beta pubsub subscriptions list --project="{{ gcp_project}}" | grep "{{ resource_name }}" | grep 'test-topic1' project: "{{ gcp_project }}"
auth_kind: "{{ gcp_cred_kind }}"
service_account_file: "{{ gcp_cred_file }}"
scopes:
- https://www.googleapis.com/auth/pubsub
register: results register: results
- name: verify that command succeeded - name: verify that command succeeded
assert: assert:
that: that:
- results.rc == 0 - results['items'] | length == 1
# ---------------------------------------------------------------------------- # ----------------------------------------------------------------------------
- name: create a subscription that already exists - name: create a subscription that already exists
gcp_pubsub_subscription: gcp_pubsub_subscription:
@ -92,15 +96,17 @@
that: that:
- result.changed == true - result.changed == true
- name: verify that subscription was deleted - name: verify that subscription was deleted
shell: | gcp_pubsub_subscription_facts:
gcloud beta pubsub subscriptions list --project="{{ gcp_project}}" | grep "{{ resource_name }}" | grep 'test-topic1' project: "{{ gcp_project }}"
auth_kind: "{{ gcp_cred_kind }}"
service_account_file: "{{ gcp_cred_file }}"
scopes:
- https://www.googleapis.com/auth/pubsub
register: results register: results
failed_when: results.rc == 0
- name: verify that command succeeded - name: verify that command succeeded
assert: assert:
that: that:
- results.rc == 1 - results['items'] | length == 0
- "\"{{ resource_name }} was not found.\" in results.stderr"
# ---------------------------------------------------------------------------- # ----------------------------------------------------------------------------
- name: delete a subscription that does not exist - name: delete a subscription that does not exist
gcp_pubsub_subscription: gcp_pubsub_subscription:

@ -34,13 +34,17 @@
that: that:
- result.changed == true - result.changed == true
- name: verify that topic was created - name: verify that topic was created
shell: | gcp_pubsub_topic_facts:
gcloud beta pubsub topics list --project="{{ gcp_project}}"| grep 'topic: projects/.*/test-topic1' project: "{{ gcp_project }}"
auth_kind: "{{ gcp_cred_kind }}"
service_account_file: "{{ gcp_cred_file }}"
scopes:
- https://www.googleapis.com/auth/pubsub
register: results register: results
- name: verify that command succeeded - name: verify that command succeeded
assert: assert:
that: that:
- results.rc == 0 - results['items'] | length == 1
# ---------------------------------------------------------------------------- # ----------------------------------------------------------------------------
- name: create a topic that already exists - name: create a topic that already exists
gcp_pubsub_topic: gcp_pubsub_topic:
@ -68,15 +72,17 @@
that: that:
- result.changed == true - result.changed == true
- name: verify that topic was deleted - name: verify that topic was deleted
shell: | gcp_pubsub_topic_facts:
gcloud beta pubsub topics list --project="{{ gcp_project}}"| grep 'topic: projects/.*/test-topic1' project: "{{ gcp_project }}"
auth_kind: "{{ gcp_cred_kind }}"
service_account_file: "{{ gcp_cred_file }}"
scopes:
- https://www.googleapis.com/auth/pubsub
register: results register: results
failed_when: results.rc == 0
- name: verify that command succeeded - name: verify that command succeeded
assert: assert:
that: that:
- results.rc == 1 - results['items'] | length == 0
- "\"{{ resource_name }} was not found.\" in results.stderr"
# ---------------------------------------------------------------------------- # ----------------------------------------------------------------------------
- name: delete a topic that does not exist - name: delete a topic that does not exist
gcp_pubsub_topic: gcp_pubsub_topic:

@ -59,7 +59,7 @@
gcp_sql_user_facts: gcp_sql_user_facts:
filters: filters:
- name = test-user - name = test-user
instance: {{ instance }} instance: "{{ instance }}"
project: "{{ gcp_project }}" project: "{{ gcp_project }}"
auth_kind: "{{ gcp_cred_kind }}" auth_kind: "{{ gcp_cred_kind }}"
service_account_file: "{{ gcp_cred_file }}" service_account_file: "{{ gcp_cred_file }}"
@ -108,7 +108,7 @@
gcp_sql_user_facts: gcp_sql_user_facts:
filters: filters:
- name = test-user - name = test-user
instance: {{ instance }} instance: "{{ instance }}"
project: "{{ gcp_project }}" project: "{{ gcp_project }}"
auth_kind: "{{ gcp_cred_kind }}" auth_kind: "{{ gcp_cred_kind }}"
service_account_file: "{{ gcp_cred_file }}" service_account_file: "{{ gcp_cred_file }}"

Loading…
Cancel
Save