summaryrefslogtreecommitdiff
path: root/lib/ansible/modules/cloud/google
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ansible/modules/cloud/google')
-rw-r--r--lib/ansible/modules/cloud/google/_gcdns_record.py775
-rw-r--r--lib/ansible/modules/cloud/google/_gcdns_zone.py371
-rw-r--r--lib/ansible/modules/cloud/google/_gce.py754
-rw-r--r--lib/ansible/modules/cloud/google/_gcp_backend_service.py404
l---------lib/ansible/modules/cloud/google/_gcp_bigquery_dataset_facts.py1
l---------lib/ansible/modules/cloud/google/_gcp_bigquery_table_facts.py1
l---------lib/ansible/modules/cloud/google/_gcp_cloudbuild_trigger_facts.py1
l---------lib/ansible/modules/cloud/google/_gcp_compute_address_facts.py1
l---------lib/ansible/modules/cloud/google/_gcp_compute_backend_bucket_facts.py1
l---------lib/ansible/modules/cloud/google/_gcp_compute_backend_service_facts.py1
l---------lib/ansible/modules/cloud/google/_gcp_compute_disk_facts.py1
l---------lib/ansible/modules/cloud/google/_gcp_compute_firewall_facts.py1
l---------lib/ansible/modules/cloud/google/_gcp_compute_forwarding_rule_facts.py1
l---------lib/ansible/modules/cloud/google/_gcp_compute_global_address_facts.py1
l---------lib/ansible/modules/cloud/google/_gcp_compute_global_forwarding_rule_facts.py1
l---------lib/ansible/modules/cloud/google/_gcp_compute_health_check_facts.py1
l---------lib/ansible/modules/cloud/google/_gcp_compute_http_health_check_facts.py1
l---------lib/ansible/modules/cloud/google/_gcp_compute_https_health_check_facts.py1
l---------lib/ansible/modules/cloud/google/_gcp_compute_image_facts.py1
l---------lib/ansible/modules/cloud/google/_gcp_compute_instance_facts.py1
l---------lib/ansible/modules/cloud/google/_gcp_compute_instance_group_facts.py1
l---------lib/ansible/modules/cloud/google/_gcp_compute_instance_group_manager_facts.py1
l---------lib/ansible/modules/cloud/google/_gcp_compute_instance_template_facts.py1
l---------lib/ansible/modules/cloud/google/_gcp_compute_interconnect_attachment_facts.py1
l---------lib/ansible/modules/cloud/google/_gcp_compute_network_facts.py1
l---------lib/ansible/modules/cloud/google/_gcp_compute_region_disk_facts.py1
l---------lib/ansible/modules/cloud/google/_gcp_compute_route_facts.py1
l---------lib/ansible/modules/cloud/google/_gcp_compute_router_facts.py1
l---------lib/ansible/modules/cloud/google/_gcp_compute_ssl_certificate_facts.py1
l---------lib/ansible/modules/cloud/google/_gcp_compute_ssl_policy_facts.py1
l---------lib/ansible/modules/cloud/google/_gcp_compute_subnetwork_facts.py1
l---------lib/ansible/modules/cloud/google/_gcp_compute_target_http_proxy_facts.py1
l---------lib/ansible/modules/cloud/google/_gcp_compute_target_https_proxy_facts.py1
l---------lib/ansible/modules/cloud/google/_gcp_compute_target_pool_facts.py1
l---------lib/ansible/modules/cloud/google/_gcp_compute_target_ssl_proxy_facts.py1
l---------lib/ansible/modules/cloud/google/_gcp_compute_target_tcp_proxy_facts.py1
l---------lib/ansible/modules/cloud/google/_gcp_compute_target_vpn_gateway_facts.py1
l---------lib/ansible/modules/cloud/google/_gcp_compute_url_map_facts.py1
l---------lib/ansible/modules/cloud/google/_gcp_compute_vpn_tunnel_facts.py1
l---------lib/ansible/modules/cloud/google/_gcp_container_cluster_facts.py1
l---------lib/ansible/modules/cloud/google/_gcp_container_node_pool_facts.py1
l---------lib/ansible/modules/cloud/google/_gcp_dns_managed_zone_facts.py1
l---------lib/ansible/modules/cloud/google/_gcp_dns_resource_record_set_facts.py1
-rw-r--r--lib/ansible/modules/cloud/google/_gcp_forwarding_rule.py355
-rw-r--r--lib/ansible/modules/cloud/google/_gcp_healthcheck.py451
l---------lib/ansible/modules/cloud/google/_gcp_iam_role_facts.py1
l---------lib/ansible/modules/cloud/google/_gcp_iam_service_account_facts.py1
l---------lib/ansible/modules/cloud/google/_gcp_pubsub_subscription_facts.py1
l---------lib/ansible/modules/cloud/google/_gcp_pubsub_topic_facts.py1
l---------lib/ansible/modules/cloud/google/_gcp_redis_instance_facts.py1
l---------lib/ansible/modules/cloud/google/_gcp_resourcemanager_project_facts.py1
l---------lib/ansible/modules/cloud/google/_gcp_sourcerepo_repository_facts.py1
l---------lib/ansible/modules/cloud/google/_gcp_spanner_database_facts.py1
l---------lib/ansible/modules/cloud/google/_gcp_spanner_instance_facts.py1
l---------lib/ansible/modules/cloud/google/_gcp_sql_database_facts.py1
l---------lib/ansible/modules/cloud/google/_gcp_sql_instance_facts.py1
l---------lib/ansible/modules/cloud/google/_gcp_sql_user_facts.py1
-rw-r--r--lib/ansible/modules/cloud/google/_gcp_target_proxy.py296
l---------lib/ansible/modules/cloud/google/_gcp_tpu_node_facts.py1
-rw-r--r--lib/ansible/modules/cloud/google/_gcp_url_map.py510
l---------lib/ansible/modules/cloud/google/_gcpubsub_facts.py1
-rw-r--r--lib/ansible/modules/cloud/google/_gcspanner.py291
-rw-r--r--lib/ansible/modules/cloud/google/gc_storage.py491
-rw-r--r--lib/ansible/modules/cloud/google/gce_eip.py228
-rw-r--r--lib/ansible/modules/cloud/google/gce_img.py209
-rw-r--r--lib/ansible/modules/cloud/google/gce_instance_template.py588
-rw-r--r--lib/ansible/modules/cloud/google/gce_labels.py324
-rw-r--r--lib/ansible/modules/cloud/google/gce_lb.py302
-rw-r--r--lib/ansible/modules/cloud/google/gce_mig.py887
-rw-r--r--lib/ansible/modules/cloud/google/gce_net.py513
-rw-r--r--lib/ansible/modules/cloud/google/gce_pd.py286
-rw-r--r--lib/ansible/modules/cloud/google/gce_snapshot.py227
-rw-r--r--lib/ansible/modules/cloud/google/gce_tag.py216
-rw-r--r--lib/ansible/modules/cloud/google/gcpubsub.py333
-rw-r--r--lib/ansible/modules/cloud/google/gcpubsub_info.py151
75 files changed, 0 insertions, 9015 deletions
diff --git a/lib/ansible/modules/cloud/google/_gcdns_record.py b/lib/ansible/modules/cloud/google/_gcdns_record.py
deleted file mode 100644
index e6e2d7049c..0000000000
--- a/lib/ansible/modules/cloud/google/_gcdns_record.py
+++ /dev/null
@@ -1,775 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright (C) 2015 CallFire Inc.
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-################################################################################
-# Documentation
-################################################################################
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['deprecated'],
- 'supported_by': 'community'}
-
-
-DOCUMENTATION = '''
----
-module: gcdns_record
-short_description: Creates or removes resource records in Google Cloud DNS
-description:
- - Creates or removes resource records in Google Cloud DNS.
-version_added: "2.2"
-author: "William Albert (@walbert947)"
-requirements:
- - "python >= 2.6"
- - "apache-libcloud >= 0.19.0"
-deprecated:
- removed_in: "2.12"
- why: Updated modules released with increased functionality
- alternative: Use M(gcp_dns_resource_record_set) instead.
-options:
- state:
- description:
- - Whether the given resource record should or should not be present.
- choices: ["present", "absent"]
- default: "present"
- record:
- description:
- - The fully-qualified domain name of the resource record.
- required: true
- aliases: ['name']
- zone:
- description:
- - The DNS domain name of the zone (e.g., example.com).
- - One of either I(zone) or I(zone_id) must be specified as an
- option, or the module will fail.
- - If both I(zone) and I(zone_id) are specified, I(zone_id) will be
- used.
- zone_id:
- description:
- - The Google Cloud ID of the zone (e.g., example-com).
- - One of either I(zone) or I(zone_id) must be specified as an
- option, or the module will fail.
- - These usually take the form of domain names with the dots replaced
- with dashes. A zone ID will never have any dots in it.
- - I(zone_id) can be faster than I(zone) in projects with a large
- number of zones.
- - If both I(zone) and I(zone_id) are specified, I(zone_id) will be
- used.
- type:
- description:
- - The type of resource record to add.
- required: true
- choices: [ 'A', 'AAAA', 'CNAME', 'SRV', 'TXT', 'SOA', 'NS', 'MX', 'SPF', 'PTR' ]
- record_data:
- description:
- - The record_data to use for the resource record.
- - I(record_data) must be specified if I(state) is C(present) or
- I(overwrite) is C(True), or the module will fail.
- - Valid record_data vary based on the record's I(type). In addition,
- resource records that contain a DNS domain name in the value
- field (e.g., CNAME, PTR, SRV, .etc) MUST include a trailing dot
- in the value.
- - Individual string record_data for TXT records must be enclosed in
- double quotes.
- - For resource records that have the same name but different
- record_data (e.g., multiple A records), they must be defined as
- multiple list entries in a single record.
- required: false
- aliases: ['value']
- ttl:
- description:
- - The amount of time in seconds that a resource record will remain
- cached by a caching resolver.
- default: 300
- overwrite:
- description:
- - Whether an attempt to overwrite an existing record should succeed
- or fail. The behavior of this option depends on I(state).
- - If I(state) is C(present) and I(overwrite) is C(True), this
- module will replace an existing resource record of the same name
- with the provided I(record_data). If I(state) is C(present) and
- I(overwrite) is C(False), this module will fail if there is an
- existing resource record with the same name and type, but
- different resource data.
- - If I(state) is C(absent) and I(overwrite) is C(True), this
- module will remove the given resource record unconditionally.
- If I(state) is C(absent) and I(overwrite) is C(False), this
- module will fail if the provided record_data do not match exactly
- with the existing resource record's record_data.
- type: bool
- default: 'no'
- service_account_email:
- description:
- - The e-mail address for a service account with access to Google
- Cloud DNS.
- pem_file:
- description:
- - The path to the PEM file associated with the service account
- email.
- - This option is deprecated and may be removed in a future release.
- Use I(credentials_file) instead.
- credentials_file:
- description:
- - The path to the JSON file associated with the service account
- email.
- project_id:
- description:
- - The Google Cloud Platform project ID to use.
-notes:
- - See also M(gcdns_zone).
- - This modules's underlying library does not support in-place updates for
- DNS resource records. Instead, resource records are quickly deleted and
- recreated.
- - SOA records are technically supported, but their functionality is limited
- to verifying that a zone's existing SOA record matches a pre-determined
- value. The SOA record cannot be updated.
- - Root NS records cannot be updated.
- - NAPTR records are not supported.
-'''
-
-EXAMPLES = '''
-# Create an A record.
-- gcdns_record:
- record: 'www1.example.com'
- zone: 'example.com'
- type: A
- value: '1.2.3.4'
-
-# Update an existing record.
-- gcdns_record:
- record: 'www1.example.com'
- zone: 'example.com'
- type: A
- overwrite: true
- value: '5.6.7.8'
-
-# Remove an A record.
-- gcdns_record:
- record: 'www1.example.com'
- zone_id: 'example-com'
- state: absent
- type: A
- value: '5.6.7.8'
-
-# Create a CNAME record.
-- gcdns_record:
- record: 'www.example.com'
- zone_id: 'example-com'
- type: CNAME
- value: 'www.example.com.' # Note the trailing dot
-
-# Create an MX record with a custom TTL.
-- gcdns_record:
- record: 'example.com'
- zone: 'example.com'
- type: MX
- ttl: 3600
- value: '10 mail.example.com.' # Note the trailing dot
-
-# Create multiple A records with the same name.
-- gcdns_record:
- record: 'api.example.com'
- zone_id: 'example-com'
- type: A
- record_data:
- - '192.0.2.23'
- - '10.4.5.6'
- - '198.51.100.5'
- - '203.0.113.10'
-
-# Change the value of an existing record with multiple record_data.
-- gcdns_record:
- record: 'api.example.com'
- zone: 'example.com'
- type: A
- overwrite: true
- record_data: # WARNING: All values in a record will be replaced
- - '192.0.2.23'
- - '192.0.2.42' # The changed record
- - '198.51.100.5'
- - '203.0.113.10'
-
-# Safely remove a multi-line record.
-- gcdns_record:
- record: 'api.example.com'
- zone_id: 'example-com'
- state: absent
- type: A
- record_data: # NOTE: All of the values must match exactly
- - '192.0.2.23'
- - '192.0.2.42'
- - '198.51.100.5'
- - '203.0.113.10'
-
-# Unconditionally remove a record.
-- gcdns_record:
- record: 'api.example.com'
- zone_id: 'example-com'
- state: absent
- overwrite: true # overwrite is true, so no values are needed
- type: A
-
-# Create an AAAA record
-- gcdns_record:
- record: 'www1.example.com'
- zone: 'example.com'
- type: AAAA
- value: 'fd00:db8::1'
-
-# Create a PTR record
-- gcdns_record:
- record: '10.5.168.192.in-addr.arpa'
- zone: '5.168.192.in-addr.arpa'
- type: PTR
- value: 'api.example.com.' # Note the trailing dot.
-
-# Create an NS record
-- gcdns_record:
- record: 'subdomain.example.com'
- zone: 'example.com'
- type: NS
- ttl: 21600
- record_data:
- - 'ns-cloud-d1.googledomains.com.' # Note the trailing dots on values
- - 'ns-cloud-d2.googledomains.com.'
- - 'ns-cloud-d3.googledomains.com.'
- - 'ns-cloud-d4.googledomains.com.'
-
-# Create a TXT record
-- gcdns_record:
- record: 'example.com'
- zone_id: 'example-com'
- type: TXT
- record_data:
- - '"v=spf1 include:_spf.google.com -all"' # A single-string TXT value
- - '"hello " "world"' # A multi-string TXT value
-'''
-
-RETURN = '''
-overwrite:
- description: Whether to the module was allowed to overwrite the record
- returned: success
- type: bool
- sample: True
-record:
- description: Fully-qualified domain name of the resource record
- returned: success
- type: str
- sample: mail.example.com.
-state:
- description: Whether the record is present or absent
- returned: success
- type: str
- sample: present
-ttl:
- description: The time-to-live of the resource record
- returned: success
- type: int
- sample: 300
-type:
- description: The type of the resource record
- returned: success
- type: str
- sample: A
-record_data:
- description: The resource record values
- returned: success
- type: list
- sample: ['5.6.7.8', '9.10.11.12']
-zone:
- description: The dns name of the zone
- returned: success
- type: str
- sample: example.com.
-zone_id:
- description: The Google Cloud DNS ID of the zone
- returned: success
- type: str
- sample: example-com
-'''
-
-
-################################################################################
-# Imports
-################################################################################
-
-import socket
-from distutils.version import LooseVersion
-
-try:
- from libcloud import __version__ as LIBCLOUD_VERSION
- from libcloud.common.google import InvalidRequestError
- from libcloud.common.types import LibcloudError
- from libcloud.dns.types import Provider
- from libcloud.dns.types import RecordDoesNotExistError
- from libcloud.dns.types import ZoneDoesNotExistError
- HAS_LIBCLOUD = True
- # The libcloud Google Cloud DNS provider.
- PROVIDER = Provider.GOOGLE
-except ImportError:
- HAS_LIBCLOUD = False
- PROVIDER = None
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.gcdns import gcdns_connect
-
-
-################################################################################
-# Constants
-################################################################################
-
-# Apache libcloud 0.19.0 was the first to contain the non-beta Google Cloud DNS
-# v1 API. Earlier versions contained the beta v1 API, which has since been
-# deprecated and decommissioned.
-MINIMUM_LIBCLOUD_VERSION = '0.19.0'
-
-# The records that libcloud's Google Cloud DNS provider supports.
-#
-# Libcloud has a RECORD_TYPE_MAP dictionary in the provider that also contains
-# this information and is the authoritative source on which records are
-# supported, but accessing the dictionary requires creating a Google Cloud DNS
-# driver object, which is done in a helper module.
-#
-# I'm hard-coding the supported record types here, because they (hopefully!)
-# shouldn't change much, and it allows me to use it as a "choices" parameter
-# in an AnsibleModule argument_spec.
-SUPPORTED_RECORD_TYPES = ['A', 'AAAA', 'CNAME', 'SRV', 'TXT', 'SOA', 'NS', 'MX', 'SPF', 'PTR']
-
-
-################################################################################
-# Functions
-################################################################################
-
-def create_record(module, gcdns, zone, record):
- """Creates or overwrites a resource record."""
-
- overwrite = module.boolean(module.params['overwrite'])
- record_name = module.params['record']
- record_type = module.params['type']
- ttl = module.params['ttl']
- record_data = module.params['record_data']
- data = dict(ttl=ttl, rrdatas=record_data)
-
- # Google Cloud DNS wants the trailing dot on all DNS names.
- if record_name[-1] != '.':
- record_name = record_name + '.'
-
- # If we found a record, we need to check if the values match.
- if record is not None:
- # If the record matches, we obviously don't have to change anything.
- if _records_match(record.data['ttl'], record.data['rrdatas'], ttl, record_data):
- return False
-
- # The record doesn't match, so we need to check if we can overwrite it.
- if not overwrite:
- module.fail_json(
- msg='cannot overwrite existing record, overwrite protection enabled',
- changed=False
- )
-
- # The record either doesn't exist, or it exists and we can overwrite it.
- if record is None and not module.check_mode:
- # There's no existing record, so we'll just create it.
- try:
- gcdns.create_record(record_name, zone, record_type, data)
- except InvalidRequestError as error:
- if error.code == 'invalid':
- # The resource record name and type are valid by themselves, but
- # not when combined (e.g., an 'A' record with "www.example.com"
- # as its value).
- module.fail_json(
- msg='value is invalid for the given type: ' +
- "%s, got value: %s" % (record_type, record_data),
- changed=False
- )
-
- elif error.code == 'cnameResourceRecordSetConflict':
- # We're attempting to create a CNAME resource record when we
- # already have another type of resource record with the name
- # domain name.
- module.fail_json(
- msg="non-CNAME resource record already exists: %s" % record_name,
- changed=False
- )
-
- else:
- # The error is something else that we don't know how to handle,
- # so we'll just re-raise the exception.
- raise
-
- elif record is not None and not module.check_mode:
- # The Google provider in libcloud doesn't support updating a record in
- # place, so if the record already exists, we need to delete it and
- # recreate it using the new information.
- gcdns.delete_record(record)
-
- try:
- gcdns.create_record(record_name, zone, record_type, data)
- except InvalidRequestError:
- # Something blew up when creating the record. This will usually be a
- # result of invalid value data in the new record. Unfortunately, we
- # already changed the state of the record by deleting the old one,
- # so we'll try to roll back before failing out.
- try:
- gcdns.create_record(record.name, record.zone, record.type, record.data)
- module.fail_json(
- msg='error updating record, the original record was restored',
- changed=False
- )
- except LibcloudError:
- # We deleted the old record, couldn't create the new record, and
- # couldn't roll back. That really sucks. We'll dump the original
- # record to the failure output so the user can restore it if
- # necessary.
- module.fail_json(
- msg='error updating record, and could not restore original record, ' +
- "original name: %s " % record.name +
- "original zone: %s " % record.zone +
- "original type: %s " % record.type +
- "original data: %s" % record.data,
- changed=True)
-
- return True
-
-
-def remove_record(module, gcdns, record):
- """Remove a resource record."""
-
- overwrite = module.boolean(module.params['overwrite'])
- ttl = module.params['ttl']
- record_data = module.params['record_data']
-
- # If there is no record, we're obviously done.
- if record is None:
- return False
-
- # If there is an existing record, do our values match the values of the
- # existing record?
- if not overwrite:
- if not _records_match(record.data['ttl'], record.data['rrdatas'], ttl, record_data):
- module.fail_json(
- msg='cannot delete due to non-matching ttl or record_data: ' +
- "ttl: %d, record_data: %s " % (ttl, record_data) +
- "original ttl: %d, original record_data: %s" % (record.data['ttl'], record.data['rrdatas']),
- changed=False
- )
-
- # If we got to this point, we're okay to delete the record.
- if not module.check_mode:
- gcdns.delete_record(record)
-
- return True
-
-
-def _get_record(gcdns, zone, record_type, record_name):
- """Gets the record object for a given FQDN."""
-
- # The record ID is a combination of its type and FQDN. For example, the
- # ID of an A record for www.example.com would be 'A:www.example.com.'
- record_id = "%s:%s" % (record_type, record_name)
-
- try:
- return gcdns.get_record(zone.id, record_id)
- except RecordDoesNotExistError:
- return None
-
-
-def _get_zone(gcdns, zone_name, zone_id):
- """Gets the zone object for a given domain name."""
-
- if zone_id is not None:
- try:
- return gcdns.get_zone(zone_id)
- except ZoneDoesNotExistError:
- return None
-
- # To create a zone, we need to supply a domain name. However, to delete a
- # zone, we need to supply a zone ID. Zone ID's are often based on domain
- # names, but that's not guaranteed, so we'll iterate through the list of
- # zones to see if we can find a matching domain name.
- available_zones = gcdns.iterate_zones()
- found_zone = None
-
- for zone in available_zones:
- if zone.domain == zone_name:
- found_zone = zone
- break
-
- return found_zone
-
-
-def _records_match(old_ttl, old_record_data, new_ttl, new_record_data):
- """Checks to see if original and new TTL and values match."""
-
- matches = True
-
- if old_ttl != new_ttl:
- matches = False
- if old_record_data != new_record_data:
- matches = False
-
- return matches
-
-
-def _sanity_check(module):
- """Run sanity checks that don't depend on info from the zone/record."""
-
- overwrite = module.params['overwrite']
- record_name = module.params['record']
- record_type = module.params['type']
- state = module.params['state']
- ttl = module.params['ttl']
- record_data = module.params['record_data']
-
- # Apache libcloud needs to be installed and at least the minimum version.
- if not HAS_LIBCLOUD:
- module.fail_json(
- msg='This module requires Apache libcloud %s or greater' % MINIMUM_LIBCLOUD_VERSION,
- changed=False
- )
- elif LooseVersion(LIBCLOUD_VERSION) < MINIMUM_LIBCLOUD_VERSION:
- module.fail_json(
- msg='This module requires Apache libcloud %s or greater' % MINIMUM_LIBCLOUD_VERSION,
- changed=False
- )
-
- # A negative TTL is not permitted (how would they even work?!).
- if ttl < 0:
- module.fail_json(
- msg='TTL cannot be less than zero, got: %d' % ttl,
- changed=False
- )
-
- # Deleting SOA records is not permitted.
- if record_type == 'SOA' and state == 'absent':
- module.fail_json(msg='cannot delete SOA records', changed=False)
-
- # Updating SOA records is not permitted.
- if record_type == 'SOA' and state == 'present' and overwrite:
- module.fail_json(msg='cannot update SOA records', changed=False)
-
- # Some sanity checks depend on what value was supplied.
- if record_data is not None and (state == 'present' or not overwrite):
- # A records must contain valid IPv4 addresses.
- if record_type == 'A':
- for value in record_data:
- try:
- socket.inet_aton(value)
- except socket.error:
- module.fail_json(
- msg='invalid A record value, got: %s' % value,
- changed=False
- )
-
- # AAAA records must contain valid IPv6 addresses.
- if record_type == 'AAAA':
- for value in record_data:
- try:
- socket.inet_pton(socket.AF_INET6, value)
- except socket.error:
- module.fail_json(
- msg='invalid AAAA record value, got: %s' % value,
- changed=False
- )
-
- # CNAME and SOA records can't have multiple values.
- if record_type in ['CNAME', 'SOA'] and len(record_data) > 1:
- module.fail_json(
- msg='CNAME or SOA records cannot have more than one value, ' +
- "got: %s" % record_data,
- changed=False
- )
-
- # Google Cloud DNS does not support wildcard NS records.
- if record_type == 'NS' and record_name[0] == '*':
- module.fail_json(
- msg="wildcard NS records not allowed, got: %s" % record_name,
- changed=False
- )
-
- # Values for txt records must begin and end with a double quote.
- if record_type == 'TXT':
- for value in record_data:
- if value[0] != '"' and value[-1] != '"':
- module.fail_json(
- msg='TXT record_data must be enclosed in double quotes, ' +
- 'got: %s' % value,
- changed=False
- )
-
-
-def _additional_sanity_checks(module, zone):
- """Run input sanity checks that depend on info from the zone/record."""
-
- overwrite = module.params['overwrite']
- record_name = module.params['record']
- record_type = module.params['type']
- state = module.params['state']
-
- # CNAME records are not allowed to have the same name as the root domain.
- if record_type == 'CNAME' and record_name == zone.domain:
- module.fail_json(
- msg='CNAME records cannot match the zone name',
- changed=False
- )
-
- # The root domain must always have an NS record.
- if record_type == 'NS' and record_name == zone.domain and state == 'absent':
- module.fail_json(
- msg='cannot delete root NS records',
- changed=False
- )
-
- # Updating NS records with the name as the root domain is not allowed
- # because libcloud does not support in-place updates and root domain NS
- # records cannot be removed.
- if record_type == 'NS' and record_name == zone.domain and overwrite:
- module.fail_json(
- msg='cannot update existing root NS records',
- changed=False
- )
-
- # SOA records with names that don't match the root domain are not permitted
- # (and wouldn't make sense anyway).
- if record_type == 'SOA' and record_name != zone.domain:
- module.fail_json(
- msg='non-root SOA records are not permitted, got: %s' % record_name,
- changed=False
- )
-
-
-################################################################################
-# Main
-################################################################################
-
-def main():
- """Main function"""
-
- module = AnsibleModule(
- argument_spec=dict(
- state=dict(default='present', choices=['present', 'absent'], type='str'),
- record=dict(required=True, aliases=['name'], type='str'),
- zone=dict(type='str'),
- zone_id=dict(type='str'),
- type=dict(required=True, choices=SUPPORTED_RECORD_TYPES, type='str'),
- record_data=dict(aliases=['value'], type='list'),
- ttl=dict(default=300, type='int'),
- overwrite=dict(default=False, type='bool'),
- service_account_email=dict(type='str'),
- pem_file=dict(type='path'),
- credentials_file=dict(type='path'),
- project_id=dict(type='str')
- ),
- required_if=[
- ('state', 'present', ['record_data']),
- ('overwrite', False, ['record_data'])
- ],
- required_one_of=[['zone', 'zone_id']],
- supports_check_mode=True
- )
-
- _sanity_check(module)
-
- record_name = module.params['record']
- record_type = module.params['type']
- state = module.params['state']
- ttl = module.params['ttl']
- zone_name = module.params['zone']
- zone_id = module.params['zone_id']
-
- json_output = dict(
- state=state,
- record=record_name,
- zone=zone_name,
- zone_id=zone_id,
- type=record_type,
- record_data=module.params['record_data'],
- ttl=ttl,
- overwrite=module.boolean(module.params['overwrite'])
- )
-
- # Google Cloud DNS wants the trailing dot on all DNS names.
- if zone_name is not None and zone_name[-1] != '.':
- zone_name = zone_name + '.'
- if record_name[-1] != '.':
- record_name = record_name + '.'
-
- # Build a connection object that we can use to connect with Google Cloud
- # DNS.
- gcdns = gcdns_connect(module, provider=PROVIDER)
-
- # We need to check that the zone we're creating a record for actually
- # exists.
- zone = _get_zone(gcdns, zone_name, zone_id)
- if zone is None and zone_name is not None:
- module.fail_json(
- msg='zone name was not found: %s' % zone_name,
- changed=False
- )
- elif zone is None and zone_id is not None:
- module.fail_json(
- msg='zone id was not found: %s' % zone_id,
- changed=False
- )
-
- # Populate the returns with the actual zone information.
- json_output['zone'] = zone.domain
- json_output['zone_id'] = zone.id
-
- # We also need to check if the record we want to create or remove actually
- # exists.
- try:
- record = _get_record(gcdns, zone, record_type, record_name)
- except InvalidRequestError:
- # We gave Google Cloud DNS an invalid DNS record name.
- module.fail_json(
- msg='record name is invalid: %s' % record_name,
- changed=False
- )
-
- _additional_sanity_checks(module, zone)
-
- diff = dict()
-
- # Build the 'before' diff
- if record is None:
- diff['before'] = ''
- diff['before_header'] = '<absent>'
- else:
- diff['before'] = dict(
- record=record.data['name'],
- type=record.data['type'],
- record_data=record.data['rrdatas'],
- ttl=record.data['ttl']
- )
- diff['before_header'] = "%s:%s" % (record_type, record_name)
-
- # Create, remove, or modify the record.
- if state == 'present':
- diff['after'] = dict(
- record=record_name,
- type=record_type,
- record_data=module.params['record_data'],
- ttl=ttl
- )
- diff['after_header'] = "%s:%s" % (record_type, record_name)
-
- changed = create_record(module, gcdns, zone, record)
-
- elif state == 'absent':
- diff['after'] = ''
- diff['after_header'] = '<absent>'
-
- changed = remove_record(module, gcdns, record)
-
- module.exit_json(changed=changed, diff=diff, **json_output)
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/cloud/google/_gcdns_zone.py b/lib/ansible/modules/cloud/google/_gcdns_zone.py
deleted file mode 100644
index 57eaf944ef..0000000000
--- a/lib/ansible/modules/cloud/google/_gcdns_zone.py
+++ /dev/null
@@ -1,371 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright (C) 2015 CallFire Inc.
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-################################################################################
-# Documentation
-################################################################################
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['deprecated'],
- 'supported_by': 'community'}
-
-
-DOCUMENTATION = '''
----
-module: gcdns_zone
-short_description: Creates or removes zones in Google Cloud DNS
-description:
- - Creates or removes managed zones in Google Cloud DNS.
-version_added: "2.2"
-author: "William Albert (@walbert947)"
-requirements:
- - "apache-libcloud >= 0.19.0"
-deprecated:
- removed_in: "2.12"
- why: Updated modules released with increased functionality
- alternative: Use M(gcp_dns_managed_zone) instead.
-options:
- state:
- description:
- - Whether the given zone should or should not be present.
- choices: ["present", "absent"]
- default: "present"
- zone:
- description:
- - The DNS domain name of the zone.
- - This is NOT the Google Cloud DNS zone ID (e.g., example-com). If
- you attempt to specify a zone ID, this module will attempt to
- create a TLD and will fail.
- required: true
- aliases: ['name']
- description:
- description:
- - An arbitrary text string to use for the zone description.
- default: ""
- service_account_email:
- description:
- - The e-mail address for a service account with access to Google
- Cloud DNS.
- pem_file:
- description:
- - The path to the PEM file associated with the service account
- email.
- - This option is deprecated and may be removed in a future release.
- Use I(credentials_file) instead.
- credentials_file:
- description:
- - The path to the JSON file associated with the service account
- email.
- project_id:
- description:
- - The Google Cloud Platform project ID to use.
-notes:
- - See also M(gcdns_record).
- - Zones that are newly created must still be set up with a domain registrar
- before they can be used.
-'''
-
-EXAMPLES = '''
-# Basic zone creation example.
-- name: Create a basic zone with the minimum number of parameters.
- gcdns_zone: zone=example.com
-
-# Zone removal example.
-- name: Remove a zone.
- gcdns_zone: zone=example.com state=absent
-
-# Zone creation with description
-- name: Creating a zone with a description
- gcdns_zone: zone=example.com description="This is an awesome zone"
-'''
-
-RETURN = '''
-description:
- description: The zone's description
- returned: success
- type: str
- sample: This is an awesome zone
-state:
- description: Whether the zone is present or absent
- returned: success
- type: str
- sample: present
-zone:
- description: The zone's DNS name
- returned: success
- type: str
- sample: example.com.
-'''
-
-
-################################################################################
-# Imports
-################################################################################
-
-from distutils.version import LooseVersion
-
-try:
- from libcloud import __version__ as LIBCLOUD_VERSION
- from libcloud.common.google import InvalidRequestError
- from libcloud.common.google import ResourceExistsError
- from libcloud.common.google import ResourceNotFoundError
- from libcloud.dns.types import Provider
- # The libcloud Google Cloud DNS provider.
- PROVIDER = Provider.GOOGLE
- HAS_LIBCLOUD = True
-except ImportError:
- HAS_LIBCLOUD = False
- PROVIDER = None
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.gcdns import gcdns_connect
-
-
-################################################################################
-# Constants
-################################################################################
-
-# Apache libcloud 0.19.0 was the first to contain the non-beta Google Cloud DNS
-# v1 API. Earlier versions contained the beta v1 API, which has since been
-# deprecated and decommissioned.
-MINIMUM_LIBCLOUD_VERSION = '0.19.0'
-
-# The URL used to verify ownership of a zone in Google Cloud DNS.
-ZONE_VERIFICATION_URL = 'https://www.google.com/webmasters/verification/'
-
-################################################################################
-# Functions
-################################################################################
-
-
-def create_zone(module, gcdns, zone):
- """Creates a new Google Cloud DNS zone."""
-
- description = module.params['description']
- extra = dict(description=description)
- zone_name = module.params['zone']
-
- # Google Cloud DNS wants the trailing dot on the domain name.
- if zone_name[-1] != '.':
- zone_name = zone_name + '.'
-
- # If we got a zone back, then the domain exists.
- if zone is not None:
- return False
-
- # The zone doesn't exist yet.
- try:
- if not module.check_mode:
- gcdns.create_zone(domain=zone_name, extra=extra)
- return True
-
- except ResourceExistsError:
- # The zone already exists. We checked for this already, so either
- # Google is lying, or someone was a ninja and created the zone
- # within milliseconds of us checking for its existence. In any case,
- # the zone has already been created, so we have nothing more to do.
- return False
-
- except InvalidRequestError as error:
- if error.code == 'invalid':
- # The zone name or a parameter might be completely invalid. This is
- # typically caused by an illegal DNS name (e.g. foo..com).
- module.fail_json(
- msg="zone name is not a valid DNS name: %s" % zone_name,
- changed=False
- )
-
- elif error.code == 'managedZoneDnsNameNotAvailable':
- # Google Cloud DNS will refuse to create zones with certain domain
- # names, such as TLDs, ccTLDs, or special domain names such as
- # example.com.
- module.fail_json(
- msg="zone name is reserved or already in use: %s" % zone_name,
- changed=False
- )
-
- elif error.code == 'verifyManagedZoneDnsNameOwnership':
- # This domain name needs to be verified before Google will create
- # it. This occurs when a user attempts to create a zone which shares
- # a domain name with a zone hosted elsewhere in Google Cloud DNS.
- module.fail_json(
- msg="ownership of zone %s needs to be verified at %s" % (zone_name, ZONE_VERIFICATION_URL),
- changed=False
- )
-
- else:
- # The error is something else that we don't know how to handle,
- # so we'll just re-raise the exception.
- raise
-
-
-def remove_zone(module, gcdns, zone):
- """Removes an existing Google Cloud DNS zone."""
-
- # If there's no zone, then we're obviously done.
- if zone is None:
- return False
-
- # An empty zone will have two resource records:
- # 1. An NS record with a list of authoritative name servers
- # 2. An SOA record
- # If any additional resource records are present, Google Cloud DNS will
- # refuse to remove the zone.
- if len(zone.list_records()) > 2:
- module.fail_json(
- msg="zone is not empty and cannot be removed: %s" % zone.domain,
- changed=False
- )
-
- try:
- if not module.check_mode:
- gcdns.delete_zone(zone)
- return True
-
- except ResourceNotFoundError:
- # When we performed our check, the zone existed. It may have been
- # deleted by something else. It's gone, so whatever.
- return False
-
- except InvalidRequestError as error:
- if error.code == 'containerNotEmpty':
- # When we performed our check, the zone existed and was empty. In
- # the milliseconds between the check and the removal command,
- # records were added to the zone.
- module.fail_json(
- msg="zone is not empty and cannot be removed: %s" % zone.domain,
- changed=False
- )
-
- else:
- # The error is something else that we don't know how to handle,
- # so we'll just re-raise the exception.
- raise
-
-
-def _get_zone(gcdns, zone_name):
- """Gets the zone object for a given domain name."""
-
- # To create a zone, we need to supply a zone name. However, to delete a
- # zone, we need to supply a zone ID. Zone ID's are often based on zone
- # names, but that's not guaranteed, so we'll iterate through the list of
- # zones to see if we can find a matching name.
- available_zones = gcdns.iterate_zones()
- found_zone = None
-
- for zone in available_zones:
- if zone.domain == zone_name:
- found_zone = zone
- break
-
- return found_zone
-
-
-def _sanity_check(module):
- """Run module sanity checks."""
-
- zone_name = module.params['zone']
-
- # Apache libcloud needs to be installed and at least the minimum version.
- if not HAS_LIBCLOUD:
- module.fail_json(
- msg='This module requires Apache libcloud %s or greater' % MINIMUM_LIBCLOUD_VERSION,
- changed=False
- )
- elif LooseVersion(LIBCLOUD_VERSION) < MINIMUM_LIBCLOUD_VERSION:
- module.fail_json(
- msg='This module requires Apache libcloud %s or greater' % MINIMUM_LIBCLOUD_VERSION,
- changed=False
- )
-
- # Google Cloud DNS does not support the creation of TLDs.
- if '.' not in zone_name or len([label for label in zone_name.split('.') if label]) == 1:
- module.fail_json(
- msg='cannot create top-level domain: %s' % zone_name,
- changed=False
- )
-
-################################################################################
-# Main
-################################################################################
-
-
-def main():
- """Main function"""
-
- module = AnsibleModule(
- argument_spec=dict(
- state=dict(default='present', choices=['present', 'absent'], type='str'),
- zone=dict(required=True, aliases=['name'], type='str'),
- description=dict(default='', type='str'),
- service_account_email=dict(type='str'),
- pem_file=dict(type='path'),
- credentials_file=dict(type='path'),
- project_id=dict(type='str')
- ),
- supports_check_mode=True
- )
-
- _sanity_check(module)
-
- zone_name = module.params['zone']
- state = module.params['state']
-
- # Google Cloud DNS wants the trailing dot on the domain name.
- if zone_name[-1] != '.':
- zone_name = zone_name + '.'
-
- json_output = dict(
- state=state,
- zone=zone_name,
- description=module.params['description']
- )
-
- # Build a connection object that was can use to connect with Google
- # Cloud DNS.
- gcdns = gcdns_connect(module, provider=PROVIDER)
-
- # We need to check if the zone we're attempting to create already exists.
- zone = _get_zone(gcdns, zone_name)
-
- diff = dict()
-
- # Build the 'before' diff
- if zone is None:
- diff['before'] = ''
- diff['before_header'] = '<absent>'
- else:
- diff['before'] = dict(
- zone=zone.domain,
- description=zone.extra['description']
- )
- diff['before_header'] = zone_name
-
- # Create or remove the zone.
- if state == 'present':
- diff['after'] = dict(
- zone=zone_name,
- description=module.params['description']
- )
- diff['after_header'] = zone_name
-
- changed = create_zone(module, gcdns, zone)
-
- elif state == 'absent':
- diff['after'] = ''
- diff['after_header'] = '<absent>'
-
- changed = remove_zone(module, gcdns, zone)
-
- module.exit_json(changed=changed, diff=diff, **json_output)
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/cloud/google/_gce.py b/lib/ansible/modules/cloud/google/_gce.py
deleted file mode 100644
index d5bd6abf28..0000000000
--- a/lib/ansible/modules/cloud/google/_gce.py
+++ /dev/null
@@ -1,754 +0,0 @@
-#!/usr/bin/python
-# Copyright 2013 Google Inc.
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-
-__metaclass__ = type
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['deprecated'],
- 'supported_by': 'community'}
-
-DOCUMENTATION = '''
----
-module: gce
-version_added: "1.4"
-short_description: create or terminate GCE instances
-description:
- - Creates or terminates Google Compute Engine (GCE) instances. See
- U(https://cloud.google.com/compute) for an overview.
- Full install/configuration instructions for the gce* modules can
- be found in the comments of ansible/test/gce_tests.py.
-deprecated:
- removed_in: "2.12"
- why: Updated modules released with increased functionality
- alternative: Use M(gcp_compute_instance) instead.
-options:
- image:
- description:
- - image string to use for the instance (default will follow latest
- stable debian image)
- default: "debian-8"
- image_family:
- description:
- - image family from which to select the image. The most recent
- non-deprecated image in the family will be used.
- version_added: "2.4"
- external_projects:
- description:
- - A list of other projects (accessible with the provisioning credentials)
- to be searched for the image.
- version_added: "2.4"
- instance_names:
- description:
- - a comma-separated list of instance names to create or destroy
- machine_type:
- description:
- - machine type to use for the instance, use 'n1-standard-1' by default
- default: "n1-standard-1"
- metadata:
- description:
- - a hash/dictionary of custom data for the instance;
- '{"key":"value", ...}'
- service_account_email:
- version_added: "1.5.1"
- description:
- - service account email
- service_account_permissions:
- version_added: "2.0"
- description:
- - service account permissions (see
- U(https://cloud.google.com/sdk/gcloud/reference/compute/instances/create),
- --scopes section for detailed information)
- choices: [
- "bigquery", "cloud-platform", "compute-ro", "compute-rw",
- "useraccounts-ro", "useraccounts-rw", "datastore", "logging-write",
- "monitoring", "sql-admin", "storage-full", "storage-ro",
- "storage-rw", "taskqueue", "userinfo-email"
- ]
- pem_file:
- version_added: "1.5.1"
- description:
- - path to the pem file associated with the service account email
- This option is deprecated. Use 'credentials_file'.
- credentials_file:
- version_added: "2.1.0"
- description:
- - path to the JSON file associated with the service account email
- project_id:
- version_added: "1.5.1"
- description:
- - your GCE project ID
- name:
- description:
- - either a name of a single instance or when used with 'num_instances',
- the base name of a cluster of nodes
- aliases: ['base_name']
- num_instances:
- description:
- - can be used with 'name', specifies
- the number of nodes to provision using 'name'
- as a base name
- version_added: "2.3"
- network:
- description:
- - name of the network, 'default' will be used if not specified
- default: "default"
- subnetwork:
- description:
- - name of the subnetwork in which the instance should be created
- version_added: "2.2"
- persistent_boot_disk:
- description:
- - if set, create the instance with a persistent boot disk
- type: bool
- default: 'no'
- disks:
- description:
- - a list of persistent disks to attach to the instance; a string value
- gives the name of the disk; alternatively, a dictionary value can
- define 'name' and 'mode' ('READ_ONLY' or 'READ_WRITE'). The first entry
- will be the boot disk (which must be READ_WRITE).
- version_added: "1.7"
- state:
- description:
- - desired state of the resource
- default: "present"
- choices: ["active", "present", "absent", "deleted", "started", "stopped", "terminated"]
- tags:
- description:
- - a comma-separated list of tags to associate with the instance
- zone:
- description:
- - the GCE zone to use. The list of available zones is at U(https://cloud.google.com/compute/docs/regions-zones/regions-zones#available).
- required: true
- default: "us-central1-a"
- ip_forward:
- version_added: "1.9"
- description:
- - set to C(yes) if the instance can forward ip packets (useful for
- gateways)
- type: bool
- default: 'no'
- external_ip:
- version_added: "1.9"
- description:
- - type of external ip, ephemeral by default; alternatively, a fixed gce ip or ip name can be given. Specify 'none' if no external ip is desired.
- default: "ephemeral"
- disk_auto_delete:
- version_added: "1.9"
- description:
- - if set boot disk will be removed after instance destruction
- type: bool
- default: 'yes'
- preemptible:
- version_added: "2.1"
- description:
- - if set to C(yes), instances will be preemptible and time-limited.
- (requires libcloud >= 0.20.0)
- type: bool
- default: 'no'
- disk_size:
- description:
- - The size of the boot disk created for this instance (in GB)
- default: 10
- version_added: "2.3"
-
-requirements:
- - "python >= 2.6"
- - "apache-libcloud >= 0.13.3, >= 0.17.0 if using JSON credentials,
- >= 0.20.0 if using preemptible option"
-notes:
- - Either I(instance_names) or I(name) is required.
- - JSON credentials strongly preferred.
-author:
- - Eric Johnson (@erjohnso) <erjohnso@google.com>
- - Tom Melendez (@supertom) <supertom@google.com>
-'''
-
-EXAMPLES = '''
-# Basic provisioning example. Create a single Debian 8 instance in the
-# us-central1-a Zone of the n1-standard-1 machine type.
-# Create multiple instances by specifying multiple names, separated by
-# commas in the instance_names field
-# (e.g. my-test-instance1,my-test-instance2)
- - gce:
- instance_names: my-test-instance1
- zone: us-central1-a
- machine_type: n1-standard-1
- image: debian-8
- state: present
- service_account_email: "your-sa@your-project-name.iam.gserviceaccount.com"
- credentials_file: "/path/to/your-key.json"
- project_id: "your-project-name"
- disk_size: 32
-
-# Create a single instance of an image from the "my-base-image" image family
-# in the us-central1-a Zone of the n1-standard-1 machine type.
-# This image family is in the "my-other-project" GCP project.
- - gce:
- instance_names: my-test-instance1
- zone: us-central1-a
- machine_type: n1-standard-1
- image_family: my-base-image
- external_projects:
- - my-other-project
- state: present
- service_account_email: "your-sa@your-project-name.iam.gserviceaccount.com"
- credentials_file: "/path/to/your-key.json"
- project_id: "your-project-name"
- disk_size: 32
-
-# Create a single Debian 8 instance in the us-central1-a Zone
-# Use existing disks, custom network/subnetwork, set service account permissions
-# add tags and metadata.
- - gce:
- instance_names: my-test-instance
- zone: us-central1-a
- machine_type: n1-standard-1
- state: present
- metadata: '{"db":"postgres", "group":"qa", "id":500}'
- tags:
- - http-server
- - my-other-tag
- disks:
- - name: disk-2
- mode: READ_WRITE
- - name: disk-3
- mode: READ_ONLY
- disk_auto_delete: false
- network: foobar-network
- subnetwork: foobar-subnetwork-1
- preemptible: true
- ip_forward: true
- service_account_permissions:
- - storage-full
- - taskqueue
- - bigquery
- - https://www.googleapis.com/auth/ndev.clouddns.readwrite
- service_account_email: "your-sa@your-project-name.iam.gserviceaccount.com"
- credentials_file: "/path/to/your-key.json"
- project_id: "your-project-name"
-
----
-# Example Playbook
-- name: Compute Engine Instance Examples
- hosts: localhost
- vars:
- service_account_email: "your-sa@your-project-name.iam.gserviceaccount.com"
- credentials_file: "/path/to/your-key.json"
- project_id: "your-project-name"
- tasks:
- - name: create multiple instances
- # Basic provisioning example. Create multiple Debian 8 instances in the
- # us-central1-a Zone of n1-standard-1 machine type.
- gce:
- instance_names: test1,test2,test3
- zone: us-central1-a
- machine_type: n1-standard-1
- image: debian-8
- state: present
- service_account_email: "{{ service_account_email }}"
- credentials_file: "{{ credentials_file }}"
- project_id: "{{ project_id }}"
- metadata : '{ "startup-script" : "apt-get update" }'
- register: gce
-
- - name: Save host data
- add_host:
- hostname: "{{ item.public_ip }}"
- groupname: gce_instances_ips
- with_items: "{{ gce.instance_data }}"
-
- - name: Wait for SSH for instances
- wait_for:
- delay: 1
- host: "{{ item.public_ip }}"
- port: 22
- state: started
- timeout: 30
- with_items: "{{ gce.instance_data }}"
-
- - name: Configure Hosts
- hosts: gce_instances_ips
- become: yes
- become_method: sudo
- roles:
- - my-role-one
- - my-role-two
- tags:
- - config
-
- - name: delete test-instances
- # Basic termination of instance.
- gce:
- service_account_email: "{{ service_account_email }}"
- credentials_file: "{{ credentials_file }}"
- project_id: "{{ project_id }}"
- instance_names: "{{ gce.instance_names }}"
- zone: us-central1-a
- state: absent
- tags:
- - delete
-'''
-
-import socket
-import logging
-
-try:
- from ast import literal_eval
-
- HAS_PYTHON26 = True
-except ImportError:
- HAS_PYTHON26 = False
-
-try:
- import libcloud
- from libcloud.compute.types import Provider
- from libcloud.compute.providers import get_driver
- from libcloud.common.google import GoogleBaseError, QuotaExceededError, \
- ResourceExistsError, ResourceInUseError, ResourceNotFoundError
- from libcloud.compute.drivers.gce import GCEAddress
-
- _ = Provider.GCE
- HAS_LIBCLOUD = True
-except ImportError:
- HAS_LIBCLOUD = False
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.gce import gce_connect, unexpected_error_msg
-from ansible.module_utils.gcp import get_valid_location
-from ansible.module_utils.six.moves import reduce
-
-
-def get_instance_info(inst):
- """Retrieves instance information from an instance object and returns it
- as a dictionary.
-
- """
- metadata = {}
- if 'metadata' in inst.extra and 'items' in inst.extra['metadata']:
- for md in inst.extra['metadata']['items']:
- metadata[md['key']] = md['value']
-
- try:
- netname = inst.extra['networkInterfaces'][0]['network'].split('/')[-1]
- except Exception:
- netname = None
- try:
- subnetname = inst.extra['networkInterfaces'][0]['subnetwork'].split('/')[-1]
- except Exception:
- subnetname = None
- if 'disks' in inst.extra:
- disk_names = [disk_info['source'].split('/')[-1]
- for disk_info
- in sorted(inst.extra['disks'],
- key=lambda disk_info: disk_info['index'])]
- else:
- disk_names = []
-
- if len(inst.public_ips) == 0:
- public_ip = None
- else:
- public_ip = inst.public_ips[0]
-
- return ({
- 'image': inst.image is not None and inst.image.split('/')[-1] or None,
- 'disks': disk_names,
- 'machine_type': inst.size,
- 'metadata': metadata,
- 'name': inst.name,
- 'network': netname,
- 'subnetwork': subnetname,
- 'private_ip': inst.private_ips[0],
- 'public_ip': public_ip,
- 'status': ('status' in inst.extra) and inst.extra['status'] or None,
- 'tags': ('tags' in inst.extra) and inst.extra['tags'] or [],
- 'zone': ('zone' in inst.extra) and inst.extra['zone'].name or None,
- })
-
-
-def create_instances(module, gce, instance_names, number, lc_zone):
- """Creates new instances. Attributes other than instance_names are picked
- up from 'module'
-
- module : AnsibleModule object
- gce: authenticated GCE libcloud driver
- instance_names: python list of instance names to create
- number: number of instances to create
- lc_zone: GCEZone object
-
- Returns:
- A list of dictionaries with instance information
- about the instances that were launched.
-
- """
- image = module.params.get('image')
- image_family = module.params.get('image_family')
- external_projects = module.params.get('external_projects')
- machine_type = module.params.get('machine_type')
- metadata = module.params.get('metadata')
- network = module.params.get('network')
- subnetwork = module.params.get('subnetwork')
- persistent_boot_disk = module.params.get('persistent_boot_disk')
- disks = module.params.get('disks')
- tags = module.params.get('tags')
- ip_forward = module.params.get('ip_forward')
- external_ip = module.params.get('external_ip')
- disk_auto_delete = module.params.get('disk_auto_delete')
- preemptible = module.params.get('preemptible')
- disk_size = module.params.get('disk_size')
- service_account_permissions = module.params.get('service_account_permissions')
-
- if external_ip == "none":
- instance_external_ip = None
- elif external_ip != "ephemeral":
- instance_external_ip = external_ip
- try:
- # check if instance_external_ip is an ip or a name
- try:
- socket.inet_aton(instance_external_ip)
- instance_external_ip = GCEAddress(id='unknown', name='unknown', address=instance_external_ip, region='unknown', driver=gce)
- except socket.error:
- instance_external_ip = gce.ex_get_address(instance_external_ip)
- except GoogleBaseError as e:
- module.fail_json(msg='Unexpected error attempting to get a static ip %s, error: %s' % (external_ip, e.value))
- else:
- instance_external_ip = external_ip
-
- new_instances = []
- changed = False
-
- lc_disks = []
- disk_modes = []
- for i, disk in enumerate(disks or []):
- if isinstance(disk, dict):
- lc_disks.append(gce.ex_get_volume(disk['name'], lc_zone))
- disk_modes.append(disk['mode'])
- else:
- lc_disks.append(gce.ex_get_volume(disk, lc_zone))
- # boot disk is implicitly READ_WRITE
- disk_modes.append('READ_ONLY' if i > 0 else 'READ_WRITE')
- lc_network = gce.ex_get_network(network)
- lc_machine_type = gce.ex_get_size(machine_type, lc_zone)
-
- # Try to convert the user's metadata value into the format expected
- # by GCE. First try to ensure user has proper quoting of a
- # dictionary-like syntax using 'literal_eval', then convert the python
- # dict into a python list of 'key' / 'value' dicts. Should end up
- # with:
- # [ {'key': key1, 'value': value1}, {'key': key2, 'value': value2}, ...]
- if metadata:
- if isinstance(metadata, dict):
- md = metadata
- else:
- try:
- md = literal_eval(str(metadata))
- if not isinstance(md, dict):
- raise ValueError('metadata must be a dict')
- except ValueError as e:
- module.fail_json(msg='bad metadata: %s' % str(e))
- except SyntaxError as e:
- module.fail_json(msg='bad metadata syntax')
-
- if hasattr(libcloud, '__version__') and libcloud.__version__ < '0.15':
- items = []
- for k, v in md.items():
- items.append({"key": k, "value": v})
- metadata = {'items': items}
- else:
- metadata = md
-
- lc_image = LazyDiskImage(module, gce, image, lc_disks, family=image_family, projects=external_projects)
- ex_sa_perms = []
- bad_perms = []
- if service_account_permissions:
- for perm in service_account_permissions:
- if perm not in gce.SA_SCOPES_MAP and not perm.startswith('https://www.googleapis.com/auth'):
- bad_perms.append(perm)
- if len(bad_perms) > 0:
- module.fail_json(msg='bad permissions: %s' % str(bad_perms))
- ex_sa_perms.append({'email': "default"})
- ex_sa_perms[0]['scopes'] = service_account_permissions
-
- # These variables all have default values but check just in case
- if not lc_network or not lc_machine_type or not lc_zone:
- module.fail_json(msg='Missing required create instance variable',
- changed=False)
-
- gce_args = dict(
- location=lc_zone,
- ex_network=network, ex_tags=tags, ex_metadata=metadata,
- ex_can_ip_forward=ip_forward,
- external_ip=instance_external_ip, ex_disk_auto_delete=disk_auto_delete,
- ex_service_accounts=ex_sa_perms
- )
- if preemptible is not None:
- gce_args['ex_preemptible'] = preemptible
- if subnetwork is not None:
- gce_args['ex_subnetwork'] = subnetwork
-
- if isinstance(instance_names, str) and not number:
- instance_names = [instance_names]
-
- if isinstance(instance_names, str) and number:
- instance_responses = gce.ex_create_multiple_nodes(instance_names, lc_machine_type,
- lc_image(), number, **gce_args)
- for resp in instance_responses:
- n = resp
- if isinstance(resp, libcloud.compute.drivers.gce.GCEFailedNode):
- try:
- n = gce.ex_get_node(n.name, lc_zone)
- except ResourceNotFoundError:
- pass
- else:
- # Assure that at least one node has been created to set changed=True
- changed = True
- new_instances.append(n)
- else:
- for instance in instance_names:
- pd = None
- if lc_disks:
- pd = lc_disks[0]
- elif persistent_boot_disk:
- try:
- pd = gce.ex_get_volume("%s" % instance, lc_zone)
- except ResourceNotFoundError:
- pd = gce.create_volume(disk_size, "%s" % instance, image=lc_image())
- gce_args['ex_boot_disk'] = pd
-
- inst = None
- try:
- inst = gce.ex_get_node(instance, lc_zone)
- except ResourceNotFoundError:
- inst = gce.create_node(
- instance, lc_machine_type, lc_image(), **gce_args
- )
- changed = True
- except GoogleBaseError as e:
- module.fail_json(msg='Unexpected error attempting to create ' +
- 'instance %s, error: %s' % (instance, e.value))
- if inst:
- new_instances.append(inst)
-
- for inst in new_instances:
- for i, lc_disk in enumerate(lc_disks):
- # Check whether the disk is already attached
- if (len(inst.extra['disks']) > i):
- attached_disk = inst.extra['disks'][i]
- if attached_disk['source'] != lc_disk.extra['selfLink']:
- module.fail_json(
- msg=("Disk at index %d does not match: requested=%s found=%s" % (
- i, lc_disk.extra['selfLink'], attached_disk['source'])))
- elif attached_disk['mode'] != disk_modes[i]:
- module.fail_json(
- msg=("Disk at index %d is in the wrong mode: requested=%s found=%s" % (
- i, disk_modes[i], attached_disk['mode'])))
- else:
- continue
- gce.attach_volume(inst, lc_disk, ex_mode=disk_modes[i])
- # Work around libcloud bug: attached volumes don't get added
- # to the instance metadata. get_instance_info() only cares about
- # source and index.
- if len(inst.extra['disks']) != i + 1:
- inst.extra['disks'].append(
- {'source': lc_disk.extra['selfLink'], 'index': i})
-
- instance_names = []
- instance_json_data = []
- for inst in new_instances:
- d = get_instance_info(inst)
- instance_names.append(d['name'])
- instance_json_data.append(d)
-
- return (changed, instance_json_data, instance_names)
-
-
-def change_instance_state(module, gce, instance_names, number, zone, state):
- """Changes the state of a list of instances. For example,
- change from started to stopped, or started to absent.
-
- module: Ansible module object
- gce: authenticated GCE connection object
- instance_names: a list of instance names to terminate
- zone: GCEZone object where the instances reside prior to termination
- state: 'state' parameter passed into module as argument
-
- Returns a dictionary of instance names that were changed.
-
- """
- changed = False
- nodes = []
- state_instance_names = []
-
- if isinstance(instance_names, str) and number:
- node_names = ['%s-%03d' % (instance_names, i) for i in range(number)]
- elif isinstance(instance_names, str) and not number:
- node_names = [instance_names]
- else:
- node_names = instance_names
-
- for name in node_names:
- inst = None
- try:
- inst = gce.ex_get_node(name, zone)
- except ResourceNotFoundError:
- state_instance_names.append(name)
- except Exception as e:
- module.fail_json(msg=unexpected_error_msg(e), changed=False)
- else:
- nodes.append(inst)
- state_instance_names.append(name)
-
- if state in ['absent', 'deleted'] and number:
- changed_nodes = gce.ex_destroy_multiple_nodes(nodes) or [False]
- changed = reduce(lambda x, y: x or y, changed_nodes)
- else:
- for node in nodes:
- if state in ['absent', 'deleted']:
- gce.destroy_node(node)
- changed = True
- elif state == 'started' and node.state == libcloud.compute.types.NodeState.STOPPED:
- gce.ex_start_node(node)
- changed = True
- elif state in ['stopped', 'terminated'] and node.state == libcloud.compute.types.NodeState.RUNNING:
- gce.ex_stop_node(node)
- changed = True
-
- return (changed, state_instance_names)
-
-
-def main():
- module = AnsibleModule(
- argument_spec=dict(
- image=dict(default='debian-8'),
- image_family=dict(),
- external_projects=dict(type='list'),
- instance_names=dict(),
- machine_type=dict(default='n1-standard-1'),
- metadata=dict(),
- name=dict(aliases=['base_name']),
- num_instances=dict(type='int'),
- network=dict(default='default'),
- subnetwork=dict(),
- persistent_boot_disk=dict(type='bool', default=False),
- disks=dict(type='list'),
- state=dict(choices=['active', 'present', 'absent', 'deleted',
- 'started', 'stopped', 'terminated'],
- default='present'),
- tags=dict(type='list'),
- zone=dict(default='us-central1-a'),
- service_account_email=dict(),
- service_account_permissions=dict(type='list'),
- pem_file=dict(type='path'),
- credentials_file=dict(type='path'),
- project_id=dict(),
- ip_forward=dict(type='bool', default=False),
- external_ip=dict(default='ephemeral'),
- disk_auto_delete=dict(type='bool', default=True),
- disk_size=dict(type='int', default=10),
- preemptible=dict(type='bool', default=None),
- ),
- mutually_exclusive=[('instance_names', 'name')]
- )
-
- if not HAS_PYTHON26:
- module.fail_json(msg="GCE module requires python's 'ast' module, python v2.6+")
- if not HAS_LIBCLOUD:
- module.fail_json(msg='libcloud with GCE support (0.17.0+) required for this module')
-
- gce = gce_connect(module)
-
- image = module.params.get('image')
- image_family = module.params.get('image_family')
- external_projects = module.params.get('external_projects')
- instance_names = module.params.get('instance_names')
- name = module.params.get('name')
- number = module.params.get('num_instances')
- subnetwork = module.params.get('subnetwork')
- state = module.params.get('state')
- zone = module.params.get('zone')
- preemptible = module.params.get('preemptible')
- changed = False
-
- inames = None
- if isinstance(instance_names, list):
- inames = instance_names
- elif isinstance(instance_names, str):
- inames = instance_names.split(',')
- if name:
- inames = name
- if not inames:
- module.fail_json(msg='Must specify a "name" or "instance_names"',
- changed=False)
- if not zone:
- module.fail_json(msg='Must specify a "zone"', changed=False)
-
- lc_zone = get_valid_location(module, gce, zone)
- if preemptible is not None and hasattr(libcloud, '__version__') and libcloud.__version__ < '0.20':
- module.fail_json(msg="Apache Libcloud 0.20.0+ is required to use 'preemptible' option",
- changed=False)
-
- if subnetwork is not None and not hasattr(gce, 'ex_get_subnetwork'):
- module.fail_json(msg="Apache Libcloud 1.0.0+ is required to use 'subnetwork' option",
- changed=False)
-
- json_output = {'zone': zone}
- if state in ['absent', 'deleted', 'started', 'stopped', 'terminated']:
- json_output['state'] = state
- (changed, state_instance_names) = change_instance_state(
- module, gce, inames, number, lc_zone, state)
-
- # based on what user specified, return the same variable, although
- # value could be different if an instance could not be destroyed
- if instance_names or name and number:
- json_output['instance_names'] = state_instance_names
- elif name:
- json_output['name'] = name
-
- elif state in ['active', 'present']:
- json_output['state'] = 'present'
- (changed, instance_data, instance_name_list) = create_instances(
- module, gce, inames, number, lc_zone)
- json_output['instance_data'] = instance_data
- if instance_names:
- json_output['instance_names'] = instance_name_list
- elif name:
- json_output['name'] = name
-
- json_output['changed'] = changed
- module.exit_json(**json_output)
-
-
-class LazyDiskImage:
- """
- Object for lazy instantiation of disk image
- gce.ex_get_image is a very expensive call, so we want to avoid calling it as much as possible.
- """
-
- def __init__(self, module, gce, name, has_pd, family=None, projects=None):
- self.image = None
- self.was_called = False
- self.gce = gce
- self.name = name
- self.has_pd = has_pd
- self.module = module
- self.family = family
- self.projects = projects
-
- def __call__(self):
- if not self.was_called:
- self.was_called = True
- if not self.has_pd:
- if self.family:
- self.image = self.gce.ex_get_image_from_family(self.family, ex_project_list=self.projects)
- else:
- self.image = self.gce.ex_get_image(self.name, ex_project_list=self.projects)
- if not self.image:
- self.module.fail_json(msg='image or disks missing for create instance', changed=False)
- return self.image
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/cloud/google/_gcp_backend_service.py b/lib/ansible/modules/cloud/google/_gcp_backend_service.py
deleted file mode 100644
index 809395a104..0000000000
--- a/lib/ansible/modules/cloud/google/_gcp_backend_service.py
+++ /dev/null
@@ -1,404 +0,0 @@
-#!/usr/bin/python
-# Copyright 2017 Google Inc.
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['deprecated'],
- 'supported_by': 'community'}
-DOCUMENTATION = '''
-module: gcp_backend_service
-version_added: "2.4"
-short_description: Create or Destroy a Backend Service.
-description:
- - Create or Destroy a Backend Service. See
- U(https://cloud.google.com/compute/docs/load-balancing/http/backend-service) for an overview.
- Full install/configuration instructions for the Google Cloud modules can
- be found in the comments of ansible/test/gce_tests.py.
-requirements:
- - "python >= 2.6"
- - "apache-libcloud >= 1.3.0"
-notes:
- - Update is not currently supported.
- - Only global backend services are currently supported. Regional backends not currently supported.
- - Internal load balancing not currently supported.
-deprecated:
- removed_in: "2.12"
- why: Updated modules released with increased functionality
- alternative: Use M(gcp_compute_backend_service) instead.
-author:
- - "Tom Melendez (@supertom) <tom@supertom.com>"
-options:
- backend_service_name:
- description:
- - Name of the Backend Service.
- required: true
- backends:
- description:
- - List of backends that make up the backend service. A backend is made up of
- an instance group and optionally several other parameters. See
- U(https://cloud.google.com/compute/docs/reference/latest/backendServices)
- for details.
- required: true
- healthchecks:
- description:
- - List of healthchecks. Only one healthcheck is supported.
- required: true
- enable_cdn:
- description:
- - If true, enable Cloud CDN for this Backend Service.
- type: bool
- port_name:
- description:
- - Name of the port on the managed instance group (MIG) that backend
- services can forward data to. Required for external load balancing.
- protocol:
- description:
- - The protocol this Backend Service uses to communicate with backends.
- Possible values are HTTP, HTTPS, TCP, and SSL. The default is HTTP.
- required: false
- timeout:
- description:
- - How many seconds to wait for the backend before considering it a failed
- request. Default is 30 seconds. Valid range is 1-86400.
- required: false
- service_account_email:
- description:
- - Service account email
- credentials_file:
- description:
- - Path to the JSON file associated with the service account email.
- project_id:
- description:
- - GCE project ID.
- state:
- description:
- - Desired state of the resource
- default: "present"
- choices: ["absent", "present"]
-'''
-
-EXAMPLES = '''
-- name: Create Minimum Backend Service
- gcp_backend_service:
- service_account_email: "{{ service_account_email }}"
- credentials_file: "{{ credentials_file }}"
- project_id: "{{ project_id }}"
- backend_service_name: "{{ bes }}"
- backends:
- - instance_group: managed_instance_group_1
- healthchecks:
- - healthcheck_name_for_backend_service
- port_name: myhttpport
- state: present
-
-- name: Create BES with extended backend parameters
- gcp_backend_service:
- service_account_email: "{{ service_account_email }}"
- credentials_file: "{{ credentials_file }}"
- project_id: "{{ project_id }}"
- backend_service_name: "{{ bes }}"
- backends:
- - instance_group: managed_instance_group_1
- max_utilization: 0.6
- max_rate: 10
- - instance_group: managed_instance_group_2
- max_utilization: 0.5
- max_rate: 4
- healthchecks:
- - healthcheck_name_for_backend_service
- port_name: myhttpport
- state: present
- timeout: 60
-'''
-
-RETURN = '''
-backend_service_created:
- description: Indicator Backend Service was created.
- returned: When a Backend Service is created.
- type: bool
- sample: "True"
-backend_service_deleted:
- description: Indicator Backend Service was deleted.
- returned: When a Backend Service is deleted.
- type: bool
- sample: "True"
-backend_service_name:
- description: Name of the Backend Service.
- returned: Always.
- type: str
- sample: "my-backend-service"
-backends:
- description: List of backends (comprised of instance_group) that
- make up a Backend Service.
- returned: When a Backend Service exists.
- type: list
- sample: "[ { 'instance_group': 'mig_one', 'zone': 'us-central1-b'} ]"
-enable_cdn:
- description: If Cloud CDN is enabled. null if not set.
- returned: When a backend service exists.
- type: bool
- sample: "True"
-healthchecks:
- description: List of healthchecks applied to the Backend Service.
- returned: When a Backend Service exists.
- type: list
- sample: "[ 'my-healthcheck' ]"
-protocol:
- description: Protocol used to communicate with the Backends.
- returned: When a Backend Service exists.
- type: str
- sample: "HTTP"
-port_name:
- description: Name of Backend Port.
- returned: When a Backend Service exists.
- type: str
- sample: "myhttpport"
-timeout:
- description: In seconds, how long before a request sent to a backend is
- considered failed.
- returned: If specified.
- type: int
- sample: "myhttpport"
-'''
-
-try:
- from ast import literal_eval
- HAS_PYTHON26 = True
-except ImportError:
- HAS_PYTHON26 = False
-
-try:
- import libcloud
- from libcloud.compute.types import Provider
- from libcloud.compute.providers import get_driver
- from libcloud.common.google import GoogleBaseError, QuotaExceededError, \
- ResourceExistsError, ResourceInUseError, ResourceNotFoundError
- from libcloud.compute.drivers.gce import GCEAddress
- _ = Provider.GCE
- HAS_LIBCLOUD = True
-except ImportError:
- HAS_LIBCLOUD = False
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.gce import gce_connect
-from ansible.module_utils.gcp import check_params
-
-
-def _validate_params(params):
- """
- Validate backend_service params.
-
- This function calls _validate_backend_params to verify
- the backend-specific parameters.
-
- :param params: Ansible dictionary containing configuration.
- :type params: ``dict``
-
- :return: True or raises ValueError
- :rtype: ``bool`` or `class:ValueError`
- """
- fields = [
- {'name': 'timeout', 'type': int, 'min': 1, 'max': 86400},
- ]
- try:
- check_params(params, fields)
- _validate_backend_params(params['backends'])
- except Exception:
- raise
-
- return (True, '')
-
-
-def _validate_backend_params(backends):
- """
- Validate configuration for backends.
-
- :param backends: Ansible dictionary containing backends configuration (only).
- :type backends: ``dict``
-
- :return: True or raises ValueError
- :rtype: ``bool`` or `class:ValueError`
- """
- fields = [
- {'name': 'balancing_mode', 'type': str, 'values': ['UTILIZATION', 'RATE', 'CONNECTION']},
- {'name': 'max_utilization', 'type': float},
- {'name': 'max_connections', 'type': int},
- {'name': 'max_rate', 'type': int},
- {'name': 'max_rate_per_instance', 'type': float},
- ]
-
- if not backends:
- raise ValueError('backends should be a list.')
-
- for backend in backends:
- try:
- check_params(backend, fields)
- except Exception:
- raise
-
- if 'max_rate' in backend and 'max_rate_per_instance' in backend:
- raise ValueError('Both maxRate or maxRatePerInstance cannot be set.')
-
- return (True, '')
-
-
-def get_backend_service(gce, name):
- """
- Get a Backend Service from GCE.
-
- :param gce: An initialized GCE driver object.
- :type gce: :class: `GCENodeDriver`
-
- :param name: Name of the Backend Service.
- :type name: ``str``
-
- :return: A GCEBackendService object or None.
- :rtype: :class: `GCEBackendService` or None
- """
- try:
- # Does the Backend Service already exist?
- return gce.ex_get_backendservice(name=name)
-
- except ResourceNotFoundError:
- return None
-
-
-def get_healthcheck(gce, name):
- return gce.ex_get_healthcheck(name)
-
-
-def get_instancegroup(gce, name, zone=None):
- return gce.ex_get_instancegroup(name=name, zone=zone)
-
-
-def create_backend_service(gce, params):
- """
- Create a new Backend Service.
-
- :param gce: An initialized GCE driver object.
- :type gce: :class: `GCENodeDriver`
-
- :param params: Dictionary of parameters needed by the module.
- :type params: ``dict``
-
- :return: Tuple with changed stats
- :rtype: tuple in the format of (bool, bool)
- """
- from copy import deepcopy
-
- changed = False
- return_data = False
- # only one healthcheck is currently supported
- hc_name = params['healthchecks'][0]
- hc = get_healthcheck(gce, hc_name)
- backends = []
- for backend in params['backends']:
- ig = get_instancegroup(gce, backend['instance_group'],
- backend.get('zone', None))
- kwargs = deepcopy(backend)
- kwargs['instance_group'] = ig
- backends.append(gce.ex_create_backend(
- **kwargs))
-
- bes = gce.ex_create_backendservice(
- name=params['backend_service_name'], healthchecks=[hc], backends=backends,
- enable_cdn=params['enable_cdn'], port_name=params['port_name'],
- timeout_sec=params['timeout'], protocol=params['protocol'])
-
- if bes:
- changed = True
- return_data = True
-
- return (changed, return_data)
-
-
-def delete_backend_service(bes):
- """
- Delete a Backend Service. The Instance Groups are NOT destroyed.
- """
- changed = False
- return_data = False
- if bes.destroy():
- changed = True
- return_data = True
- return (changed, return_data)
-
-
-def main():
- module = AnsibleModule(argument_spec=dict(
- backends=dict(type='list', required=True),
- backend_service_name=dict(required=True),
- healthchecks=dict(type='list', required=True),
- service_account_email=dict(),
- service_account_permissions=dict(type='list'),
- enable_cdn=dict(type='bool'),
- port_name=dict(type='str'),
- protocol=dict(type='str', default='TCP',
- choices=['HTTP', 'HTTPS', 'SSL', 'TCP']),
- timeout=dict(type='int'),
- state=dict(choices=['absent', 'present'], default='present'),
- pem_file=dict(),
- credentials_file=dict(),
- project_id=dict(), ), )
-
- if not HAS_PYTHON26:
- module.fail_json(
- msg="GCE module requires python's 'ast' module, python v2.6+")
- if not HAS_LIBCLOUD:
- module.fail_json(
- msg='libcloud with GCE Backend Service support (1.3+) required for this module.')
-
- gce = gce_connect(module)
- if not hasattr(gce, 'ex_create_instancegroupmanager'):
- module.fail_json(
- msg='libcloud with GCE Backend Service support (1.3+) required for this module.',
- changed=False)
-
- params = {}
- params['state'] = module.params.get('state')
- params['backend_service_name'] = module.params.get('backend_service_name')
- params['backends'] = module.params.get('backends')
- params['healthchecks'] = module.params.get('healthchecks')
- params['enable_cdn'] = module.params.get('enable_cdn', None)
- params['port_name'] = module.params.get('port_name', None)
- params['protocol'] = module.params.get('protocol', None)
- params['timeout'] = module.params.get('timeout', None)
-
- try:
- _validate_params(params)
- except Exception as e:
- module.fail_json(msg=e.message, changed=False)
-
- changed = False
- json_output = {'state': params['state']}
- bes = get_backend_service(gce, params['backend_service_name'])
-
- if not bes:
- if params['state'] == 'absent':
- # Doesn't exist and state==absent.
- changed = False
- module.fail_json(
- msg="Cannot delete unknown backend service: %s" %
- (params['backend_service_name']))
- else:
- # Create
- (changed, json_output['backend_service_created']) = create_backend_service(gce,
- params)
- elif params['state'] == 'absent':
- # Delete
- (changed, json_output['backend_service_deleted']) = delete_backend_service(bes)
- else:
- # TODO(supertom): Add update support when it is available in libcloud.
- changed = False
-
- json_output['changed'] = changed
- json_output.update(params)
- module.exit_json(**json_output)
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/cloud/google/_gcp_bigquery_dataset_facts.py b/lib/ansible/modules/cloud/google/_gcp_bigquery_dataset_facts.py
deleted file mode 120000
index 048b511508..0000000000
--- a/lib/ansible/modules/cloud/google/_gcp_bigquery_dataset_facts.py
+++ /dev/null
@@ -1 +0,0 @@
-gcp_bigquery_dataset_info.py \ No newline at end of file
diff --git a/lib/ansible/modules/cloud/google/_gcp_bigquery_table_facts.py b/lib/ansible/modules/cloud/google/_gcp_bigquery_table_facts.py
deleted file mode 120000
index 289c79bcfe..0000000000
--- a/lib/ansible/modules/cloud/google/_gcp_bigquery_table_facts.py
+++ /dev/null
@@ -1 +0,0 @@
-gcp_bigquery_table_info.py \ No newline at end of file
diff --git a/lib/ansible/modules/cloud/google/_gcp_cloudbuild_trigger_facts.py b/lib/ansible/modules/cloud/google/_gcp_cloudbuild_trigger_facts.py
deleted file mode 120000
index 66c2c93f2c..0000000000
--- a/lib/ansible/modules/cloud/google/_gcp_cloudbuild_trigger_facts.py
+++ /dev/null
@@ -1 +0,0 @@
-gcp_cloudbuild_trigger_info.py \ No newline at end of file
diff --git a/lib/ansible/modules/cloud/google/_gcp_compute_address_facts.py b/lib/ansible/modules/cloud/google/_gcp_compute_address_facts.py
deleted file mode 120000
index d12b7e4d49..0000000000
--- a/lib/ansible/modules/cloud/google/_gcp_compute_address_facts.py
+++ /dev/null
@@ -1 +0,0 @@
-gcp_compute_address_info.py \ No newline at end of file
diff --git a/lib/ansible/modules/cloud/google/_gcp_compute_backend_bucket_facts.py b/lib/ansible/modules/cloud/google/_gcp_compute_backend_bucket_facts.py
deleted file mode 120000
index d80cf8b0ae..0000000000
--- a/lib/ansible/modules/cloud/google/_gcp_compute_backend_bucket_facts.py
+++ /dev/null
@@ -1 +0,0 @@
-gcp_compute_backend_bucket_info.py \ No newline at end of file
diff --git a/lib/ansible/modules/cloud/google/_gcp_compute_backend_service_facts.py b/lib/ansible/modules/cloud/google/_gcp_compute_backend_service_facts.py
deleted file mode 120000
index def0ed0e6f..0000000000
--- a/lib/ansible/modules/cloud/google/_gcp_compute_backend_service_facts.py
+++ /dev/null
@@ -1 +0,0 @@
-gcp_compute_backend_service_info.py \ No newline at end of file
diff --git a/lib/ansible/modules/cloud/google/_gcp_compute_disk_facts.py b/lib/ansible/modules/cloud/google/_gcp_compute_disk_facts.py
deleted file mode 120000
index 52aabea81a..0000000000
--- a/lib/ansible/modules/cloud/google/_gcp_compute_disk_facts.py
+++ /dev/null
@@ -1 +0,0 @@
-gcp_compute_disk_info.py \ No newline at end of file
diff --git a/lib/ansible/modules/cloud/google/_gcp_compute_firewall_facts.py b/lib/ansible/modules/cloud/google/_gcp_compute_firewall_facts.py
deleted file mode 120000
index 7a8ccaa415..0000000000
--- a/lib/ansible/modules/cloud/google/_gcp_compute_firewall_facts.py
+++ /dev/null
@@ -1 +0,0 @@
-gcp_compute_firewall_info.py \ No newline at end of file
diff --git a/lib/ansible/modules/cloud/google/_gcp_compute_forwarding_rule_facts.py b/lib/ansible/modules/cloud/google/_gcp_compute_forwarding_rule_facts.py
deleted file mode 120000
index 4f09197451..0000000000
--- a/lib/ansible/modules/cloud/google/_gcp_compute_forwarding_rule_facts.py
+++ /dev/null
@@ -1 +0,0 @@
-gcp_compute_forwarding_rule_info.py \ No newline at end of file
diff --git a/lib/ansible/modules/cloud/google/_gcp_compute_global_address_facts.py b/lib/ansible/modules/cloud/google/_gcp_compute_global_address_facts.py
deleted file mode 120000
index 497372674a..0000000000
--- a/lib/ansible/modules/cloud/google/_gcp_compute_global_address_facts.py
+++ /dev/null
@@ -1 +0,0 @@
-gcp_compute_global_address_info.py \ No newline at end of file
diff --git a/lib/ansible/modules/cloud/google/_gcp_compute_global_forwarding_rule_facts.py b/lib/ansible/modules/cloud/google/_gcp_compute_global_forwarding_rule_facts.py
deleted file mode 120000
index 18d0b3b5db..0000000000
--- a/lib/ansible/modules/cloud/google/_gcp_compute_global_forwarding_rule_facts.py
+++ /dev/null
@@ -1 +0,0 @@
-gcp_compute_global_forwarding_rule_info.py \ No newline at end of file
diff --git a/lib/ansible/modules/cloud/google/_gcp_compute_health_check_facts.py b/lib/ansible/modules/cloud/google/_gcp_compute_health_check_facts.py
deleted file mode 120000
index a2646a6c8d..0000000000
--- a/lib/ansible/modules/cloud/google/_gcp_compute_health_check_facts.py
+++ /dev/null
@@ -1 +0,0 @@
-gcp_compute_health_check_info.py \ No newline at end of file
diff --git a/lib/ansible/modules/cloud/google/_gcp_compute_http_health_check_facts.py b/lib/ansible/modules/cloud/google/_gcp_compute_http_health_check_facts.py
deleted file mode 120000
index dbf679c115..0000000000
--- a/lib/ansible/modules/cloud/google/_gcp_compute_http_health_check_facts.py
+++ /dev/null
@@ -1 +0,0 @@
-gcp_compute_http_health_check_info.py \ No newline at end of file
diff --git a/lib/ansible/modules/cloud/google/_gcp_compute_https_health_check_facts.py b/lib/ansible/modules/cloud/google/_gcp_compute_https_health_check_facts.py
deleted file mode 120000
index 887a5ffe68..0000000000
--- a/lib/ansible/modules/cloud/google/_gcp_compute_https_health_check_facts.py
+++ /dev/null
@@ -1 +0,0 @@
-gcp_compute_https_health_check_info.py \ No newline at end of file
diff --git a/lib/ansible/modules/cloud/google/_gcp_compute_image_facts.py b/lib/ansible/modules/cloud/google/_gcp_compute_image_facts.py
deleted file mode 120000
index f4ca4647ec..0000000000
--- a/lib/ansible/modules/cloud/google/_gcp_compute_image_facts.py
+++ /dev/null
@@ -1 +0,0 @@
-gcp_compute_image_info.py \ No newline at end of file
diff --git a/lib/ansible/modules/cloud/google/_gcp_compute_instance_facts.py b/lib/ansible/modules/cloud/google/_gcp_compute_instance_facts.py
deleted file mode 120000
index b886b91c69..0000000000
--- a/lib/ansible/modules/cloud/google/_gcp_compute_instance_facts.py
+++ /dev/null
@@ -1 +0,0 @@
-gcp_compute_instance_info.py \ No newline at end of file
diff --git a/lib/ansible/modules/cloud/google/_gcp_compute_instance_group_facts.py b/lib/ansible/modules/cloud/google/_gcp_compute_instance_group_facts.py
deleted file mode 120000
index 8703aff9e8..0000000000
--- a/lib/ansible/modules/cloud/google/_gcp_compute_instance_group_facts.py
+++ /dev/null
@@ -1 +0,0 @@
-gcp_compute_instance_group_info.py \ No newline at end of file
diff --git a/lib/ansible/modules/cloud/google/_gcp_compute_instance_group_manager_facts.py b/lib/ansible/modules/cloud/google/_gcp_compute_instance_group_manager_facts.py
deleted file mode 120000
index 2b9ec76192..0000000000
--- a/lib/ansible/modules/cloud/google/_gcp_compute_instance_group_manager_facts.py
+++ /dev/null
@@ -1 +0,0 @@
-gcp_compute_instance_group_manager_info.py \ No newline at end of file
diff --git a/lib/ansible/modules/cloud/google/_gcp_compute_instance_template_facts.py b/lib/ansible/modules/cloud/google/_gcp_compute_instance_template_facts.py
deleted file mode 120000
index a9826ba8f1..0000000000
--- a/lib/ansible/modules/cloud/google/_gcp_compute_instance_template_facts.py
+++ /dev/null
@@ -1 +0,0 @@
-gcp_compute_instance_template_info.py \ No newline at end of file
diff --git a/lib/ansible/modules/cloud/google/_gcp_compute_interconnect_attachment_facts.py b/lib/ansible/modules/cloud/google/_gcp_compute_interconnect_attachment_facts.py
deleted file mode 120000
index 479308d6e7..0000000000
--- a/lib/ansible/modules/cloud/google/_gcp_compute_interconnect_attachment_facts.py
+++ /dev/null
@@ -1 +0,0 @@
-gcp_compute_interconnect_attachment_info.py \ No newline at end of file
diff --git a/lib/ansible/modules/cloud/google/_gcp_compute_network_facts.py b/lib/ansible/modules/cloud/google/_gcp_compute_network_facts.py
deleted file mode 120000
index c2e964a21d..0000000000
--- a/lib/ansible/modules/cloud/google/_gcp_compute_network_facts.py
+++ /dev/null
@@ -1 +0,0 @@
-gcp_compute_network_info.py \ No newline at end of file
diff --git a/lib/ansible/modules/cloud/google/_gcp_compute_region_disk_facts.py b/lib/ansible/modules/cloud/google/_gcp_compute_region_disk_facts.py
deleted file mode 120000
index 1dbc112907..0000000000
--- a/lib/ansible/modules/cloud/google/_gcp_compute_region_disk_facts.py
+++ /dev/null
@@ -1 +0,0 @@
-gcp_compute_region_disk_info.py \ No newline at end of file
diff --git a/lib/ansible/modules/cloud/google/_gcp_compute_route_facts.py b/lib/ansible/modules/cloud/google/_gcp_compute_route_facts.py
deleted file mode 120000
index 33dccb6671..0000000000
--- a/lib/ansible/modules/cloud/google/_gcp_compute_route_facts.py
+++ /dev/null
@@ -1 +0,0 @@
-gcp_compute_route_info.py \ No newline at end of file
diff --git a/lib/ansible/modules/cloud/google/_gcp_compute_router_facts.py b/lib/ansible/modules/cloud/google/_gcp_compute_router_facts.py
deleted file mode 120000
index 00498a1b87..0000000000
--- a/lib/ansible/modules/cloud/google/_gcp_compute_router_facts.py
+++ /dev/null
@@ -1 +0,0 @@
-gcp_compute_router_info.py \ No newline at end of file
diff --git a/lib/ansible/modules/cloud/google/_gcp_compute_ssl_certificate_facts.py b/lib/ansible/modules/cloud/google/_gcp_compute_ssl_certificate_facts.py
deleted file mode 120000
index 188f2878a9..0000000000
--- a/lib/ansible/modules/cloud/google/_gcp_compute_ssl_certificate_facts.py
+++ /dev/null
@@ -1 +0,0 @@
-gcp_compute_ssl_certificate_info.py \ No newline at end of file
diff --git a/lib/ansible/modules/cloud/google/_gcp_compute_ssl_policy_facts.py b/lib/ansible/modules/cloud/google/_gcp_compute_ssl_policy_facts.py
deleted file mode 120000
index 2e64eb7d47..0000000000
--- a/lib/ansible/modules/cloud/google/_gcp_compute_ssl_policy_facts.py
+++ /dev/null
@@ -1 +0,0 @@
-gcp_compute_ssl_policy_info.py \ No newline at end of file
diff --git a/lib/ansible/modules/cloud/google/_gcp_compute_subnetwork_facts.py b/lib/ansible/modules/cloud/google/_gcp_compute_subnetwork_facts.py
deleted file mode 120000
index dc4a73ad54..0000000000
--- a/lib/ansible/modules/cloud/google/_gcp_compute_subnetwork_facts.py
+++ /dev/null
@@ -1 +0,0 @@
-gcp_compute_subnetwork_info.py \ No newline at end of file
diff --git a/lib/ansible/modules/cloud/google/_gcp_compute_target_http_proxy_facts.py b/lib/ansible/modules/cloud/google/_gcp_compute_target_http_proxy_facts.py
deleted file mode 120000
index 628457e100..0000000000
--- a/lib/ansible/modules/cloud/google/_gcp_compute_target_http_proxy_facts.py
+++ /dev/null
@@ -1 +0,0 @@
-gcp_compute_target_http_proxy_info.py \ No newline at end of file
diff --git a/lib/ansible/modules/cloud/google/_gcp_compute_target_https_proxy_facts.py b/lib/ansible/modules/cloud/google/_gcp_compute_target_https_proxy_facts.py
deleted file mode 120000
index 9b6beebab5..0000000000
--- a/lib/ansible/modules/cloud/google/_gcp_compute_target_https_proxy_facts.py
+++ /dev/null
@@ -1 +0,0 @@
-gcp_compute_target_https_proxy_info.py \ No newline at end of file
diff --git a/lib/ansible/modules/cloud/google/_gcp_compute_target_pool_facts.py b/lib/ansible/modules/cloud/google/_gcp_compute_target_pool_facts.py
deleted file mode 120000
index e3583a7239..0000000000
--- a/lib/ansible/modules/cloud/google/_gcp_compute_target_pool_facts.py
+++ /dev/null
@@ -1 +0,0 @@
-gcp_compute_target_pool_info.py \ No newline at end of file
diff --git a/lib/ansible/modules/cloud/google/_gcp_compute_target_ssl_proxy_facts.py b/lib/ansible/modules/cloud/google/_gcp_compute_target_ssl_proxy_facts.py
deleted file mode 120000
index 6f82c12ab5..0000000000
--- a/lib/ansible/modules/cloud/google/_gcp_compute_target_ssl_proxy_facts.py
+++ /dev/null
@@ -1 +0,0 @@
-gcp_compute_target_ssl_proxy_info.py \ No newline at end of file
diff --git a/lib/ansible/modules/cloud/google/_gcp_compute_target_tcp_proxy_facts.py b/lib/ansible/modules/cloud/google/_gcp_compute_target_tcp_proxy_facts.py
deleted file mode 120000
index 551871b74e..0000000000
--- a/lib/ansible/modules/cloud/google/_gcp_compute_target_tcp_proxy_facts.py
+++ /dev/null
@@ -1 +0,0 @@
-gcp_compute_target_tcp_proxy_info.py \ No newline at end of file
diff --git a/lib/ansible/modules/cloud/google/_gcp_compute_target_vpn_gateway_facts.py b/lib/ansible/modules/cloud/google/_gcp_compute_target_vpn_gateway_facts.py
deleted file mode 120000
index 72c072765a..0000000000
--- a/lib/ansible/modules/cloud/google/_gcp_compute_target_vpn_gateway_facts.py
+++ /dev/null
@@ -1 +0,0 @@
-gcp_compute_target_vpn_gateway_info.py \ No newline at end of file
diff --git a/lib/ansible/modules/cloud/google/_gcp_compute_url_map_facts.py b/lib/ansible/modules/cloud/google/_gcp_compute_url_map_facts.py
deleted file mode 120000
index e8046ebc54..0000000000
--- a/lib/ansible/modules/cloud/google/_gcp_compute_url_map_facts.py
+++ /dev/null
@@ -1 +0,0 @@
-gcp_compute_url_map_info.py \ No newline at end of file
diff --git a/lib/ansible/modules/cloud/google/_gcp_compute_vpn_tunnel_facts.py b/lib/ansible/modules/cloud/google/_gcp_compute_vpn_tunnel_facts.py
deleted file mode 120000
index 26de5596b8..0000000000
--- a/lib/ansible/modules/cloud/google/_gcp_compute_vpn_tunnel_facts.py
+++ /dev/null
@@ -1 +0,0 @@
-gcp_compute_vpn_tunnel_info.py \ No newline at end of file
diff --git a/lib/ansible/modules/cloud/google/_gcp_container_cluster_facts.py b/lib/ansible/modules/cloud/google/_gcp_container_cluster_facts.py
deleted file mode 120000
index 50b4ee8253..0000000000
--- a/lib/ansible/modules/cloud/google/_gcp_container_cluster_facts.py
+++ /dev/null
@@ -1 +0,0 @@
-gcp_container_cluster_info.py \ No newline at end of file
diff --git a/lib/ansible/modules/cloud/google/_gcp_container_node_pool_facts.py b/lib/ansible/modules/cloud/google/_gcp_container_node_pool_facts.py
deleted file mode 120000
index 2b73f3c477..0000000000
--- a/lib/ansible/modules/cloud/google/_gcp_container_node_pool_facts.py
+++ /dev/null
@@ -1 +0,0 @@
-gcp_container_node_pool_info.py \ No newline at end of file
diff --git a/lib/ansible/modules/cloud/google/_gcp_dns_managed_zone_facts.py b/lib/ansible/modules/cloud/google/_gcp_dns_managed_zone_facts.py
deleted file mode 120000
index 08fc673ed2..0000000000
--- a/lib/ansible/modules/cloud/google/_gcp_dns_managed_zone_facts.py
+++ /dev/null
@@ -1 +0,0 @@
-gcp_dns_managed_zone_info.py \ No newline at end of file
diff --git a/lib/ansible/modules/cloud/google/_gcp_dns_resource_record_set_facts.py b/lib/ansible/modules/cloud/google/_gcp_dns_resource_record_set_facts.py
deleted file mode 120000
index 879f4b6344..0000000000
--- a/lib/ansible/modules/cloud/google/_gcp_dns_resource_record_set_facts.py
+++ /dev/null
@@ -1 +0,0 @@
-gcp_dns_resource_record_set_info.py \ No newline at end of file
diff --git a/lib/ansible/modules/cloud/google/_gcp_forwarding_rule.py b/lib/ansible/modules/cloud/google/_gcp_forwarding_rule.py
deleted file mode 100644
index a9c835578a..0000000000
--- a/lib/ansible/modules/cloud/google/_gcp_forwarding_rule.py
+++ /dev/null
@@ -1,355 +0,0 @@
-#!/usr/bin/python
-# Copyright 2017 Google Inc.
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['deprecated'],
- 'supported_by': 'community'}
-
-
-DOCUMENTATION = '''
----
-module: gcp_forwarding_rule
-version_added: "2.4"
-short_description: Create, Update or Destroy a Forwarding_Rule.
-description:
- - Create, Update or Destroy a Forwarding_Rule. See
- U(https://cloud.google.com/compute/docs/load-balancing/http/target-proxies) for an overview.
- More details on the Global Forwarding_Rule API can be found at
- U(https://cloud.google.com/compute/docs/reference/latest/globalForwardingRules)
- More details on the Forwarding Rules API can be found at
- U(https://cloud.google.com/compute/docs/reference/latest/forwardingRules)
-requirements:
- - "python >= 2.6"
- - "google-api-python-client >= 1.6.2"
- - "google-auth >= 0.9.0"
- - "google-auth-httplib2 >= 0.0.2"
-deprecated:
- removed_in: "2.12"
- why: Updated modules released with increased functionality
- alternative: Use M(gcp_compute_forwarding_rule) or M(gcp_compute_global_forwarding_rule) instead.
-notes:
- - Currently only supports global forwarding rules.
- As such, Load Balancing Scheme is always EXTERNAL.
-author:
- - "Tom Melendez (@supertom) <tom@supertom.com>"
-options:
- address:
- description:
- - IPv4 or named IP address. Must be of the same scope (regional, global).
- Reserved addresses can (and probably should) be used for global
- forwarding rules. You may reserve IPs from the console or
- via the gce_eip module.
- required: false
- forwarding_rule_name:
- description:
- - Name of the Forwarding_Rule.
- required: true
- port_range:
- description:
- - For global forwarding rules, must be set to 80 or 8080 for TargetHttpProxy, and
- 443 for TargetHttpsProxy or TargetSslProxy.
- required: false
- protocol:
- description:
- - For global forwarding rules, TCP, UDP, ESP, AH, SCTP or ICMP. Default is TCP.
- required: false
- region:
- description:
- - The region for this forwarding rule. Currently, only 'global' is supported.
- required: false
- state:
- description:
- - The state of the Forwarding Rule. 'present' or 'absent'
- required: true
- choices: ["present", "absent"]
- target:
- description:
- - Target resource for forwarding rule. For global proxy, this is a Global
- TargetProxy resource. Required for external load balancing (including Global load balancing)
- required: false
-'''
-
-EXAMPLES = '''
-- name: Create Minimum GLOBAL Forwarding_Rule
- gcp_forwarding_rule:
- service_account_email: "{{ service_account_email }}"
- credentials_file: "{{ credentials_file }}"
- project_id: "{{ project_id }}"
- forwarding_rule_name: my-forwarding_rule
- protocol: TCP
- port_range: 80
- region: global
- target: my-target-proxy
- state: present
-
-- name: Create Forwarding_Rule w/reserved static address
- gcp_forwarding_rule:
- service_account_email: "{{ service_account_email }}"
- credentials_file: "{{ credentials_file }}"
- project_id: "{{ project_id }}"
- forwarding_rule_name: my-forwarding_rule
- protocol: TCP
- port_range: 80
- address: my-reserved-static-address-name
- region: global
- target: my-target-proxy
- state: present
-'''
-
-RETURN = '''
-forwarding_rule_name:
- description: Name of the Forwarding_Rule
- returned: Always
- type: str
- sample: my-target-proxy
-forwarding_rule:
- description: GCP Forwarding_Rule dictionary
- returned: Always. Refer to GCP documentation for detailed field descriptions.
- type: dict
- sample: { "name": "my-forwarding_rule", "target": "..." }
-region:
- description: Region for Forwarding Rule.
- returned: Always
- type: bool
- sample: true
-state:
- description: state of the Forwarding_Rule
- returned: Always.
- type: str
- sample: present
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.gcp import get_google_api_client, GCPUtils
-
-
-USER_AGENT_PRODUCT = 'ansible-forwarding_rule'
-USER_AGENT_VERSION = '0.0.1'
-
-
-def _build_global_forwarding_rule_dict(params, project_id=None):
- """
- Reformat services in Ansible Params.
-
- :param params: Params from AnsibleModule object
- :type params: ``dict``
-
- :param project_id: The GCP project ID.
- :type project_id: ``str``
-
- :return: dictionary suitable for submission to GCP API.
- :rtype ``dict``
- """
- url = ''
- if project_id:
- url = GCPUtils.build_googleapi_url(project_id)
- gcp_dict = GCPUtils.params_to_gcp_dict(params, 'forwarding_rule_name')
- if 'target' in gcp_dict:
- gcp_dict['target'] = '%s/global/targetHttpProxies/%s' % (url,
- gcp_dict['target'])
- if 'address' in gcp_dict:
- gcp_dict['IPAddress'] = '%s/global/addresses/%s' % (url,
- gcp_dict['address'])
- del gcp_dict['address']
- if 'protocol' in gcp_dict:
- gcp_dict['IPProtocol'] = gcp_dict['protocol']
- del gcp_dict['protocol']
- return gcp_dict
-
-
-def get_global_forwarding_rule(client, name, project_id=None):
- """
- Get a Global Forwarding Rule from GCP.
-
- :param client: An initialized GCE Compute Discovery resource.
- :type client: :class: `googleapiclient.discovery.Resource`
-
- :param name: Name of the Global Forwarding Rule.
- :type name: ``str``
-
- :param project_id: The GCP project ID.
- :type project_id: ``str``
-
- :return: A dict resp from the respective GCP 'get' request.
- :rtype: ``dict``
- """
- try:
- req = client.globalForwardingRules().get(
- project=project_id, forwardingRule=name)
- return GCPUtils.execute_api_client_req(req, raise_404=False)
- except Exception:
- raise
-
-
-def create_global_forwarding_rule(client, params, project_id):
- """
- Create a new Global Forwarding Rule.
-
- :param client: An initialized GCE Compute Discovery resource.
- :type client: :class: `googleapiclient.discovery.Resource`
-
- :param params: Dictionary of arguments from AnsibleModule.
- :type params: ``dict``
-
- :return: Tuple with changed status and response dict
- :rtype: ``tuple`` in the format of (bool, dict)
- """
- gcp_dict = _build_global_forwarding_rule_dict(params, project_id)
- try:
- req = client.globalForwardingRules().insert(project=project_id, body=gcp_dict)
- return_data = GCPUtils.execute_api_client_req(req, client, raw=False)
- if not return_data:
- return_data = get_global_forwarding_rule(client,
- name=params['forwarding_rule_name'],
- project_id=project_id)
- return (True, return_data)
- except Exception:
- raise
-
-
-def delete_global_forwarding_rule(client, name, project_id):
- """
- Delete a Global Forwarding Rule.
-
- :param client: An initialized GCE Compute Discovery resource.
- :type client: :class: `googleapiclient.discovery.Resource`
-
- :param name: Name of the Target Proxy.
- :type name: ``str``
-
- :param project_id: The GCP project ID.
- :type project_id: ``str``
-
- :return: Tuple with changed status and response dict
- :rtype: ``tuple`` in the format of (bool, dict)
- """
- try:
- req = client.globalForwardingRules().delete(
- project=project_id, forwardingRule=name)
- return_data = GCPUtils.execute_api_client_req(req, client)
- return (True, return_data)
- except Exception:
- raise
-
-
-def update_global_forwarding_rule(client, forwarding_rule, params, name, project_id):
- """
- Update a Global Forwarding_Rule. Currently, only a target can be updated.
-
- If the forwarding_rule has not changed, the update will not occur.
-
- :param client: An initialized GCE Compute Discovery resource.
- :type client: :class: `googleapiclient.discovery.Resource`
-
- :param forwarding_rule: Name of the Target Proxy.
- :type forwarding_rule: ``dict``
-
- :param params: Dictionary of arguments from AnsibleModule.
- :type params: ``dict``
-
- :param name: Name of the Global Forwarding Rule.
- :type name: ``str``
-
- :param project_id: The GCP project ID.
- :type project_id: ``str``
-
- :return: Tuple with changed status and response dict
- :rtype: ``tuple`` in the format of (bool, dict)
- """
- gcp_dict = _build_global_forwarding_rule_dict(params, project_id)
-
- GCPUtils.are_params_equal(forwarding_rule, gcp_dict)
- if forwarding_rule['target'] == gcp_dict['target']:
- return (False, 'no update necessary')
-
- try:
- req = client.globalForwardingRules().setTarget(project=project_id,
- forwardingRule=name,
- body={'target': gcp_dict['target']})
- return_data = GCPUtils.execute_api_client_req(
- req, client=client, raw=False)
- return (True, return_data)
- except Exception:
- raise
-
-
-def main():
- module = AnsibleModule(argument_spec=dict(
- forwarding_rule_name=dict(required=True),
- region=dict(required=True),
- target=dict(required=False),
- address=dict(type='str', required=False),
- protocol=dict(required=False, default='TCP', choices=['TCP']),
- port_range=dict(required=False),
- load_balancing_scheme=dict(
- required=False, default='EXTERNAL', choices=['EXTERNAL']),
- state=dict(required=True, choices=['absent', 'present']),
- service_account_email=dict(),
- service_account_permissions=dict(type='list'),
- pem_file=dict(),
- credentials_file=dict(),
- project_id=dict(), ), )
-
- client, conn_params = get_google_api_client(module, 'compute', user_agent_product=USER_AGENT_PRODUCT,
- user_agent_version=USER_AGENT_VERSION)
-
- params = {}
- params['state'] = module.params.get('state')
- params['forwarding_rule_name'] = module.params.get('forwarding_rule_name')
- params['region'] = module.params.get('region')
- params['target'] = module.params.get('target', None)
- params['protocol'] = module.params.get('protocol', None)
- params['port_range'] = module.params.get('port_range')
- if module.params.get('address', None):
- params['address'] = module.params.get('address', None)
-
- if params['region'] != 'global':
- # This module currently doesn't support regional rules.
- module.fail_json(
- msg=("%s - Only global forwarding rules currently supported. "
- "Be sure to specify 'global' for the region option.") %
- (params['forwarding_rule_name']))
-
- changed = False
- json_output = {'state': params['state']}
- forwarding_rule = None
- if params['region'] == 'global':
- forwarding_rule = get_global_forwarding_rule(client,
- name=params['forwarding_rule_name'],
- project_id=conn_params['project_id'])
- if not forwarding_rule:
- if params['state'] == 'absent':
- # Doesn't exist in GCE, and state==absent.
- changed = False
- module.fail_json(
- msg="Cannot delete unknown forwarding_rule: %s" %
- (params['forwarding_rule_name']))
- else:
- # Create
- changed, json_output['forwarding_rule'] = create_global_forwarding_rule(client,
- params=params,
- project_id=conn_params['project_id'])
- elif params['state'] == 'absent':
- # Delete
- changed, json_output['forwarding_rule'] = delete_global_forwarding_rule(client,
- name=params['forwarding_rule_name'],
- project_id=conn_params['project_id'])
- else:
- changed, json_output['forwarding_rule'] = update_global_forwarding_rule(client,
- forwarding_rule=forwarding_rule,
- params=params,
- name=params['forwarding_rule_name'],
- project_id=conn_params['project_id'])
-
- json_output['changed'] = changed
- json_output.update(params)
- module.exit_json(**json_output)
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/cloud/google/_gcp_healthcheck.py b/lib/ansible/modules/cloud/google/_gcp_healthcheck.py
deleted file mode 100644
index 805e12db1b..0000000000
--- a/lib/ansible/modules/cloud/google/_gcp_healthcheck.py
+++ /dev/null
@@ -1,451 +0,0 @@
-#!/usr/bin/python
-# Copyright 2017 Google Inc.
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['deprecated'],
- 'supported_by': 'community'}
-
-
-DOCUMENTATION = '''
----
-module: gcp_healthcheck
-version_added: "2.4"
-short_description: Create, Update or Destroy a Healthcheck.
-description:
- - Create, Update or Destroy a Healthcheck. Currently only HTTP and
- HTTPS Healthchecks are supported. Healthchecks are used to monitor
- individual instances, managed instance groups and/or backend
- services. Healtchecks are reusable.
- - Visit
- U(https://cloud.google.com/compute/docs/load-balancing/health-checks)
- for an overview of Healthchecks on GCP.
- - See
- U(https://cloud.google.com/compute/docs/reference/latest/httpHealthChecks) for
- API details on HTTP Healthchecks.
- - See
- U(https://cloud.google.com/compute/docs/reference/latest/httpsHealthChecks)
- for more details on the HTTPS Healtcheck API.
-requirements:
- - "python >= 2.6"
- - "google-api-python-client >= 1.6.2"
- - "google-auth >= 0.9.0"
- - "google-auth-httplib2 >= 0.0.2"
-notes:
- - Only supports HTTP and HTTPS Healthchecks currently.
-deprecated:
- removed_in: "2.12"
- why: Updated modules released with increased functionality
- alternative: >
- Use M(gcp_compute_health_check), M(gcp_compute_http_health_check) or
- M(gcp_compute_https_health_check) instead.
-author:
- - "Tom Melendez (@supertom) <tom@supertom.com>"
-options:
- check_interval:
- description:
- - How often (in seconds) to send a health check.
- default: 5
- healthcheck_name:
- description:
- - Name of the Healthcheck.
- required: true
- healthcheck_type:
- description:
- - Type of Healthcheck.
- required: true
- choices: ["HTTP", "HTTPS"]
- host_header:
- description:
- - The value of the host header in the health check request. If left
- empty, the public IP on behalf of which this health
- check is performed will be used.
- required: true
- default: ""
- port:
- description:
- - The TCP port number for the health check request. The default value is
- 443 for HTTPS and 80 for HTTP.
- request_path:
- description:
- - The request path of the HTTPS health check request.
- required: false
- default: "/"
- state:
- description: State of the Healthcheck.
- required: true
- choices: ["present", "absent"]
- timeout:
- description:
- - How long (in seconds) to wait for a response before claiming
- failure. It is invalid for timeout
- to have a greater value than check_interval.
- default: 5
- unhealthy_threshold:
- description:
- - A so-far healthy instance will be marked unhealthy after this
- many consecutive failures.
- default: 2
- healthy_threshold:
- description:
- - A so-far unhealthy instance will be marked healthy after this
- many consecutive successes.
- default: 2
- service_account_email:
- description:
- - service account email
- service_account_permissions:
- version_added: "2.0"
- description:
- - service account permissions (see
- U(https://cloud.google.com/sdk/gcloud/reference/compute/instances/create),
- --scopes section for detailed information)
- choices: [
- "bigquery", "cloud-platform", "compute-ro", "compute-rw",
- "useraccounts-ro", "useraccounts-rw", "datastore", "logging-write",
- "monitoring", "sql-admin", "storage-full", "storage-ro",
- "storage-rw", "taskqueue", "userinfo-email"
- ]
- credentials_file:
- description:
- - Path to the JSON file associated with the service account email
- project_id:
- description:
- - Your GCP project ID
-'''
-
-EXAMPLES = '''
-- name: Create Minimum HealthCheck
- gcp_healthcheck:
- service_account_email: "{{ service_account_email }}"
- credentials_file: "{{ credentials_file }}"
- project_id: "{{ project_id }}"
- healthcheck_name: my-healthcheck
- healthcheck_type: HTTP
- state: present
-- name: Create HTTP HealthCheck
- gcp_healthcheck:
- service_account_email: "{{ service_account_email }}"
- credentials_file: "{{ credentials_file }}"
- project_id: "{{ project_id }}"
- healthcheck_name: my-healthcheck
- healthcheck_type: HTTP
- host: my-host
- request_path: /hc
- check_interval: 10
- timeout: 30
- unhealthy_threshhold: 2
- healthy_threshhold: 1
- state: present
-- name: Create HTTPS HealthCheck
- gcp_healthcheck:
- service_account_email: "{{ service_account_email }}"
- credentials_file: "{{ credentials_file }}"
- project_id: "{{ project_id }}"
- healthcheck_name: "{{ https_healthcheck }}"
- healthcheck_type: HTTPS
- host_header: my-host
- request_path: /hc
- check_interval: 5
- timeout: 5
- unhealthy_threshold: 2
- healthy_threshold: 1
- state: present
-'''
-
-RETURN = '''
-state:
- description: state of the Healthcheck
- returned: Always.
- type: str
- sample: present
-healthcheck_name:
- description: Name of the Healthcheck
- returned: Always
- type: str
- sample: my-url-map
-healthcheck_type:
- description: Type of the Healthcheck
- returned: Always
- type: str
- sample: HTTP
-healthcheck:
- description: GCP Healthcheck dictionary
- returned: Always. Refer to GCP documentation for detailed field descriptions.
- type: dict
- sample: { "name": "my-hc", "port": 443, "requestPath": "/foo" }
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.gcp import get_google_api_client, GCPUtils
-
-
-USER_AGENT_PRODUCT = 'ansible-healthcheck'
-USER_AGENT_VERSION = '0.0.1'
-
-
-def _validate_healthcheck_params(params):
- """
- Validate healthcheck params.
-
- Simple validation has already assumed by AnsibleModule.
-
- :param params: Ansible dictionary containing configuration.
- :type params: ``dict``
-
- :return: True or raises ValueError
- :rtype: ``bool`` or `class:ValueError`
- """
- if params['timeout'] > params['check_interval']:
- raise ValueError("timeout (%s) is greater than check_interval (%s)" % (
- params['timeout'], params['check_interval']))
-
- return (True, '')
-
-
-def _build_healthcheck_dict(params):
- """
- Reformat services in Ansible Params for GCP.
-
- :param params: Params from AnsibleModule object
- :type params: ``dict``
-
- :param project_id: The GCP project ID.
- :type project_id: ``str``
-
- :return: dictionary suitable for submission to GCP
- HealthCheck (HTTP/HTTPS) API.
- :rtype ``dict``
- """
- gcp_dict = GCPUtils.params_to_gcp_dict(params, 'healthcheck_name')
- if 'timeout' in gcp_dict:
- gcp_dict['timeoutSec'] = gcp_dict['timeout']
- del gcp_dict['timeout']
-
- if 'checkInterval' in gcp_dict:
- gcp_dict['checkIntervalSec'] = gcp_dict['checkInterval']
- del gcp_dict['checkInterval']
-
- if 'hostHeader' in gcp_dict:
- gcp_dict['host'] = gcp_dict['hostHeader']
- del gcp_dict['hostHeader']
-
- if 'healthcheckType' in gcp_dict:
- del gcp_dict['healthcheckType']
- return gcp_dict
-
-
-def _get_req_resource(client, resource_type):
- if resource_type == 'HTTPS':
- return (client.httpsHealthChecks(), 'httpsHealthCheck')
- else:
- return (client.httpHealthChecks(), 'httpHealthCheck')
-
-
-def get_healthcheck(client, name, project_id=None, resource_type='HTTP'):
- """
- Get a Healthcheck from GCP.
-
- :param client: An initialized GCE Compute Discovery resource.
- :type client: :class: `googleapiclient.discovery.Resource`
-
- :param name: Name of the Url Map.
- :type name: ``str``
-
- :param project_id: The GCP project ID.
- :type project_id: ``str``
-
- :return: A dict resp from the respective GCP 'get' request.
- :rtype: ``dict``
- """
- try:
- resource, entity_name = _get_req_resource(client, resource_type)
- args = {'project': project_id, entity_name: name}
- req = resource.get(**args)
- return GCPUtils.execute_api_client_req(req, raise_404=False)
- except Exception:
- raise
-
-
-def create_healthcheck(client, params, project_id, resource_type='HTTP'):
- """
- Create a new Healthcheck.
-
- :param client: An initialized GCE Compute Discovery resource.
- :type client: :class: `googleapiclient.discovery.Resource`
-
- :param params: Dictionary of arguments from AnsibleModule.
- :type params: ``dict``
-
- :return: Tuple with changed status and response dict
- :rtype: ``tuple`` in the format of (bool, dict)
- """
- gcp_dict = _build_healthcheck_dict(params)
- try:
- resource, _ = _get_req_resource(client, resource_type)
- args = {'project': project_id, 'body': gcp_dict}
- req = resource.insert(**args)
- return_data = GCPUtils.execute_api_client_req(req, client, raw=False)
- if not return_data:
- return_data = get_healthcheck(client,
- name=params['healthcheck_name'],
- project_id=project_id)
- return (True, return_data)
- except Exception:
- raise
-
-
-def delete_healthcheck(client, name, project_id, resource_type='HTTP'):
- """
- Delete a Healthcheck.
-
- :param client: An initialized GCE Compute Discovery resource.
- :type client: :class: `googleapiclient.discovery.Resource`
-
- :param name: Name of the Url Map.
- :type name: ``str``
-
- :param project_id: The GCP project ID.
- :type project_id: ``str``
-
- :return: Tuple with changed status and response dict
- :rtype: ``tuple`` in the format of (bool, dict)
- """
- try:
- resource, entity_name = _get_req_resource(client, resource_type)
- args = {'project': project_id, entity_name: name}
- req = resource.delete(**args)
- return_data = GCPUtils.execute_api_client_req(req, client)
- return (True, return_data)
- except Exception:
- raise
-
-
-def update_healthcheck(client, healthcheck, params, name, project_id,
- resource_type='HTTP'):
- """
- Update a Healthcheck.
-
- If the healthcheck has not changed, the update will not occur.
-
- :param client: An initialized GCE Compute Discovery resource.
- :type client: :class: `googleapiclient.discovery.Resource`
-
- :param healthcheck: Name of the Url Map.
- :type healthcheck: ``dict``
-
- :param params: Dictionary of arguments from AnsibleModule.
- :type params: ``dict``
-
- :param name: Name of the Url Map.
- :type name: ``str``
-
- :param project_id: The GCP project ID.
- :type project_id: ``str``
-
- :return: Tuple with changed status and response dict
- :rtype: ``tuple`` in the format of (bool, dict)
- """
- gcp_dict = _build_healthcheck_dict(params)
- ans = GCPUtils.are_params_equal(healthcheck, gcp_dict)
- if ans:
- return (False, 'no update necessary')
-
- try:
- resource, entity_name = _get_req_resource(client, resource_type)
- args = {'project': project_id, entity_name: name, 'body': gcp_dict}
- req = resource.update(**args)
- return_data = GCPUtils.execute_api_client_req(
- req, client=client, raw=False)
- return (True, return_data)
- except Exception:
- raise
-
-
-def main():
- module = AnsibleModule(argument_spec=dict(
- healthcheck_name=dict(required=True),
- healthcheck_type=dict(required=True,
- choices=['HTTP', 'HTTPS']),
- request_path=dict(required=False, default='/'),
- check_interval=dict(required=False, type='int', default=5),
- healthy_threshold=dict(required=False, type='int', default=2),
- unhealthy_threshold=dict(required=False, type='int', default=2),
- host_header=dict(required=False, type='str', default=''),
- timeout=dict(required=False, type='int', default=5),
- port=dict(required=False, type='int'),
- state=dict(choices=['absent', 'present'], default='present'),
- service_account_email=dict(),
- service_account_permissions=dict(type='list'),
- credentials_file=dict(),
- project_id=dict(), ), )
-
- client, conn_params = get_google_api_client(module, 'compute', user_agent_product=USER_AGENT_PRODUCT,
- user_agent_version=USER_AGENT_VERSION)
-
- params = {}
-
- params['healthcheck_name'] = module.params.get('healthcheck_name')
- params['healthcheck_type'] = module.params.get('healthcheck_type')
- params['request_path'] = module.params.get('request_path')
- params['check_interval'] = module.params.get('check_interval')
- params['healthy_threshold'] = module.params.get('healthy_threshold')
- params['unhealthy_threshold'] = module.params.get('unhealthy_threshold')
- params['host_header'] = module.params.get('host_header')
- params['timeout'] = module.params.get('timeout')
- params['port'] = module.params.get('port', None)
- params['state'] = module.params.get('state')
-
- if not params['port']:
- params['port'] = 80
- if params['healthcheck_type'] == 'HTTPS':
- params['port'] = 443
- try:
- _validate_healthcheck_params(params)
- except Exception as e:
- module.fail_json(msg=e.message, changed=False)
-
- changed = False
- json_output = {'state': params['state']}
- healthcheck = get_healthcheck(client,
- name=params['healthcheck_name'],
- project_id=conn_params['project_id'],
- resource_type=params['healthcheck_type'])
-
- if not healthcheck:
- if params['state'] == 'absent':
- # Doesn't exist in GCE, and state==absent.
- changed = False
- module.fail_json(
- msg="Cannot delete unknown healthcheck: %s" %
- (params['healthcheck_name']))
- else:
- # Create
- changed, json_output['healthcheck'] = create_healthcheck(client,
- params=params,
- project_id=conn_params['project_id'],
- resource_type=params['healthcheck_type'])
- elif params['state'] == 'absent':
- # Delete
- changed, json_output['healthcheck'] = delete_healthcheck(client,
- name=params['healthcheck_name'],
- project_id=conn_params['project_id'],
- resource_type=params['healthcheck_type'])
- else:
- changed, json_output['healthcheck'] = update_healthcheck(client,
- healthcheck=healthcheck,
- params=params,
- name=params['healthcheck_name'],
- project_id=conn_params['project_id'],
- resource_type=params['healthcheck_type'])
- json_output['changed'] = changed
- json_output.update(params)
- module.exit_json(**json_output)
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/cloud/google/_gcp_iam_role_facts.py b/lib/ansible/modules/cloud/google/_gcp_iam_role_facts.py
deleted file mode 120000
index f46a8e3ec7..0000000000
--- a/lib/ansible/modules/cloud/google/_gcp_iam_role_facts.py
+++ /dev/null
@@ -1 +0,0 @@
-gcp_iam_role_info.py \ No newline at end of file
diff --git a/lib/ansible/modules/cloud/google/_gcp_iam_service_account_facts.py b/lib/ansible/modules/cloud/google/_gcp_iam_service_account_facts.py
deleted file mode 120000
index 3f03024049..0000000000
--- a/lib/ansible/modules/cloud/google/_gcp_iam_service_account_facts.py
+++ /dev/null
@@ -1 +0,0 @@
-gcp_iam_service_account_info.py \ No newline at end of file
diff --git a/lib/ansible/modules/cloud/google/_gcp_pubsub_subscription_facts.py b/lib/ansible/modules/cloud/google/_gcp_pubsub_subscription_facts.py
deleted file mode 120000
index 3196ae083b..0000000000
--- a/lib/ansible/modules/cloud/google/_gcp_pubsub_subscription_facts.py
+++ /dev/null
@@ -1 +0,0 @@
-gcp_pubsub_subscription_info.py \ No newline at end of file
diff --git a/lib/ansible/modules/cloud/google/_gcp_pubsub_topic_facts.py b/lib/ansible/modules/cloud/google/_gcp_pubsub_topic_facts.py
deleted file mode 120000
index 388ebfc1d1..0000000000
--- a/lib/ansible/modules/cloud/google/_gcp_pubsub_topic_facts.py
+++ /dev/null
@@ -1 +0,0 @@
-gcp_pubsub_topic_info.py \ No newline at end of file
diff --git a/lib/ansible/modules/cloud/google/_gcp_redis_instance_facts.py b/lib/ansible/modules/cloud/google/_gcp_redis_instance_facts.py
deleted file mode 120000
index e6d6fa6db2..0000000000
--- a/lib/ansible/modules/cloud/google/_gcp_redis_instance_facts.py
+++ /dev/null
@@ -1 +0,0 @@
-gcp_redis_instance_info.py \ No newline at end of file
diff --git a/lib/ansible/modules/cloud/google/_gcp_resourcemanager_project_facts.py b/lib/ansible/modules/cloud/google/_gcp_resourcemanager_project_facts.py
deleted file mode 120000
index 5766332a37..0000000000
--- a/lib/ansible/modules/cloud/google/_gcp_resourcemanager_project_facts.py
+++ /dev/null
@@ -1 +0,0 @@
-gcp_resourcemanager_project_info.py \ No newline at end of file
diff --git a/lib/ansible/modules/cloud/google/_gcp_sourcerepo_repository_facts.py b/lib/ansible/modules/cloud/google/_gcp_sourcerepo_repository_facts.py
deleted file mode 120000
index b6dc6a8d75..0000000000
--- a/lib/ansible/modules/cloud/google/_gcp_sourcerepo_repository_facts.py
+++ /dev/null
@@ -1 +0,0 @@
-gcp_sourcerepo_repository_info.py \ No newline at end of file
diff --git a/lib/ansible/modules/cloud/google/_gcp_spanner_database_facts.py b/lib/ansible/modules/cloud/google/_gcp_spanner_database_facts.py
deleted file mode 120000
index abadc34b30..0000000000
--- a/lib/ansible/modules/cloud/google/_gcp_spanner_database_facts.py
+++ /dev/null
@@ -1 +0,0 @@
-gcp_spanner_database_info.py \ No newline at end of file
diff --git a/lib/ansible/modules/cloud/google/_gcp_spanner_instance_facts.py b/lib/ansible/modules/cloud/google/_gcp_spanner_instance_facts.py
deleted file mode 120000
index 1c1e47220a..0000000000
--- a/lib/ansible/modules/cloud/google/_gcp_spanner_instance_facts.py
+++ /dev/null
@@ -1 +0,0 @@
-gcp_spanner_instance_info.py \ No newline at end of file
diff --git a/lib/ansible/modules/cloud/google/_gcp_sql_database_facts.py b/lib/ansible/modules/cloud/google/_gcp_sql_database_facts.py
deleted file mode 120000
index de080a71eb..0000000000
--- a/lib/ansible/modules/cloud/google/_gcp_sql_database_facts.py
+++ /dev/null
@@ -1 +0,0 @@
-gcp_sql_database_info.py \ No newline at end of file
diff --git a/lib/ansible/modules/cloud/google/_gcp_sql_instance_facts.py b/lib/ansible/modules/cloud/google/_gcp_sql_instance_facts.py
deleted file mode 120000
index c6c2c5f386..0000000000
--- a/lib/ansible/modules/cloud/google/_gcp_sql_instance_facts.py
+++ /dev/null
@@ -1 +0,0 @@
-gcp_sql_instance_info.py \ No newline at end of file
diff --git a/lib/ansible/modules/cloud/google/_gcp_sql_user_facts.py b/lib/ansible/modules/cloud/google/_gcp_sql_user_facts.py
deleted file mode 120000
index 44488004a4..0000000000
--- a/lib/ansible/modules/cloud/google/_gcp_sql_user_facts.py
+++ /dev/null
@@ -1 +0,0 @@
-gcp_sql_user_info.py \ No newline at end of file
diff --git a/lib/ansible/modules/cloud/google/_gcp_target_proxy.py b/lib/ansible/modules/cloud/google/_gcp_target_proxy.py
deleted file mode 100644
index 57078a8fe1..0000000000
--- a/lib/ansible/modules/cloud/google/_gcp_target_proxy.py
+++ /dev/null
@@ -1,296 +0,0 @@
-#!/usr/bin/python
-# Copyright 2017 Google Inc.
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['deprecated'],
- 'supported_by': 'community'}
-
-
-DOCUMENTATION = '''
----
-module: gcp_target_proxy
-version_added: "2.4"
-short_description: Create, Update or Destroy a Target_Proxy.
-description:
- - Create, Update or Destroy a Target_Proxy. See
- U(https://cloud.google.com/compute/docs/load-balancing/http/target-proxies) for an overview.
- More details on the Target_Proxy API can be found at
- U(https://cloud.google.com/compute/docs/reference/latest/targetHttpProxies#resource-representations).
-requirements:
- - "python >= 2.6"
- - "google-api-python-client >= 1.6.2"
- - "google-auth >= 0.9.0"
- - "google-auth-httplib2 >= 0.0.2"
-deprecated:
- removed_in: "2.12"
- why: Updated modules released with increased functionality
- alternative: Use M(gcp_compute_target_http_proxy) instead.
-notes:
- - Currently only supports global HTTP proxy.
-author:
- - "Tom Melendez (@supertom) <tom@supertom.com>"
-options:
- target_proxy_name:
- description:
- - Name of the Target_Proxy.
- required: true
- target_proxy_type:
- description:
- - Type of Target_Proxy. HTTP, HTTPS or SSL. Only HTTP is currently supported.
- required: true
- url_map_name:
- description:
- - Name of the Url Map. Required if type is HTTP or HTTPS proxy.
- required: false
-'''
-
-EXAMPLES = '''
-- name: Create Minimum HTTP Target_Proxy
- gcp_target_proxy:
- service_account_email: "{{ service_account_email }}"
- credentials_file: "{{ credentials_file }}"
- project_id: "{{ project_id }}"
- target_proxy_name: my-target_proxy
- target_proxy_type: HTTP
- url_map_name: my-url-map
- state: present
-'''
-
-RETURN = '''
-state:
- description: state of the Target_Proxy
- returned: Always.
- type: str
- sample: present
-updated_target_proxy:
- description: True if the target_proxy has been updated. Will not appear on
- initial target_proxy creation.
- returned: if the target_proxy has been updated.
- type: bool
- sample: true
-target_proxy_name:
- description: Name of the Target_Proxy
- returned: Always
- type: str
- sample: my-target-proxy
-target_proxy_type:
- description: Type of Target_Proxy. One of HTTP, HTTPS or SSL.
- returned: Always
- type: str
- sample: HTTP
-target_proxy:
- description: GCP Target_Proxy dictionary
- returned: Always. Refer to GCP documentation for detailed field descriptions.
- type: dict
- sample: { "name": "my-target-proxy", "urlMap": "..." }
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.gcp import get_google_api_client, GCPUtils
-
-
-USER_AGENT_PRODUCT = 'ansible-target_proxy'
-USER_AGENT_VERSION = '0.0.1'
-
-
-def _build_target_proxy_dict(params, project_id=None):
- """
- Reformat services in Ansible Params.
-
- :param params: Params from AnsibleModule object
- :type params: ``dict``
-
- :param project_id: The GCP project ID.
- :type project_id: ``str``
-
- :return: dictionary suitable for submission to GCP UrlMap API.
- :rtype ``dict``
- """
- url = ''
- if project_id:
- url = GCPUtils.build_googleapi_url(project_id)
- gcp_dict = GCPUtils.params_to_gcp_dict(params, 'target_proxy_name')
- if 'urlMap' in gcp_dict:
- gcp_dict['urlMap'] = '%s/global/urlMaps/%s' % (url,
- gcp_dict['urlMap'])
- return gcp_dict
-
-
-def get_target_http_proxy(client, name, project_id=None):
- """
- Get a Target HTTP Proxy from GCP.
-
- :param client: An initialized GCE Compute Discovery resource.
- :type client: :class: `googleapiclient.discovery.Resource`
-
- :param name: Name of the Target Proxy.
- :type name: ``str``
-
- :param project_id: The GCP project ID.
- :type project_id: ``str``
-
- :return: A dict resp from the respective GCP 'get' request.
- :rtype: ``dict``
- """
- req = client.targetHttpProxies().get(project=project_id,
- targetHttpProxy=name)
- return GCPUtils.execute_api_client_req(req, raise_404=False)
-
-
-def create_target_http_proxy(client, params, project_id):
- """
- Create a new Target_Proxy.
-
- :param client: An initialized GCE Compute Discovery resource.
- :type client: :class: `googleapiclient.discovery.Resource`
-
- :param params: Dictionary of arguments from AnsibleModule.
- :type params: ``dict``
-
- :return: Tuple with changed status and response dict
- :rtype: ``tuple`` in the format of (bool, dict)
- """
- gcp_dict = _build_target_proxy_dict(params, project_id)
- try:
- req = client.targetHttpProxies().insert(project=project_id,
- body=gcp_dict)
- return_data = GCPUtils.execute_api_client_req(req, client, raw=False)
- if not return_data:
- return_data = get_target_http_proxy(client,
- name=params['target_proxy_name'],
- project_id=project_id)
- return (True, return_data)
- except Exception:
- raise
-
-
-def delete_target_http_proxy(client, name, project_id):
- """
- Delete a Target_Proxy.
-
- :param client: An initialized GCE Compute Discovery resource.
- :type client: :class: `googleapiclient.discovery.Resource`
-
- :param name: Name of the Target Proxy.
- :type name: ``str``
-
- :param project_id: The GCP project ID.
- :type project_id: ``str``
-
- :return: Tuple with changed status and response dict
- :rtype: ``tuple`` in the format of (bool, dict)
- """
- try:
- req = client.targetHttpProxies().delete(
- project=project_id, targetHttpProxy=name)
- return_data = GCPUtils.execute_api_client_req(req, client)
- return (True, return_data)
- except Exception:
- raise
-
-
-def update_target_http_proxy(client, target_proxy, params, name, project_id):
- """
- Update a HTTP Target_Proxy. Currently only the Url Map can be updated.
-
- If the target_proxy has not changed, the update will not occur.
-
- :param client: An initialized GCE Compute Discovery resource.
- :type client: :class: `googleapiclient.discovery.Resource`
-
- :param target_proxy: Name of the Target Proxy.
- :type target_proxy: ``dict``
-
- :param params: Dictionary of arguments from AnsibleModule.
- :type params: ``dict``
-
- :param name: Name of the Target Proxy.
- :type name: ``str``
-
- :param project_id: The GCP project ID.
- :type project_id: ``str``
-
- :return: Tuple with changed status and response dict
- :rtype: ``tuple`` in the format of (bool, dict)
- """
- gcp_dict = _build_target_proxy_dict(params, project_id)
-
- GCPUtils.are_params_equal(target_proxy, gcp_dict)
- if target_proxy['urlMap'] == gcp_dict['urlMap']:
- return (False, 'no update necessary')
-
- try:
- req = client.targetHttpProxies().setUrlMap(project=project_id,
- targetHttpProxy=name,
- body={"urlMap": gcp_dict['urlMap']})
- return_data = GCPUtils.execute_api_client_req(
- req, client=client, raw=False)
- return (True, return_data)
- except Exception:
- raise
-
-
-def main():
- module = AnsibleModule(argument_spec=dict(
- target_proxy_name=dict(required=True),
- target_proxy_type=dict(required=True, choices=['HTTP']),
- url_map_name=dict(required=False),
- state=dict(required=True, choices=['absent', 'present']),
- service_account_email=dict(),
- service_account_permissions=dict(type='list'),
- pem_file=dict(),
- credentials_file=dict(),
- project_id=dict(), ), )
-
- client, conn_params = get_google_api_client(module, 'compute', user_agent_product=USER_AGENT_PRODUCT,
- user_agent_version=USER_AGENT_VERSION)
-
- params = {}
- params['state'] = module.params.get('state')
- params['target_proxy_name'] = module.params.get('target_proxy_name')
- params['target_proxy_type'] = module.params.get('target_proxy_type')
- params['url_map'] = module.params.get('url_map_name', None)
-
- changed = False
- json_output = {'state': params['state']}
- target_proxy = get_target_http_proxy(client,
- name=params['target_proxy_name'],
- project_id=conn_params['project_id'])
-
- if not target_proxy:
- if params['state'] == 'absent':
- # Doesn't exist in GCE, and state==absent.
- changed = False
- module.fail_json(
- msg="Cannot delete unknown target_proxy: %s" %
- (params['target_proxy_name']))
- else:
- # Create
- changed, json_output['target_proxy'] = create_target_http_proxy(client,
- params=params,
- project_id=conn_params['project_id'])
- elif params['state'] == 'absent':
- # Delete
- changed, json_output['target_proxy'] = delete_target_http_proxy(client,
- name=params['target_proxy_name'],
- project_id=conn_params['project_id'])
- else:
- changed, json_output['target_proxy'] = update_target_http_proxy(client,
- target_proxy=target_proxy,
- params=params,
- name=params['target_proxy_name'],
- project_id=conn_params['project_id'])
- json_output['updated_target_proxy'] = changed
-
- json_output['changed'] = changed
- json_output.update(params)
- module.exit_json(**json_output)
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/cloud/google/_gcp_tpu_node_facts.py b/lib/ansible/modules/cloud/google/_gcp_tpu_node_facts.py
deleted file mode 120000
index 5e0ba332eb..0000000000
--- a/lib/ansible/modules/cloud/google/_gcp_tpu_node_facts.py
+++ /dev/null
@@ -1 +0,0 @@
-gcp_tpu_node_info.py \ No newline at end of file
diff --git a/lib/ansible/modules/cloud/google/_gcp_url_map.py b/lib/ansible/modules/cloud/google/_gcp_url_map.py
deleted file mode 100644
index 34bfcf583c..0000000000
--- a/lib/ansible/modules/cloud/google/_gcp_url_map.py
+++ /dev/null
@@ -1,510 +0,0 @@
-#!/usr/bin/python
-# Copyright 2017 Google Inc.
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['deprecated'],
- 'supported_by': 'community'}
-
-
-DOCUMENTATION = '''
----
-module: gcp_url_map
-version_added: "2.4"
-short_description: Create, Update or Destroy a Url_Map.
-description:
- - Create, Update or Destroy a Url_Map. See
- U(https://cloud.google.com/compute/docs/load-balancing/http/url-map) for an overview.
- More details on the Url_Map API can be found at
- U(https://cloud.google.com/compute/docs/reference/latest/urlMaps#resource).
-requirements:
- - "python >= 2.6"
- - "google-api-python-client >= 1.6.2"
- - "google-auth >= 0.9.0"
- - "google-auth-httplib2 >= 0.0.2"
-notes:
- - Only supports global Backend Services.
- - Url_Map tests are not currently supported.
-author:
- - "Tom Melendez (@supertom) <tom@supertom.com>"
-deprecated:
- removed_in: "2.12"
- why: Updated modules released with increased functionality
- alternative: Use M(gcp_compute_url_map) instead.
-options:
- url_map_name:
- description:
- - Name of the Url_Map.
- required: true
- default_service:
- description:
- - Default Backend Service if no host rules match.
- required: true
- host_rules:
- description:
- - The list of HostRules to use against the URL. Contains
- a list of hosts and an associated path_matcher.
- - The 'hosts' parameter is a 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 must be followed in the pattern by either - or ..
- - The 'path_matcher' parameter is name of the PathMatcher to use
- to match the path portion of the URL if the hostRule matches the URL's
- host portion.
- required: false
- path_matchers:
- description:
- - The list of named PathMatchers to use against the URL. Contains
- path_rules, which is a list of paths and an associated service. A
- default_service can also be specified for each path_matcher.
- - The 'name' parameter to which this path_matcher is referred by the
- host_rule.
- - The 'default_service' parameter is the name of the
- BackendService resource. This will be used if none of the path_rules
- defined by this path_matcher is matched by the URL's path portion.
- - The 'path_rules' parameter is a list of dictionaries containing a
- list of paths and a service to direct traffic to. Each path item must
- start with / and the only place a * is allowed is at the end following
- a /. The string fed to the path matcher does not include any text after
- the first ? or #, and those chars are not allowed here.
- required: false
-'''
-
-EXAMPLES = '''
-- name: Create Minimal Url_Map
- gcp_url_map:
- service_account_email: "{{ service_account_email }}"
- credentials_file: "{{ credentials_file }}"
- project_id: "{{ project_id }}"
- url_map_name: my-url_map
- default_service: my-backend-service
- state: present
-- name: Create UrlMap with pathmatcher
- gcp_url_map:
- service_account_email: "{{ service_account_email }}"
- credentials_file: "{{ credentials_file }}"
- project_id: "{{ project_id }}"
- url_map_name: my-url-map-pm
- default_service: default-backend-service
- path_matchers:
- - name: 'path-matcher-one'
- description: 'path matcher one'
- default_service: 'bes-pathmatcher-one-default'
- path_rules:
- - service: 'my-one-bes'
- paths:
- - '/data'
- - '/aboutus'
- host_rules:
- - hosts:
- - '*.'
- path_matcher: 'path-matcher-one'
- state: "present"
-'''
-
-RETURN = '''
-host_rules:
- description: List of HostRules.
- returned: If specified.
- type: dict
- sample: [ { hosts: ["*."], "path_matcher": "my-pm" } ]
-path_matchers:
- description: The list of named PathMatchers to use against the URL.
- returned: If specified.
- type: dict
- sample: [ { "name": "my-pm", "path_rules": [ { "paths": [ "/data" ] } ], "service": "my-service" } ]
-state:
- description: state of the Url_Map
- returned: Always.
- type: str
- sample: present
-updated_url_map:
- description: True if the url_map has been updated. Will not appear on
- initial url_map creation.
- returned: if the url_map has been updated.
- type: bool
- sample: true
-url_map_name:
- description: Name of the Url_Map
- returned: Always
- type: str
- sample: my-url-map
-url_map:
- description: GCP Url_Map dictionary
- returned: Always. Refer to GCP documentation for detailed field descriptions.
- type: dict
- sample: { "name": "my-url-map", "hostRules": [...], "pathMatchers": [...] }
-'''
-
-try:
- from ast import literal_eval
- HAS_PYTHON26 = True
-except ImportError:
- HAS_PYTHON26 = False
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.gcp import check_params, get_google_api_client, GCPUtils
-from ansible.module_utils.six import string_types
-
-
-USER_AGENT_PRODUCT = 'ansible-url_map'
-USER_AGENT_VERSION = '0.0.1'
-
-
-def _validate_params(params):
- """
- Validate url_map params.
-
- This function calls _validate_host_rules_params to verify
- the host_rules-specific parameters.
-
- This function calls _validate_path_matchers_params to verify
- the path_matchers-specific parameters.
-
- :param params: Ansible dictionary containing configuration.
- :type params: ``dict``
-
- :return: True or raises ValueError
- :rtype: ``bool`` or `class:ValueError`
- """
- fields = [
- {'name': 'default_service', 'type': str, 'required': True},
- {'name': 'host_rules', 'type': list},
- {'name': 'path_matchers', 'type': list},
- ]
- try:
- check_params(params, fields)
- if 'path_matchers' in params and params['path_matchers'] is not None:
- _validate_path_matcher_params(params['path_matchers'])
- if 'host_rules' in params and params['host_rules'] is not None:
- _validate_host_rules_params(params['host_rules'])
- except Exception:
- raise
-
- return (True, '')
-
-
-def _validate_path_matcher_params(path_matchers):
- """
- Validate configuration for path_matchers.
-
- :param path_matchers: Ansible dictionary containing path_matchers
- configuration (only).
- :type path_matchers: ``dict``
-
- :return: True or raises ValueError
- :rtype: ``bool`` or `class:ValueError`
- """
- fields = [
- {'name': 'name', 'type': str, 'required': True},
- {'name': 'default_service', 'type': str, 'required': True},
- {'name': 'path_rules', 'type': list, 'required': True},
- {'name': 'max_rate', 'type': int},
- {'name': 'max_rate_per_instance', 'type': float},
- ]
- pr_fields = [
- {'name': 'service', 'type': str, 'required': True},
- {'name': 'paths', 'type': list, 'required': True},
- ]
-
- if not path_matchers:
- raise ValueError(('path_matchers should be a list. %s (%s) provided'
- % (path_matchers, type(path_matchers))))
-
- for pm in path_matchers:
- try:
- check_params(pm, fields)
- for pr in pm['path_rules']:
- check_params(pr, pr_fields)
- for path in pr['paths']:
- if not path.startswith('/'):
- raise ValueError("path for %s must start with /" % (
- pm['name']))
- except Exception:
- raise
-
- return (True, '')
-
-
-def _validate_host_rules_params(host_rules):
- """
- Validate configuration for host_rules.
-
- :param host_rules: Ansible dictionary containing host_rules
- configuration (only).
- :type host_rules ``dict``
-
- :return: True or raises ValueError
- :rtype: ``bool`` or `class:ValueError`
- """
- fields = [
- {'name': 'path_matcher', 'type': str, 'required': True},
- ]
-
- if not host_rules:
- raise ValueError('host_rules should be a list.')
-
- for hr in host_rules:
- try:
- check_params(hr, fields)
- for host in hr['hosts']:
- if not isinstance(host, string_types):
- raise ValueError("host in hostrules must be a string")
- elif '*' in host:
- if host.index('*') != 0:
- raise ValueError("wildcard must be first char in host, %s" % (
- host))
- else:
- if host[1] not in ['.', '-', ]:
- raise ValueError("wildcard be followed by a '.' or '-', %s" % (
- host))
-
- except Exception:
- raise
-
- return (True, '')
-
-
-def _build_path_matchers(path_matcher_list, project_id):
- """
- Reformat services in path matchers list.
-
- Specifically, builds out URLs.
-
- :param path_matcher_list: The GCP project ID.
- :type path_matcher_list: ``list`` of ``dict``
-
- :param project_id: The GCP project ID.
- :type project_id: ``str``
-
- :return: list suitable for submission to GCP
- UrlMap API Path Matchers list.
- :rtype ``list`` of ``dict``
- """
- url = ''
- if project_id:
- url = GCPUtils.build_googleapi_url(project_id)
- for pm in path_matcher_list:
- if 'defaultService' in pm:
- pm['defaultService'] = '%s/global/backendServices/%s' % (url,
- pm['defaultService'])
- if 'pathRules' in pm:
- for rule in pm['pathRules']:
- if 'service' in rule:
- rule['service'] = '%s/global/backendServices/%s' % (url,
- rule['service'])
- return path_matcher_list
-
-
-def _build_url_map_dict(params, project_id=None):
- """
- Reformat services in Ansible Params.
-
- :param params: Params from AnsibleModule object
- :type params: ``dict``
-
- :param project_id: The GCP project ID.
- :type project_id: ``str``
-
- :return: dictionary suitable for submission to GCP UrlMap API.
- :rtype ``dict``
- """
- url = ''
- if project_id:
- url = GCPUtils.build_googleapi_url(project_id)
- gcp_dict = GCPUtils.params_to_gcp_dict(params, 'url_map_name')
- if 'defaultService' in gcp_dict:
- gcp_dict['defaultService'] = '%s/global/backendServices/%s' % (url,
- gcp_dict['defaultService'])
- if 'pathMatchers' in gcp_dict:
- gcp_dict['pathMatchers'] = _build_path_matchers(gcp_dict['pathMatchers'], project_id)
-
- return gcp_dict
-
-
-def get_url_map(client, name, project_id=None):
- """
- Get a Url_Map from GCP.
-
- :param client: An initialized GCE Compute Discovery resource.
- :type client: :class: `googleapiclient.discovery.Resource`
-
- :param name: Name of the Url Map.
- :type name: ``str``
-
- :param project_id: The GCP project ID.
- :type project_id: ``str``
-
- :return: A dict resp from the respective GCP 'get' request.
- :rtype: ``dict``
- """
- try:
- req = client.urlMaps().get(project=project_id, urlMap=name)
- return GCPUtils.execute_api_client_req(req, raise_404=False)
- except Exception:
- raise
-
-
-def create_url_map(client, params, project_id):
- """
- Create a new Url_Map.
-
- :param client: An initialized GCE Compute Discovery resource.
- :type client: :class: `googleapiclient.discovery.Resource`
-
- :param params: Dictionary of arguments from AnsibleModule.
- :type params: ``dict``
-
- :return: Tuple with changed status and response dict
- :rtype: ``tuple`` in the format of (bool, dict)
- """
- gcp_dict = _build_url_map_dict(params, project_id)
- try:
- req = client.urlMaps().insert(project=project_id, body=gcp_dict)
- return_data = GCPUtils.execute_api_client_req(req, client, raw=False)
- if not return_data:
- return_data = get_url_map(client,
- name=params['url_map_name'],
- project_id=project_id)
- return (True, return_data)
- except Exception:
- raise
-
-
-def delete_url_map(client, name, project_id):
- """
- Delete a Url_Map.
-
- :param client: An initialized GCE Compute Discover resource.
- :type client: :class: `googleapiclient.discovery.Resource`
-
- :param name: Name of the Url Map.
- :type name: ``str``
-
- :param project_id: The GCP project ID.
- :type project_id: ``str``
-
- :return: Tuple with changed status and response dict
- :rtype: ``tuple`` in the format of (bool, dict)
- """
- try:
- req = client.urlMaps().delete(project=project_id, urlMap=name)
- return_data = GCPUtils.execute_api_client_req(req, client)
- return (True, return_data)
- except Exception:
- raise
-
-
-def update_url_map(client, url_map, params, name, project_id):
- """
- Update a Url_Map.
-
- If the url_map has not changed, the update will not occur.
-
- :param client: An initialized GCE Compute Discovery resource.
- :type client: :class: `googleapiclient.discovery.Resource`
-
- :param url_map: Name of the Url Map.
- :type url_map: ``dict``
-
- :param params: Dictionary of arguments from AnsibleModule.
- :type params: ``dict``
-
- :param name: Name of the Url Map.
- :type name: ``str``
-
- :param project_id: The GCP project ID.
- :type project_id: ``str``
-
- :return: Tuple with changed status and response dict
- :rtype: ``tuple`` in the format of (bool, dict)
- """
- gcp_dict = _build_url_map_dict(params, project_id)
-
- ans = GCPUtils.are_params_equal(url_map, gcp_dict)
- if ans:
- return (False, 'no update necessary')
-
- gcp_dict['fingerprint'] = url_map['fingerprint']
- try:
- req = client.urlMaps().update(project=project_id,
- urlMap=name, body=gcp_dict)
- return_data = GCPUtils.execute_api_client_req(req, client=client, raw=False)
- return (True, return_data)
- except Exception:
- raise
-
-
-def main():
- module = AnsibleModule(argument_spec=dict(
- url_map_name=dict(required=True),
- state=dict(choices=['absent', 'present'], default='present'),
- default_service=dict(required=True),
- path_matchers=dict(type='list', required=False),
- host_rules=dict(type='list', required=False),
- service_account_email=dict(),
- service_account_permissions=dict(type='list'),
- pem_file=dict(),
- credentials_file=dict(),
- project_id=dict(), ), required_together=[
- ['path_matchers', 'host_rules'], ])
-
- client, conn_params = get_google_api_client(module, 'compute', user_agent_product=USER_AGENT_PRODUCT,
- user_agent_version=USER_AGENT_VERSION)
-
- params = {}
- params['state'] = module.params.get('state')
- params['url_map_name'] = module.params.get('url_map_name')
- params['default_service'] = module.params.get('default_service')
- if module.params.get('path_matchers'):
- params['path_matchers'] = module.params.get('path_matchers')
- if module.params.get('host_rules'):
- params['host_rules'] = module.params.get('host_rules')
-
- try:
- _validate_params(params)
- except Exception as e:
- module.fail_json(msg=e.message, changed=False)
-
- changed = False
- json_output = {'state': params['state']}
- url_map = get_url_map(client,
- name=params['url_map_name'],
- project_id=conn_params['project_id'])
-
- if not url_map:
- if params['state'] == 'absent':
- # Doesn't exist in GCE, and state==absent.
- changed = False
- module.fail_json(
- msg="Cannot delete unknown url_map: %s" %
- (params['url_map_name']))
- else:
- # Create
- changed, json_output['url_map'] = create_url_map(client,
- params=params,
- project_id=conn_params['project_id'])
- elif params['state'] == 'absent':
- # Delete
- changed, json_output['url_map'] = delete_url_map(client,
- name=params['url_map_name'],
- project_id=conn_params['project_id'])
- else:
- changed, json_output['url_map'] = update_url_map(client,
- url_map=url_map,
- params=params,
- name=params['url_map_name'],
- project_id=conn_params['project_id'])
- json_output['updated_url_map'] = changed
-
- json_output['changed'] = changed
- json_output.update(params)
- module.exit_json(**json_output)
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/cloud/google/_gcpubsub_facts.py b/lib/ansible/modules/cloud/google/_gcpubsub_facts.py
deleted file mode 120000
index 3feb35c3ee..0000000000
--- a/lib/ansible/modules/cloud/google/_gcpubsub_facts.py
+++ /dev/null
@@ -1 +0,0 @@
-gcpubsub_info.py \ No newline at end of file
diff --git a/lib/ansible/modules/cloud/google/_gcspanner.py b/lib/ansible/modules/cloud/google/_gcspanner.py
deleted file mode 100644
index fdf81cafca..0000000000
--- a/lib/ansible/modules/cloud/google/_gcspanner.py
+++ /dev/null
@@ -1,291 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-
-# Copyright: (c) 2017, Google Inc.
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['deprecated'],
- 'supported_by': 'community'}
-
-DOCUMENTATION = '''
----
-module: gcspanner
-version_added: "2.3"
-short_description: Create and Delete Instances/Databases on Spanner
-description:
- - Create and Delete Instances/Databases on Spanner.
- See U(https://cloud.google.com/spanner/docs) for an overview.
-requirements:
- - python >= 2.6
- - google-auth >= 0.5.0
- - google-cloud-spanner >= 0.23.0
-notes:
- - Changing the configuration on an existing instance is not supported.
-deprecated:
- removed_in: "2.12"
- why: Updated modules released with increased functionality
- alternative: Use M(gcp_spanner_database) and/or M(gcp_spanner_instance) instead.
-author:
- - Tom Melendez (@supertom) <tom@supertom.com>
-options:
- configuration:
- description:
- - Configuration the instance should use.
- - Examples are us-central1, asia-east1 and europe-west1.
- required: yes
- instance_id:
- description:
- - GCP spanner instance name.
- required: yes
- database_name:
- description:
- - Name of database contained on the instance.
- force_instance_delete:
- description:
- - To delete an instance, this argument must exist and be true (along with state being equal to absent).
- type: bool
- default: 'no'
- instance_display_name:
- description:
- - Name of Instance to display.
- - If not specified, instance_id will be used instead.
- node_count:
- description:
- - Number of nodes in the instance.
- default: 1
- state:
- description:
- - State of the instance or database. Applies to the most granular resource.
- - If a C(database_name) is specified we remove it.
- - If only C(instance_id) is specified, that is what is removed.
- choices: [ absent, present ]
- default: present
-'''
-
-EXAMPLES = '''
-- name: Create instance
- gcspanner:
- instance_id: '{{ instance_id }}'
- configuration: '{{ configuration }}'
- state: present
- node_count: 1
-
-- name: Create database
- gcspanner:
- instance_id: '{{ instance_id }}'
- configuration: '{{ configuration }}'
- database_name: '{{ database_name }}'
- state: present
-
-- name: Delete instance (and all databases)
-- gcspanner:
- instance_id: '{{ instance_id }}'
- configuration: '{{ configuration }}'
- state: absent
- force_instance_delete: yes
-'''
-
-RETURN = '''
-state:
- description: The state of the instance or database. Value will be either 'absent' or 'present'.
- returned: Always
- type: str
- sample: "present"
-
-database_name:
- description: Name of database.
- returned: When database name is specified
- type: str
- sample: "mydatabase"
-
-instance_id:
- description: Name of instance.
- returned: Always
- type: str
- sample: "myinstance"
-
-previous_values:
- description: List of dictionaries containing previous values prior to update.
- returned: When an instance update has occurred and a field has been modified.
- type: dict
- sample: "'previous_values': { 'instance': { 'instance_display_name': 'my-instance', 'node_count': 1 } }"
-
-updated:
- description: Boolean field to denote an update has occurred.
- returned: When an update has occurred.
- type: bool
- sample: True
-'''
-try:
- from ast import literal_eval
- HAS_PYTHON26 = True
-except ImportError:
- HAS_PYTHON26 = False
-
-try:
- from google.cloud import spanner
- from google.gax.errors import GaxError
- HAS_GOOGLE_CLOUD_SPANNER = True
-except ImportError as e:
- HAS_GOOGLE_CLOUD_SPANNER = False
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.gcp import check_min_pkg_version, get_google_cloud_credentials
-from ansible.module_utils.six import string_types
-
-
-CLOUD_CLIENT = 'google-cloud-spanner'
-CLOUD_CLIENT_MINIMUM_VERSION = '0.23.0'
-CLOUD_CLIENT_USER_AGENT = 'ansible-spanner-0.1'
-
-
-def get_spanner_configuration_name(config_name, project_name):
- config_name = 'projects/%s/instanceConfigs/regional-%s' % (project_name,
- config_name)
- return config_name
-
-
-def instance_update(instance):
- """
- Call update method on spanner client.
-
- Note: A ValueError exception is thrown despite the client succeeding.
- So, we validate the node_count and instance_display_name parameters and then
- ignore the ValueError exception.
-
- :param instance: a Spanner instance object
- :type instance: class `google.cloud.spanner.Instance`
-
- :returns True on success, raises ValueError on type error.
- :rtype ``bool``
- """
- errmsg = ''
- if not isinstance(instance.node_count, int):
- errmsg = 'node_count must be an integer %s (%s)' % (
- instance.node_count, type(instance.node_count))
- if instance.display_name and not isinstance(instance.display_name,
- string_types):
- errmsg = 'instance_display_name must be an string %s (%s)' % (
- instance.display_name, type(instance.display_name))
- if errmsg:
- raise ValueError(errmsg)
-
- try:
- instance.update()
- except ValueError:
- # The ValueError here is the one we 'expect'.
- pass
-
- return True
-
-
-def main():
- module = AnsibleModule(
- argument_spec=dict(
- instance_id=dict(type='str', required=True),
- state=dict(type='str', default='present', choices=['absent', 'present']),
- database_name=dict(type='str'),
- configuration=dict(type='str', required=True),
- node_count=dict(type='int', default=1),
- instance_display_name=dict(type='str'),
- force_instance_delete=dict(type='bool', default=False),
- service_account_email=dict(type='str'),
- credentials_file=dict(type='str'),
- project_id=dict(type='str'),
- ),
- )
-
- if not HAS_PYTHON26:
- module.fail_json(
- msg="GCE module requires python's 'ast' module, python v2.6+")
-
- if not HAS_GOOGLE_CLOUD_SPANNER:
- module.fail_json(msg="Please install google-cloud-spanner.")
-
- if not check_min_pkg_version(CLOUD_CLIENT, CLOUD_CLIENT_MINIMUM_VERSION):
- module.fail_json(msg="Please install %s client version %s" %
- (CLOUD_CLIENT, CLOUD_CLIENT_MINIMUM_VERSION))
-
- mod_params = {}
- mod_params['state'] = module.params.get('state')
- mod_params['instance_id'] = module.params.get('instance_id')
- mod_params['database_name'] = module.params.get('database_name')
- mod_params['configuration'] = module.params.get('configuration')
- mod_params['node_count'] = module.params.get('node_count', None)
- mod_params['instance_display_name'] = module.params.get('instance_display_name')
- mod_params['force_instance_delete'] = module.params.get('force_instance_delete')
-
- creds, params = get_google_cloud_credentials(module)
- spanner_client = spanner.Client(project=params['project_id'],
- credentials=creds,
- user_agent=CLOUD_CLIENT_USER_AGENT)
- changed = False
- json_output = {}
-
- i = None
- if mod_params['instance_id']:
- config_name = get_spanner_configuration_name(
- mod_params['configuration'], params['project_id'])
- i = spanner_client.instance(mod_params['instance_id'],
- configuration_name=config_name)
- d = None
- if mod_params['database_name']:
- # TODO(supertom): support DDL
- ddl_statements = ''
- d = i.database(mod_params['database_name'], ddl_statements)
-
- if mod_params['state'] == 'absent':
- # Remove the most granular resource. If database is specified
- # we remove it. If only instance is specified, that is what is removed.
- if d is not None and d.exists():
- d.drop()
- changed = True
- else:
- if i.exists():
- if mod_params['force_instance_delete']:
- i.delete()
- else:
- module.fail_json(
- msg=(("Cannot delete Spanner instance: "
- "'force_instance_delete' argument not specified")))
- changed = True
- elif mod_params['state'] == 'present':
- if not i.exists():
- i = spanner_client.instance(mod_params['instance_id'],
- configuration_name=config_name,
- display_name=mod_params['instance_display_name'],
- node_count=mod_params['node_count'] or 1)
- i.create()
- changed = True
- else:
- # update instance
- i.reload()
- inst_prev_vals = {}
- if i.display_name != mod_params['instance_display_name']:
- inst_prev_vals['instance_display_name'] = i.display_name
- i.display_name = mod_params['instance_display_name']
- if mod_params['node_count']:
- if i.node_count != mod_params['node_count']:
- inst_prev_vals['node_count'] = i.node_count
- i.node_count = mod_params['node_count']
- if inst_prev_vals:
- changed = instance_update(i)
- json_output['updated'] = changed
- json_output['previous_values'] = {'instance': inst_prev_vals}
- if d:
- if not d.exists():
- d.create()
- d.reload()
- changed = True
-
- json_output['changed'] = changed
- json_output.update(mod_params)
- module.exit_json(**json_output)
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/cloud/google/gc_storage.py b/lib/ansible/modules/cloud/google/gc_storage.py
deleted file mode 100644
index 4fe29eb681..0000000000
--- a/lib/ansible/modules/cloud/google/gc_storage.py
+++ /dev/null
@@ -1,491 +0,0 @@
-#!/usr/bin/python
-#
-# Copyright: Ansible Project
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'community'}
-
-
-DOCUMENTATION = '''
----
-module: gc_storage
-version_added: "1.4"
-short_description: This module manages objects/buckets in Google Cloud Storage.
-description:
- - This module allows users to manage their objects/buckets in Google Cloud Storage. It allows upload and download operations and can set some
- canned permissions. It also allows retrieval of URLs for objects for use in playbooks, and retrieval of string contents of objects. This module
- requires setting the default project in GCS prior to playbook usage. See U(https://developers.google.com/storage/docs/reference/v1/apiversion1) for
- information about setting the default project.
-
-options:
- bucket:
- description:
- - Bucket name.
- required: true
- object:
- description:
- - Keyname of the object inside the bucket. Can be also be used to create "virtual directories" (see examples).
- src:
- description:
- - The source file path when performing a PUT operation.
- dest:
- description:
- - The destination file path when downloading an object/key with a GET operation.
- force:
- description:
- - Forces an overwrite either locally on the filesystem or remotely with the object/key. Used with PUT and GET operations.
- type: bool
- default: 'yes'
- aliases: [ 'overwrite' ]
- permission:
- description:
- - This option let's the user set the canned permissions on the object/bucket that are created. The permissions that can be set are 'private',
- 'public-read', 'authenticated-read'.
- default: private
- headers:
- version_added: "2.0"
- description:
- - Headers to attach to object.
- default: {}
- expiration:
- description:
- - Time limit (in seconds) for the URL generated and returned by GCA when performing a mode=put or mode=get_url operation. This url is only
- available when public-read is the acl for the object.
- mode:
- description:
- - Switches the module behaviour between upload, download, get_url (return download url) , get_str (download object as string), create (bucket) and
- delete (bucket).
- required: true
- choices: [ 'get', 'put', 'get_url', 'get_str', 'delete', 'create' ]
- gs_secret_key:
- description:
- - GS secret key. If not set then the value of the GS_SECRET_ACCESS_KEY environment variable is used.
- required: true
- gs_access_key:
- description:
- - GS access key. If not set then the value of the GS_ACCESS_KEY_ID environment variable is used.
- required: true
- region:
- version_added: "2.4"
- description:
- - The gs region to use. If not defined then the value 'US' will be used. See U(https://cloud.google.com/storage/docs/bucket-locations)
- default: 'US'
- versioning:
- version_added: "2.4"
- description:
- - Whether versioning is enabled or disabled (note that once versioning is enabled, it can only be suspended)
- type: bool
-
-requirements:
- - "python >= 2.6"
- - "boto >= 2.9"
-
-author:
-- Benno Joy (@bennojoy)
-- Lukas Beumer (@Nitaco)
-
-'''
-
-EXAMPLES = '''
-- name: Upload some content
- gc_storage:
- bucket: mybucket
- object: key.txt
- src: /usr/local/myfile.txt
- mode: put
- permission: public-read
-
-- name: Upload some headers
- gc_storage:
- bucket: mybucket
- object: key.txt
- src: /usr/local/myfile.txt
- headers: '{"Content-Encoding": "gzip"}'
-
-- name: Download some content
- gc_storage:
- bucket: mybucket
- object: key.txt
- dest: /usr/local/myfile.txt
- mode: get
-
-- name: Download an object as a string to use else where in your playbook
- gc_storage:
- bucket: mybucket
- object: key.txt
- mode: get_str
-
-- name: Create an empty bucket
- gc_storage:
- bucket: mybucket
- mode: create
-
-- name: Create a bucket with key as directory
- gc_storage:
- bucket: mybucket
- object: /my/directory/path
- mode: create
-
-- name: Delete a bucket and all contents
- gc_storage:
- bucket: mybucket
- mode: delete
-
-- name: Create a bucket with versioning enabled
- gc_storage:
- bucket: "mybucket"
- versioning: yes
- mode: create
-
-- name: Create a bucket located in the eu
- gc_storage:
- bucket: "mybucket"
- region: "europe-west3"
- mode: create
-
-'''
-
-import os
-
-try:
- import boto
- HAS_BOTO = True
-except ImportError:
- HAS_BOTO = False
-
-from ansible.module_utils.basic import AnsibleModule
-
-
-def grant_check(module, gs, obj):
- try:
- acp = obj.get_acl()
- if module.params.get('permission') == 'public-read':
- grant = [x for x in acp.entries.entry_list if x.scope.type == 'AllUsers']
- if not grant:
- obj.set_acl('public-read')
- module.exit_json(changed=True, result="The objects permission as been set to public-read")
- if module.params.get('permission') == 'authenticated-read':
- grant = [x for x in acp.entries.entry_list if x.scope.type == 'AllAuthenticatedUsers']
- if not grant:
- obj.set_acl('authenticated-read')
- module.exit_json(changed=True, result="The objects permission as been set to authenticated-read")
- except gs.provider.storage_response_error as e:
- module.fail_json(msg=str(e))
- return True
-
-
-def key_check(module, gs, bucket, obj):
- try:
- bucket = gs.lookup(bucket)
- key_check = bucket.get_key(obj)
- except gs.provider.storage_response_error as e:
- module.fail_json(msg=str(e))
- if key_check:
- grant_check(module, gs, key_check)
- return True
- else:
- return False
-
-
-def keysum(module, gs, bucket, obj):
- bucket = gs.lookup(bucket)
- key_check = bucket.get_key(obj)
- if not key_check:
- return None
- md5_remote = key_check.etag[1:-1]
- etag_multipart = '-' in md5_remote # Check for multipart, etag is not md5
- if etag_multipart is True:
- module.fail_json(msg="Files uploaded with multipart of gs are not supported with checksum, unable to compute checksum.")
- return md5_remote
-
-
-def bucket_check(module, gs, bucket):
- try:
- result = gs.lookup(bucket)
- except gs.provider.storage_response_error as e:
- module.fail_json(msg=str(e))
- if result:
- grant_check(module, gs, result)
- return True
- else:
- return False
-
-
-def create_bucket(module, gs, bucket):
- try:
- bucket = gs.create_bucket(bucket, transform_headers(module.params.get('headers')), module.params.get('region'))
- bucket.set_acl(module.params.get('permission'))
- bucket.configure_versioning(module.params.get('versioning'))
- except gs.provider.storage_response_error as e:
- module.fail_json(msg=str(e))
- if bucket:
- return True
-
-
-def delete_bucket(module, gs, bucket):
- try:
- bucket = gs.lookup(bucket)
- bucket_contents = bucket.list()
- for key in bucket_contents:
- bucket.delete_key(key.name)
- bucket.delete()
- return True
- except gs.provider.storage_response_error as e:
- module.fail_json(msg=str(e))
-
-
-def delete_key(module, gs, bucket, obj):
- try:
- bucket = gs.lookup(bucket)
- bucket.delete_key(obj)
- module.exit_json(msg="Object deleted from bucket ", changed=True)
- except gs.provider.storage_response_error as e:
- module.fail_json(msg=str(e))
-
-
-def create_dirkey(module, gs, bucket, obj):
- try:
- bucket = gs.lookup(bucket)
- key = bucket.new_key(obj)
- key.set_contents_from_string('')
- module.exit_json(msg="Virtual directory %s created in bucket %s" % (obj, bucket.name), changed=True)
- except gs.provider.storage_response_error as e:
- module.fail_json(msg=str(e))
-
-
-def path_check(path):
- if os.path.exists(path):
- return True
- else:
- return False
-
-
-def transform_headers(headers):
- """
- Boto url-encodes values unless we convert the value to `str`, so doing
- this prevents 'max-age=100000' from being converted to "max-age%3D100000".
-
- :param headers: Headers to convert
- :type headers: dict
- :rtype: dict
-
- """
-
- for key, value in headers.items():
- headers[key] = str(value)
- return headers
-
-
-def upload_gsfile(module, gs, bucket, obj, src, expiry):
- try:
- bucket = gs.lookup(bucket)
- key = bucket.new_key(obj)
- key.set_contents_from_filename(
- filename=src,
- headers=transform_headers(module.params.get('headers'))
- )
- key.set_acl(module.params.get('permission'))
- url = key.generate_url(expiry)
- module.exit_json(msg="PUT operation complete", url=url, changed=True)
- except gs.provider.storage_copy_error as e:
- module.fail_json(msg=str(e))
-
-
-def download_gsfile(module, gs, bucket, obj, dest):
- try:
- bucket = gs.lookup(bucket)
- key = bucket.lookup(obj)
- key.get_contents_to_filename(dest)
- module.exit_json(msg="GET operation complete", changed=True)
- except gs.provider.storage_copy_error as e:
- module.fail_json(msg=str(e))
-
-
-def download_gsstr(module, gs, bucket, obj):
- try:
- bucket = gs.lookup(bucket)
- key = bucket.lookup(obj)
- contents = key.get_contents_as_string()
- module.exit_json(msg="GET operation complete", contents=contents, changed=True)
- except gs.provider.storage_copy_error as e:
- module.fail_json(msg=str(e))
-
-
-def get_download_url(module, gs, bucket, obj, expiry):
- try:
- bucket = gs.lookup(bucket)
- key = bucket.lookup(obj)
- url = key.generate_url(expiry)
- module.exit_json(msg="Download url:", url=url, expiration=expiry, changed=True)
- except gs.provider.storage_response_error as e:
- module.fail_json(msg=str(e))
-
-
-def handle_get(module, gs, bucket, obj, overwrite, dest):
- md5_remote = keysum(module, gs, bucket, obj)
- md5_local = module.md5(dest)
- if md5_local == md5_remote:
- module.exit_json(changed=False)
- if md5_local != md5_remote and not overwrite:
- module.exit_json(msg="WARNING: Checksums do not match. Use overwrite parameter to force download.", failed=True)
- else:
- download_gsfile(module, gs, bucket, obj, dest)
-
-
-def handle_put(module, gs, bucket, obj, overwrite, src, expiration):
- # Lets check to see if bucket exists to get ground truth.
- bucket_rc = bucket_check(module, gs, bucket)
- key_rc = key_check(module, gs, bucket, obj)
-
- # Lets check key state. Does it exist and if it does, compute the etag md5sum.
- if bucket_rc and key_rc:
- md5_remote = keysum(module, gs, bucket, obj)
- md5_local = module.md5(src)
- if md5_local == md5_remote:
- module.exit_json(msg="Local and remote object are identical", changed=False)
- if md5_local != md5_remote and not overwrite:
- module.exit_json(msg="WARNING: Checksums do not match. Use overwrite parameter to force upload.", failed=True)
- else:
- upload_gsfile(module, gs, bucket, obj, src, expiration)
-
- if not bucket_rc:
- create_bucket(module, gs, bucket)
- upload_gsfile(module, gs, bucket, obj, src, expiration)
-
- # If bucket exists but key doesn't, just upload.
- if bucket_rc and not key_rc:
- upload_gsfile(module, gs, bucket, obj, src, expiration)
-
-
-def handle_delete(module, gs, bucket, obj):
- if bucket and not obj:
- if bucket_check(module, gs, bucket):
- module.exit_json(msg="Bucket %s and all keys have been deleted." % bucket, changed=delete_bucket(module, gs, bucket))
- else:
- module.exit_json(msg="Bucket does not exist.", changed=False)
- if bucket and obj:
- if bucket_check(module, gs, bucket):
- if key_check(module, gs, bucket, obj):
- module.exit_json(msg="Object has been deleted.", changed=delete_key(module, gs, bucket, obj))
- else:
- module.exit_json(msg="Object does not exist.", changed=False)
- else:
- module.exit_json(msg="Bucket does not exist.", changed=False)
- else:
- module.fail_json(msg="Bucket or Bucket & object parameter is required.", failed=True)
-
-
-def handle_create(module, gs, bucket, obj):
- if bucket and not obj:
- if bucket_check(module, gs, bucket):
- module.exit_json(msg="Bucket already exists.", changed=False)
- else:
- module.exit_json(msg="Bucket created successfully", changed=create_bucket(module, gs, bucket))
- if bucket and obj:
- if obj.endswith('/'):
- dirobj = obj
- else:
- dirobj = obj + "/"
-
- if bucket_check(module, gs, bucket):
- if key_check(module, gs, bucket, dirobj):
- module.exit_json(msg="Bucket %s and key %s already exists." % (bucket, obj), changed=False)
- else:
- create_dirkey(module, gs, bucket, dirobj)
- else:
- create_bucket(module, gs, bucket)
- create_dirkey(module, gs, bucket, dirobj)
-
-
-def main():
- module = AnsibleModule(
- argument_spec=dict(
- bucket=dict(required=True),
- object=dict(default=None, type='path'),
- src=dict(default=None),
- dest=dict(default=None, type='path'),
- expiration=dict(type='int', default=600, aliases=['expiry']),
- mode=dict(choices=['get', 'put', 'delete', 'create', 'get_url', 'get_str'], required=True),
- permission=dict(choices=['private', 'public-read', 'authenticated-read'], default='private'),
- headers=dict(type='dict', default={}),
- gs_secret_key=dict(no_log=True, required=True),
- gs_access_key=dict(required=True),
- overwrite=dict(default=True, type='bool', aliases=['force']),
- region=dict(default='US', type='str'),
- versioning=dict(default='no', type='bool')
- ),
- )
-
- if not HAS_BOTO:
- module.fail_json(msg='`boto` 2.9+ is required for this module. Try: pip install `boto` --upgrade')
-
- bucket = module.params.get('bucket')
- obj = module.params.get('object')
- src = module.params.get('src')
- dest = module.params.get('dest')
- mode = module.params.get('mode')
- expiry = module.params.get('expiration')
- gs_secret_key = module.params.get('gs_secret_key')
- gs_access_key = module.params.get('gs_access_key')
- overwrite = module.params.get('overwrite')
-
- if mode == 'put':
- if not src or not object:
- module.fail_json(msg="When using PUT, src, bucket, object are mandatory parameters")
- if mode == 'get':
- if not dest or not object:
- module.fail_json(msg="When using GET, dest, bucket, object are mandatory parameters")
-
- try:
- gs = boto.connect_gs(gs_access_key, gs_secret_key)
- except boto.exception.NoAuthHandlerFound as e:
- module.fail_json(msg=str(e))
-
- if mode == 'get':
- if not bucket_check(module, gs, bucket) or not key_check(module, gs, bucket, obj):
- module.fail_json(msg="Target bucket/key cannot be found", failed=True)
- if not path_check(dest):
- download_gsfile(module, gs, bucket, obj, dest)
- else:
- handle_get(module, gs, bucket, obj, overwrite, dest)
-
- if mode == 'put':
- if not path_check(src):
- module.fail_json(msg="Local object for PUT does not exist", failed=True)
- handle_put(module, gs, bucket, obj, overwrite, src, expiry)
-
- # Support for deleting an object if we have both params.
- if mode == 'delete':
- handle_delete(module, gs, bucket, obj)
-
- if mode == 'create':
- handle_create(module, gs, bucket, obj)
-
- if mode == 'get_url':
- if bucket and obj:
- if bucket_check(module, gs, bucket) and key_check(module, gs, bucket, obj):
- get_download_url(module, gs, bucket, obj, expiry)
- else:
- module.fail_json(msg="Key/Bucket does not exist", failed=True)
- else:
- module.fail_json(msg="Bucket and Object parameters must be set", failed=True)
-
- # --------------------------- Get the String contents of an Object -------------------------
- if mode == 'get_str':
- if bucket and obj:
- if bucket_check(module, gs, bucket) and key_check(module, gs, bucket, obj):
- download_gsstr(module, gs, bucket, obj)
- else:
- module.fail_json(msg="Key/Bucket does not exist", failed=True)
- else:
- module.fail_json(msg="Bucket and Object parameters must be set", failed=True)
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/cloud/google/gce_eip.py b/lib/ansible/modules/cloud/google/gce_eip.py
deleted file mode 100644
index 40f8822e91..0000000000
--- a/lib/ansible/modules/cloud/google/gce_eip.py
+++ /dev/null
@@ -1,228 +0,0 @@
-#!/usr/bin/python
-# Copyright 2017 Google Inc.
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'community'}
-
-DOCUMENTATION = '''
-module: gce_eip
-version_added: "2.3"
-short_description: Create or Destroy Global or Regional External IP addresses.
-description:
- - Create (reserve) or Destroy (release) Regional or Global IP Addresses. See
- U(https://cloud.google.com/compute/docs/configure-instance-ip-addresses#reserve_new_static) for more on reserving static addresses.
-requirements:
- - "python >= 2.6"
- - "apache-libcloud >= 0.19.0"
-notes:
- - Global addresses can only be used with Global Forwarding Rules.
-author:
- - "Tom Melendez (@supertom) <tom@supertom.com>"
-options:
- name:
- description:
- - Name of Address.
- required: true
- region:
- description:
- - Region to create the address in. Set to 'global' to create a global address.
- required: true
- state:
- description: The state the address should be in. C(present) or C(absent) are the only valid options.
- default: present
- required: false
- choices: [present, absent]
-'''
-
-EXAMPLES = '''
-# Create a Global external IP address
-- gce_eip:
- service_account_email: "{{ service_account_email }}"
- credentials_file: "{{ credentials_file }}"
- project_id: "{{ project_id }}"
- name: my-global-ip
- region: global
- state: present
-
-# Create a Regional external IP address
-- gce_eip:
- service_account_email: "{{ service_account_email }}"
- credentials_file: "{{ credentials_file }}"
- project_id: "{{ project_id }}"
- name: my-global-ip
- region: us-east1
- state: present
-'''
-
-RETURN = '''
-address:
- description: IP address being operated on
- returned: always
- type: str
- sample: "35.186.222.233"
-name:
- description: name of the address being operated on
- returned: always
- type: str
- sample: "my-address"
-region:
- description: Which region an address belongs.
- returned: always
- type: str
- sample: "global"
-'''
-
-USER_AGENT_VERSION = 'v1'
-USER_AGENT_PRODUCT = 'Ansible-gce_eip'
-
-try:
- from ast import literal_eval
- HAS_PYTHON26 = True
-except ImportError:
- HAS_PYTHON26 = False
-
-try:
- import libcloud
- from libcloud.compute.types import Provider
- from libcloud.compute.providers import get_driver
- from libcloud.common.google import GoogleBaseError, QuotaExceededError, \
- ResourceExistsError, ResourceInUseError, ResourceNotFoundError
- from libcloud.compute.drivers.gce import GCEAddress
- _ = Provider.GCE
- HAS_LIBCLOUD = True
-except ImportError:
- HAS_LIBCLOUD = False
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.gcp import gcp_connect
-
-
-def get_address(gce, name, region):
- """
- Get an Address from GCE.
-
- :param gce: An initialized GCE driver object.
- :type gce: :class: `GCENodeDriver`
-
- :param name: Name of the Address.
- :type name: ``str``
-
- :return: A GCEAddress object or None.
- :rtype: :class: `GCEAddress` or None
- """
- try:
- return gce.ex_get_address(name=name, region=region)
-
- except ResourceNotFoundError:
- return None
-
-
-def create_address(gce, params):
- """
- Create a new Address.
-
- :param gce: An initialized GCE driver object.
- :type gce: :class: `GCENodeDriver`
-
- :param params: Dictionary of parameters needed by the module.
- :type params: ``dict``
-
- :return: Tuple with changed status and address.
- :rtype: tuple in the format of (bool, str)
- """
- changed = False
- return_data = []
-
- address = gce.ex_create_address(
- name=params['name'], region=params['region'])
-
- if address:
- changed = True
- return_data = address.address
-
- return (changed, return_data)
-
-
-def delete_address(address):
- """
- Delete an Address.
-
- :param gce: An initialized GCE driver object.
- :type gce: :class: `GCENodeDriver`
-
- :param params: Dictionary of parameters needed by the module.
- :type params: ``dict``
-
- :return: Tuple with changed status and address.
- :rtype: tuple in the format of (bool, str)
- """
- changed = False
- return_data = []
- if address.destroy():
- changed = True
- return_data = address.address
- return (changed, return_data)
-
-
-def main():
- module = AnsibleModule(argument_spec=dict(
- name=dict(required=True),
- state=dict(choices=['absent', 'present'], default='present'),
- region=dict(required=True),
- service_account_email=dict(),
- service_account_permissions=dict(type='list'),
- pem_file=dict(type='path'),
- credentials_file=dict(type='path'),
- project_id=dict(), ), )
-
- if not HAS_PYTHON26:
- module.fail_json(
- msg="GCE module requires python's 'ast' module, python v2.6+")
- if not HAS_LIBCLOUD:
- module.fail_json(
- msg='libcloud with GCE support (+0.19) required for this module.')
-
- gce = gcp_connect(module, Provider.GCE, get_driver,
- USER_AGENT_PRODUCT, USER_AGENT_VERSION)
-
- params = {}
- params['state'] = module.params.get('state')
- params['name'] = module.params.get('name')
- params['region'] = module.params.get('region')
-
- changed = False
- json_output = {'state': params['state']}
- address = get_address(gce, params['name'], region=params['region'])
-
- if params['state'] == 'absent':
- if not address:
- # Doesn't exist in GCE, and state==absent.
- changed = False
- module.fail_json(
- msg="Cannot delete unknown address: %s" %
- (params['name']))
- else:
- # Delete
- (changed, json_output['address']) = delete_address(address)
- else:
- if not address:
- # Create
- (changed, json_output['address']) = create_address(gce,
- params)
- else:
- changed = False
- json_output['address'] = address.address
-
- json_output['changed'] = changed
- json_output.update(params)
- module.exit_json(**json_output)
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/cloud/google/gce_img.py b/lib/ansible/modules/cloud/google/gce_img.py
deleted file mode 100644
index e5abbbbcbb..0000000000
--- a/lib/ansible/modules/cloud/google/gce_img.py
+++ /dev/null
@@ -1,209 +0,0 @@
-#!/usr/bin/python
-# Copyright 2015 Google Inc. All Rights Reserved.
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-"""An Ansible module to utilize GCE image resources."""
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'community'}
-
-
-DOCUMENTATION = '''
----
-module: gce_img
-version_added: "1.9"
-short_description: utilize GCE image resources
-description:
- - This module can create and delete GCE private images from gzipped
- compressed tarball containing raw disk data or from existing detached
- disks in any zone. U(https://cloud.google.com/compute/docs/images)
-options:
- name:
- description:
- - the name of the image to create or delete
- required: true
- description:
- description:
- - an optional description
- family:
- description:
- - an optional family name
- version_added: "2.2"
- source:
- description:
- - the source disk or the Google Cloud Storage URI to create the image from
- state:
- description:
- - desired state of the image
- default: "present"
- choices: ["present", "absent"]
- zone:
- description:
- - the zone of the disk specified by source
- default: "us-central1-a"
- timeout:
- description:
- - timeout for the operation
- default: 180
- version_added: "2.0"
- service_account_email:
- description:
- - service account email
- pem_file:
- description:
- - path to the pem file associated with the service account email
- project_id:
- description:
- - your GCE project ID
-requirements:
- - "python >= 2.6"
- - "apache-libcloud"
-author: "Tom Melendez (@supertom)"
-'''
-
-EXAMPLES = '''
-# Create an image named test-image from the disk 'test-disk' in zone us-central1-a.
-- gce_img:
- name: test-image
- source: test-disk
- zone: us-central1-a
- state: present
-
-# Create an image named test-image from a tarball in Google Cloud Storage.
-- gce_img:
- name: test-image
- source: https://storage.googleapis.com/bucket/path/to/image.tgz
-
-# Alternatively use the gs scheme
-- gce_img:
- name: test-image
- source: gs://bucket/path/to/image.tgz
-
-# Delete an image named test-image.
-- gce_img:
- name: test-image
- state: absent
-'''
-
-
-try:
- import libcloud
- from libcloud.compute.types import Provider
- from libcloud.compute.providers import get_driver
- from libcloud.common.google import GoogleBaseError
- from libcloud.common.google import ResourceExistsError
- from libcloud.common.google import ResourceNotFoundError
- _ = Provider.GCE
- has_libcloud = True
-except ImportError:
- has_libcloud = False
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.gce import gce_connect
-
-
-GCS_URI = 'https://storage.googleapis.com/'
-
-
-def create_image(gce, name, module):
- """Create an image with the specified name."""
- source = module.params.get('source')
- zone = module.params.get('zone')
- desc = module.params.get('description')
- timeout = module.params.get('timeout')
- family = module.params.get('family')
-
- if not source:
- module.fail_json(msg='Must supply a source', changed=False)
-
- if source.startswith(GCS_URI):
- # source is a Google Cloud Storage URI
- volume = source
- elif source.startswith('gs://'):
- # libcloud only accepts https URI.
- volume = source.replace('gs://', GCS_URI)
- else:
- try:
- volume = gce.ex_get_volume(source, zone)
- except ResourceNotFoundError:
- module.fail_json(msg='Disk %s not found in zone %s' % (source, zone),
- changed=False)
- except GoogleBaseError as e:
- module.fail_json(msg=str(e), changed=False)
-
- gce_extra_args = {}
- if family is not None:
- gce_extra_args['family'] = family
-
- old_timeout = gce.connection.timeout
- try:
- gce.connection.timeout = timeout
- gce.ex_create_image(name, volume, desc, use_existing=False, **gce_extra_args)
- return True
- except ResourceExistsError:
- return False
- except GoogleBaseError as e:
- module.fail_json(msg=str(e), changed=False)
- finally:
- gce.connection.timeout = old_timeout
-
-
-def delete_image(gce, name, module):
- """Delete a specific image resource by name."""
- try:
- gce.ex_delete_image(name)
- return True
- except ResourceNotFoundError:
- return False
- except GoogleBaseError as e:
- module.fail_json(msg=str(e), changed=False)
-
-
-def main():
- module = AnsibleModule(
- argument_spec=dict(
- name=dict(required=True),
- family=dict(),
- description=dict(),
- source=dict(),
- state=dict(default='present', choices=['present', 'absent']),
- zone=dict(default='us-central1-a'),
- service_account_email=dict(),
- pem_file=dict(type='path'),
- project_id=dict(),
- timeout=dict(type='int', default=180)
- )
- )
-
- if not has_libcloud:
- module.fail_json(msg='libcloud with GCE support is required.')
-
- gce = gce_connect(module)
-
- name = module.params.get('name')
- state = module.params.get('state')
- family = module.params.get('family')
- changed = False
-
- if family is not None and hasattr(libcloud, '__version__') and libcloud.__version__ <= '0.20.1':
- module.fail_json(msg="Apache Libcloud 1.0.0+ is required to use 'family' option",
- changed=False)
-
- # user wants to create an image.
- if state == 'present':
- changed = create_image(gce, name, module)
-
- # user wants to delete the image.
- if state == 'absent':
- changed = delete_image(gce, name, module)
-
- module.exit_json(changed=changed, name=name)
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/cloud/google/gce_instance_template.py b/lib/ansible/modules/cloud/google/gce_instance_template.py
deleted file mode 100644
index 1116ac32f5..0000000000
--- a/lib/ansible/modules/cloud/google/gce_instance_template.py
+++ /dev/null
@@ -1,588 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-
-# Copyright: Ansible Project
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'community'}
-
-
-DOCUMENTATION = '''
----
-module: gce_instance_template
-version_added: "2.3"
-short_description: create or destroy instance templates of Compute Engine of GCP.
-description:
- - Creates or destroy Google instance templates
- of Compute Engine of Google Cloud Platform.
-options:
- state:
- description:
- - The desired state for the instance template.
- default: "present"
- choices: ["present", "absent"]
- name:
- description:
- - The name of the GCE instance template.
- required: True
- size:
- description:
- - The desired machine type for the instance template.
- default: "f1-micro"
- source:
- description:
- - A source disk to attach to the instance.
- Cannot specify both I(image) and I(source).
- image:
- description:
- - The image to use to create the instance.
- Cannot specify both both I(image) and I(source).
- image_family:
- description:
- - The image family to use to create the instance.
- If I(image) has been used I(image_family) is ignored.
- Cannot specify both I(image) and I(source).
- disk_type:
- description:
- - Specify a C(pd-standard) disk or C(pd-ssd)
- for an SSD disk.
- default: pd-standard
- disk_auto_delete:
- description:
- - Indicate that the boot disk should be
- deleted when the Node is deleted.
- default: true
- type: bool
- network:
- description:
- - The network to associate with the instance.
- default: "default"
- subnetwork:
- description:
- - The Subnetwork resource name for this instance.
- can_ip_forward:
- description:
- - Set to C(yes) to allow instance to
- send/receive non-matching src/dst packets.
- type: bool
- default: 'no'
- external_ip:
- description:
- - The external IP address to use.
- If C(ephemeral), a new non-static address will be
- used. If C(None), then no external address will
- be used. To use an existing static IP address
- specify address name.
- default: "ephemeral"
- service_account_email:
- description:
- - service account email
- service_account_permissions:
- description:
- - service account permissions (see
- U(https://cloud.google.com/sdk/gcloud/reference/compute/instances/create),
- --scopes section for detailed information)
- choices: [
- "bigquery", "cloud-platform", "compute-ro", "compute-rw",
- "useraccounts-ro", "useraccounts-rw", "datastore", "logging-write",
- "monitoring", "sql-admin", "storage-full", "storage-ro",
- "storage-rw", "taskqueue", "userinfo-email"
- ]
- automatic_restart:
- description:
- - Defines whether the instance should be
- automatically restarted when it is
- terminated by Compute Engine.
- type: bool
- preemptible:
- description:
- - Defines whether the instance is preemptible.
- type: bool
- tags:
- description:
- - a comma-separated list of tags to associate with the instance
- metadata:
- description:
- - a hash/dictionary of custom data for the instance;
- '{"key":"value", ...}'
- description:
- description:
- - description of instance template
- disks:
- description:
- - a list of persistent disks to attach to the instance; a string value
- gives the name of the disk; alternatively, a dictionary value can
- define 'name' and 'mode' ('READ_ONLY' or 'READ_WRITE'). The first entry
- will be the boot disk (which must be READ_WRITE).
- nic_gce_struct:
- description:
- - Support passing in the GCE-specific
- formatted networkInterfaces[] structure.
- disks_gce_struct:
- description:
- - Support passing in the GCE-specific
- formatted formatted disks[] structure. Case sensitive.
- see U(https://cloud.google.com/compute/docs/reference/latest/instanceTemplates#resource) for detailed information
- version_added: "2.4"
- project_id:
- description:
- - your GCE project ID
- pem_file:
- description:
- - path to the pem file associated with the service account email
- This option is deprecated. Use 'credentials_file'.
- credentials_file:
- description:
- - path to the JSON file associated with the service account email
- subnetwork_region:
- version_added: "2.4"
- description:
- - Region that subnetwork resides in. (Required for subnetwork to successfully complete)
-requirements:
- - "python >= 2.6"
- - "apache-libcloud >= 0.13.3, >= 0.17.0 if using JSON credentials,
- >= 0.20.0 if using preemptible option"
-notes:
- - JSON credentials strongly preferred.
-author: "Gwenael Pellen (@GwenaelPellenArkeup) <gwenael.pellen@arkeup.com>"
-'''
-
-EXAMPLES = '''
-# Usage
-- name: create instance template named foo
- gce_instance_template:
- name: foo
- size: n1-standard-1
- image_family: ubuntu-1604-lts
- state: present
- project_id: "your-project-name"
- credentials_file: "/path/to/your-key.json"
- service_account_email: "your-sa@your-project-name.iam.gserviceaccount.com"
-
-# Example Playbook
-- name: Compute Engine Instance Template Examples
- hosts: localhost
- vars:
- service_account_email: "your-sa@your-project-name.iam.gserviceaccount.com"
- credentials_file: "/path/to/your-key.json"
- project_id: "your-project-name"
- tasks:
- - name: create instance template
- gce_instance_template:
- name: my-test-instance-template
- size: n1-standard-1
- image_family: ubuntu-1604-lts
- state: present
- project_id: "{{ project_id }}"
- credentials_file: "{{ credentials_file }}"
- service_account_email: "{{ service_account_email }}"
- - name: delete instance template
- gce_instance_template:
- name: my-test-instance-template
- size: n1-standard-1
- image_family: ubuntu-1604-lts
- state: absent
- project_id: "{{ project_id }}"
- credentials_file: "{{ credentials_file }}"
- service_account_email: "{{ service_account_email }}"
-
-# Example playbook using disks_gce_struct
-- name: Compute Engine Instance Template Examples
- hosts: localhost
- vars:
- service_account_email: "your-sa@your-project-name.iam.gserviceaccount.com"
- credentials_file: "/path/to/your-key.json"
- project_id: "your-project-name"
- tasks:
- - name: create instance template
- gce_instance_template:
- name: foo
- size: n1-standard-1
- state: present
- project_id: "{{ project_id }}"
- credentials_file: "{{ credentials_file }}"
- service_account_email: "{{ service_account_email }}"
- disks_gce_struct:
- - device_name: /dev/sda
- boot: true
- autoDelete: true
- initializeParams:
- diskSizeGb: 30
- diskType: pd-ssd
- sourceImage: projects/debian-cloud/global/images/family/debian-8
-
-'''
-
-RETURN = '''
-'''
-
-import traceback
-try:
- from ast import literal_eval
- HAS_PYTHON26 = True
-except ImportError:
- HAS_PYTHON26 = False
-
-try:
- import libcloud
- from libcloud.compute.types import Provider
- from libcloud.compute.providers import get_driver
- from libcloud.common.google import GoogleBaseError, QuotaExceededError, \
- ResourceExistsError, ResourceInUseError, ResourceNotFoundError
- from libcloud.compute.drivers.gce import GCEAddress
- _ = Provider.GCE
- HAS_LIBCLOUD = True
-except ImportError:
- HAS_LIBCLOUD = False
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.gce import gce_connect
-from ansible.module_utils._text import to_native
-
-
-def get_info(inst):
- """Retrieves instance template information
- """
- return({
- 'name': inst.name,
- 'extra': inst.extra,
- })
-
-
-def create_instance_template(module, gce):
- """Create an instance template
- module : AnsibleModule object
- gce: authenticated GCE libcloud driver
- Returns:
- instance template information
- """
- # get info from module
- name = module.params.get('name')
- size = module.params.get('size')
- source = module.params.get('source')
- image = module.params.get('image')
- image_family = module.params.get('image_family')
- disk_type = module.params.get('disk_type')
- disk_auto_delete = module.params.get('disk_auto_delete')
- network = module.params.get('network')
- subnetwork = module.params.get('subnetwork')
- subnetwork_region = module.params.get('subnetwork_region')
- can_ip_forward = module.params.get('can_ip_forward')
- external_ip = module.params.get('external_ip')
- service_account_permissions = module.params.get(
- 'service_account_permissions')
- service_account_email = module.params.get('service_account_email')
- on_host_maintenance = module.params.get('on_host_maintenance')
- automatic_restart = module.params.get('automatic_restart')
- preemptible = module.params.get('preemptible')
- tags = module.params.get('tags')
- metadata = module.params.get('metadata')
- description = module.params.get('description')
- disks_gce_struct = module.params.get('disks_gce_struct')
- changed = False
-
- # args of ex_create_instancetemplate
- gce_args = dict(
- name="instance",
- size="f1-micro",
- source=None,
- image=None,
- disk_type='pd-standard',
- disk_auto_delete=True,
- network='default',
- subnetwork=None,
- can_ip_forward=None,
- external_ip='ephemeral',
- service_accounts=None,
- on_host_maintenance=None,
- automatic_restart=None,
- preemptible=None,
- tags=None,
- metadata=None,
- description=None,
- disks_gce_struct=None,
- nic_gce_struct=None
- )
-
- gce_args['name'] = name
- gce_args['size'] = size
-
- if source is not None:
- gce_args['source'] = source
-
- if image:
- gce_args['image'] = image
- else:
- if image_family:
- image = gce.ex_get_image_from_family(image_family)
- gce_args['image'] = image
- else:
- gce_args['image'] = "debian-8"
-
- gce_args['disk_type'] = disk_type
- gce_args['disk_auto_delete'] = disk_auto_delete
-
- gce_network = gce.ex_get_network(network)
- gce_args['network'] = gce_network
-
- if subnetwork is not None:
- gce_args['subnetwork'] = gce.ex_get_subnetwork(subnetwork, region=subnetwork_region)
-
- if can_ip_forward is not None:
- gce_args['can_ip_forward'] = can_ip_forward
-
- if external_ip == "ephemeral":
- instance_external_ip = external_ip
- elif external_ip == "none":
- instance_external_ip = None
- else:
- try:
- instance_external_ip = gce.ex_get_address(external_ip)
- except GoogleBaseError as err:
- # external_ip is name ?
- instance_external_ip = external_ip
- gce_args['external_ip'] = instance_external_ip
-
- ex_sa_perms = []
- bad_perms = []
- if service_account_permissions:
- for perm in service_account_permissions:
- if perm not in gce.SA_SCOPES_MAP:
- bad_perms.append(perm)
- if len(bad_perms) > 0:
- module.fail_json(msg='bad permissions: %s' % str(bad_perms))
- if service_account_email is not None:
- ex_sa_perms.append({'email': str(service_account_email)})
- else:
- ex_sa_perms.append({'email': "default"})
- ex_sa_perms[0]['scopes'] = service_account_permissions
- gce_args['service_accounts'] = ex_sa_perms
-
- if on_host_maintenance is not None:
- gce_args['on_host_maintenance'] = on_host_maintenance
-
- if automatic_restart is not None:
- gce_args['automatic_restart'] = automatic_restart
-
- if preemptible is not None:
- gce_args['preemptible'] = preemptible
-
- if tags is not None:
- gce_args['tags'] = tags
-
- if disks_gce_struct is not None:
- gce_args['disks_gce_struct'] = disks_gce_struct
-
- # Try to convert the user's metadata value into the format expected
- # by GCE. First try to ensure user has proper quoting of a
- # dictionary-like syntax using 'literal_eval', then convert the python
- # dict into a python list of 'key' / 'value' dicts. Should end up
- # with:
- # [ {'key': key1, 'value': value1}, {'key': key2, 'value': value2}, ...]
- if metadata:
- if isinstance(metadata, dict):
- md = metadata
- else:
- try:
- md = literal_eval(str(metadata))
- if not isinstance(md, dict):
- raise ValueError('metadata must be a dict')
- except ValueError as e:
- module.fail_json(msg='bad metadata: %s' % str(e))
- except SyntaxError as e:
- module.fail_json(msg='bad metadata syntax')
-
- if hasattr(libcloud, '__version__') and libcloud.__version__ < '0.15':
- items = []
- for k, v in md.items():
- items.append({"key": k, "value": v})
- metadata = {'items': items}
- else:
- metadata = md
- gce_args['metadata'] = metadata
-
- if description is not None:
- gce_args['description'] = description
-
- instance = None
- try:
- instance = gce.ex_get_instancetemplate(name)
- except ResourceNotFoundError:
- try:
- instance = gce.ex_create_instancetemplate(**gce_args)
- changed = True
- except GoogleBaseError as err:
- module.fail_json(
- msg='Unexpected error attempting to create instance {0}, error: {1}'
- .format(
- instance,
- err.value
- )
- )
-
- if instance:
- json_data = get_info(instance)
- else:
- module.fail_json(msg="no instance template!")
-
- return (changed, json_data, name)
-
-
-def delete_instance_template(module, gce):
- """ Delete instance template.
- module : AnsibleModule object
- gce: authenticated GCE libcloud driver
- Returns:
- instance template information
- """
- name = module.params.get('name')
- current_state = "absent"
- changed = False
-
- # get instance template
- instance = None
- try:
- instance = gce.ex_get_instancetemplate(name)
- current_state = "present"
- except GoogleBaseError as e:
- json_data = dict(msg='instance template not exists: %s' % to_native(e),
- exception=traceback.format_exc())
-
- if current_state == "present":
- rc = instance.destroy()
- if rc:
- changed = True
- else:
- module.fail_json(
- msg='instance template destroy failed'
- )
-
- json_data = {}
- return (changed, json_data, name)
-
-
-def module_controller(module, gce):
- ''' Control module state parameter.
- module : AnsibleModule object
- gce: authenticated GCE libcloud driver
- Returns:
- nothing
- Exit:
- AnsibleModule object exit with json data.
- '''
- json_output = dict()
- state = module.params.get("state")
- if state == "present":
- (changed, output, name) = create_instance_template(module, gce)
- json_output['changed'] = changed
- json_output['msg'] = output
- elif state == "absent":
- (changed, output, name) = delete_instance_template(module, gce)
- json_output['changed'] = changed
- json_output['msg'] = output
-
- module.exit_json(**json_output)
-
-
-def check_if_system_state_would_be_changed(module, gce):
- ''' check_if_system_state_would_be_changed !
- module : AnsibleModule object
- gce: authenticated GCE libcloud driver
- Returns:
- system_state changed
- '''
- changed = False
- current_state = "absent"
-
- state = module.params.get("state")
- name = module.params.get("name")
-
- try:
- gce.ex_get_instancetemplate(name)
- current_state = "present"
- except GoogleBaseError as e:
- module.fail_json(msg='GCE get instancetemplate problem: %s' % to_native(e),
- exception=traceback.format_exc())
-
- if current_state != state:
- changed = True
-
- if current_state == "absent":
- if changed:
- output = 'instance template {0} will be created'.format(name)
- else:
- output = 'nothing to do for instance template {0} '.format(name)
- if current_state == "present":
- if changed:
- output = 'instance template {0} will be destroyed'.format(name)
- else:
- output = 'nothing to do for instance template {0} '.format(name)
-
- return (changed, output)
-
-
-def main():
- module = AnsibleModule(
- argument_spec=dict(
- state=dict(choices=['present', 'absent'], default='present'),
- name=dict(required=True, aliases=['base_name']),
- size=dict(default='f1-micro'),
- source=dict(),
- image=dict(),
- image_family=dict(default='debian-8'),
- disk_type=dict(choices=['pd-standard', 'pd-ssd'], default='pd-standard', type='str'),
- disk_auto_delete=dict(type='bool', default=True),
- network=dict(default='default'),
- subnetwork=dict(),
- can_ip_forward=dict(type='bool', default=False),
- external_ip=dict(default='ephemeral'),
- service_account_email=dict(),
- service_account_permissions=dict(type='list'),
- automatic_restart=dict(type='bool', default=None),
- preemptible=dict(type='bool', default=None),
- tags=dict(type='list'),
- metadata=dict(),
- description=dict(),
- disks=dict(type='list'),
- nic_gce_struct=dict(type='list'),
- project_id=dict(),
- pem_file=dict(type='path'),
- credentials_file=dict(type='path'),
- subnetwork_region=dict(),
- disks_gce_struct=dict(type='list')
- ),
- mutually_exclusive=[['source', 'image']],
- required_one_of=[['image', 'image_family']],
- supports_check_mode=True
- )
-
- if not HAS_PYTHON26:
- module.fail_json(
- msg="GCE module requires python's 'ast' module, python v2.6+")
- if not HAS_LIBCLOUD:
- module.fail_json(
- msg='libcloud with GCE support (0.17.0+) required for this module')
-
- try:
- gce = gce_connect(module)
- except GoogleBaseError as e:
- module.fail_json(msg='GCE Connection failed %s' % to_native(e), exception=traceback.format_exc())
-
- if module.check_mode:
- (changed, output) = check_if_system_state_would_be_changed(module, gce)
- module.exit_json(
- changed=changed,
- msg=output
- )
- else:
- module_controller(module, gce)
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/cloud/google/gce_labels.py b/lib/ansible/modules/cloud/google/gce_labels.py
deleted file mode 100644
index 004da50c09..0000000000
--- a/lib/ansible/modules/cloud/google/gce_labels.py
+++ /dev/null
@@ -1,324 +0,0 @@
-#!/usr/bin/python
-# Copyright 2017 Google Inc.
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'community'}
-
-
-DOCUMENTATION = '''
----
-module: gce_labels
-version_added: '2.4'
-short_description: Create, Update or Destroy GCE Labels.
-description:
- - Create, Update or Destroy GCE Labels on instances, disks, snapshots, etc.
- When specifying the GCE resource, users may specify the full URL for
- the resource (its 'self_link'), or the individual parameters of the
- resource (type, location, name). Examples for the two options can be
- seen in the documentation.
- See U(https://cloud.google.com/compute/docs/label-or-tag-resources) for
- more information about GCE Labels. Labels are gradually being added to
- more GCE resources, so this module will need to be updated as new
- resources are added to the GCE (v1) API.
-requirements:
- - 'python >= 2.6'
- - 'google-api-python-client >= 1.6.2'
- - 'google-auth >= 1.0.0'
- - 'google-auth-httplib2 >= 0.0.2'
-notes:
- - Labels support resources such as instances, disks, images, etc. See
- U(https://cloud.google.com/compute/docs/labeling-resources) for the list
- of resources available in the GCE v1 API (not alpha or beta).
-author:
- - 'Eric Johnson (@erjohnso) <erjohnso@google.com>'
-options:
- labels:
- description:
- - A list of labels (key/value pairs) to add or remove for the resource.
- required: false
- resource_url:
- description:
- - The 'self_link' for the resource (instance, disk, snapshot, etc)
- required: false
- resource_type:
- description:
- - The type of resource (instances, disks, snapshots, images)
- required: false
- resource_location:
- description:
- - The location of resource (global, us-central1-f, etc.)
- required: false
- resource_name:
- description:
- - The name of resource.
- required: false
-'''
-
-EXAMPLES = '''
-- name: Add labels on an existing instance (using resource_url)
- gce_labels:
- service_account_email: "{{ service_account_email }}"
- credentials_file: "{{ credentials_file }}"
- project_id: "{{ project_id }}"
- labels:
- webserver-frontend: homepage
- environment: test
- experiment-name: kennedy
- resource_url: https://www.googleapis.com/compute/beta/projects/myproject/zones/us-central1-f/instances/example-instance
- state: present
-- name: Add labels on an image (using resource params)
- gce_labels:
- service_account_email: "{{ service_account_email }}"
- credentials_file: "{{ credentials_file }}"
- project_id: "{{ project_id }}"
- labels:
- webserver-frontend: homepage
- environment: test
- experiment-name: kennedy
- resource_type: images
- resource_location: global
- resource_name: my-custom-image
- state: present
-- name: Remove specified labels from the GCE instance
- gce_labels:
- service_account_email: "{{ service_account_email }}"
- credentials_file: "{{ credentials_file }}"
- project_id: "{{ project_id }}"
- labels:
- environment: prod
- experiment-name: kennedy
- resource_url: https://www.googleapis.com/compute/beta/projects/myproject/zones/us-central1-f/instances/example-instance
- state: absent
-'''
-
-RETURN = '''
-labels:
- description: List of labels that exist on the resource.
- returned: Always.
- type: dict
- sample: [ { 'webserver-frontend': 'homepage', 'environment': 'test', 'environment-name': 'kennedy' } ]
-resource_url:
- description: The 'self_link' of the GCE resource.
- returned: Always.
- type: str
- sample: 'https://www.googleapis.com/compute/beta/projects/myproject/zones/us-central1-f/instances/example-instance'
-resource_type:
- description: The type of the GCE resource.
- returned: Always.
- type: str
- sample: instances
-resource_location:
- description: The location of the GCE resource.
- returned: Always.
- type: str
- sample: us-central1-f
-resource_name:
- description: The name of the GCE resource.
- returned: Always.
- type: str
- sample: my-happy-little-instance
-state:
- description: state of the labels
- returned: Always.
- type: str
- sample: present
-'''
-
-try:
- from ast import literal_eval
- HAS_PYTHON26 = True
-except ImportError:
- HAS_PYTHON26 = False
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.gcp import check_params, get_google_api_client, GCPUtils
-
-
-UA_PRODUCT = 'ansible-gce_labels'
-UA_VERSION = '0.0.1'
-GCE_API_VERSION = 'v1'
-
-# TODO(all): As Labels are added to more GCE resources, this list will need to
-# be updated (along with some code changes below). The list can *only* include
-# resources from the 'v1' GCE API and will *not* work with 'beta' or 'alpha'.
-KNOWN_RESOURCES = ['instances', 'disks', 'snapshots', 'images']
-
-
-def _fetch_resource(client, module):
- params = module.params
- if params['resource_url']:
- if not params['resource_url'].startswith('https://www.googleapis.com/compute'):
- module.fail_json(
- msg='Invalid self_link url: %s' % params['resource_url'])
- else:
- parts = params['resource_url'].split('/')[8:]
- if len(parts) == 2:
- resource_type, resource_name = parts
- resource_location = 'global'
- else:
- resource_location, resource_type, resource_name = parts
- else:
- if not params['resource_type'] or not params['resource_location'] \
- or not params['resource_name']:
- module.fail_json(msg='Missing required resource params.')
- resource_type = params['resource_type'].lower()
- resource_name = params['resource_name'].lower()
- resource_location = params['resource_location'].lower()
-
- if resource_type not in KNOWN_RESOURCES:
- module.fail_json(msg='Unsupported resource_type: %s' % resource_type)
-
- # TODO(all): See the comment above for KNOWN_RESOURCES. As labels are
- # added to the v1 GCE API for more resources, some minor code work will
- # need to be added here.
- if resource_type == 'instances':
- resource = client.instances().get(project=params['project_id'],
- zone=resource_location,
- instance=resource_name).execute()
- elif resource_type == 'disks':
- resource = client.disks().get(project=params['project_id'],
- zone=resource_location,
- disk=resource_name).execute()
- elif resource_type == 'snapshots':
- resource = client.snapshots().get(project=params['project_id'],
- snapshot=resource_name).execute()
- elif resource_type == 'images':
- resource = client.images().get(project=params['project_id'],
- image=resource_name).execute()
- else:
- module.fail_json(msg='Unsupported resource type: %s' % resource_type)
-
- return resource.get('labelFingerprint', ''), {
- 'resource_name': resource.get('name'),
- 'resource_url': resource.get('selfLink'),
- 'resource_type': resource_type,
- 'resource_location': resource_location,
- 'labels': resource.get('labels', {})
- }
-
-
-def _set_labels(client, new_labels, module, ri, fingerprint):
- params = module.params
- result = err = None
- labels = {
- 'labels': new_labels,
- 'labelFingerprint': fingerprint
- }
-
- # TODO(all): See the comment above for KNOWN_RESOURCES. As labels are
- # added to the v1 GCE API for more resources, some minor code work will
- # need to be added here.
- if ri['resource_type'] == 'instances':
- req = client.instances().setLabels(project=params['project_id'],
- instance=ri['resource_name'],
- zone=ri['resource_location'],
- body=labels)
- elif ri['resource_type'] == 'disks':
- req = client.disks().setLabels(project=params['project_id'],
- zone=ri['resource_location'],
- resource=ri['resource_name'],
- body=labels)
- elif ri['resource_type'] == 'snapshots':
- req = client.snapshots().setLabels(project=params['project_id'],
- resource=ri['resource_name'],
- body=labels)
- elif ri['resource_type'] == 'images':
- req = client.images().setLabels(project=params['project_id'],
- resource=ri['resource_name'],
- body=labels)
- else:
- module.fail_json(msg='Unsupported resource type: %s' % ri['resource_type'])
-
- # TODO(erjohnso): Once Labels goes GA, we'll be able to use the GCPUtils
- # method to poll for the async request/operation to complete before
- # returning. However, during 'beta', we are in an odd state where
- # API requests must be sent to the 'compute/beta' API, but the python
- # client library only allows for *Operations.get() requests to be
- # sent to 'compute/v1' API. The response operation is in the 'beta'
- # API-scope, but the client library cannot find the operation (404).
- # result = GCPUtils.execute_api_client_req(req, client=client, raw=False)
- # return result, err
- result = req.execute()
- return True, err
-
-
-def main():
- module = AnsibleModule(
- argument_spec=dict(
- state=dict(choices=['absent', 'present'], default='present'),
- service_account_email=dict(),
- service_account_permissions=dict(type='list'),
- pem_file=dict(),
- credentials_file=dict(),
- labels=dict(required=False, type='dict', default={}),
- resource_url=dict(required=False, type='str'),
- resource_name=dict(required=False, type='str'),
- resource_location=dict(required=False, type='str'),
- resource_type=dict(required=False, type='str'),
- project_id=dict()
- ),
- required_together=[
- ['resource_name', 'resource_location', 'resource_type']
- ],
- mutually_exclusive=[
- ['resource_url', 'resource_name'],
- ['resource_url', 'resource_location'],
- ['resource_url', 'resource_type']
- ]
- )
-
- if not HAS_PYTHON26:
- module.fail_json(
- msg="GCE module requires python's 'ast' module, python v2.6+")
-
- client, cparams = get_google_api_client(module, 'compute',
- user_agent_product=UA_PRODUCT,
- user_agent_version=UA_VERSION,
- api_version=GCE_API_VERSION)
-
- # Get current resource info including labelFingerprint
- fingerprint, resource_info = _fetch_resource(client, module)
- new_labels = resource_info['labels'].copy()
-
- update_needed = False
- if module.params['state'] == 'absent':
- for k, v in module.params['labels'].items():
- if k in new_labels:
- if new_labels[k] == v:
- update_needed = True
- new_labels.pop(k, None)
- else:
- module.fail_json(msg="Could not remove unmatched label pair '%s':'%s'" % (k, v))
- else:
- for k, v in module.params['labels'].items():
- if k not in new_labels:
- update_needed = True
- new_labels[k] = v
-
- changed = False
- json_output = {'state': module.params['state']}
- if update_needed:
- changed, err = _set_labels(client, new_labels, module, resource_info,
- fingerprint)
- json_output['changed'] = changed
-
- # TODO(erjohnso): probably want to re-fetch the resource to return the
- # new labelFingerprint, check that desired labels match updated labels.
- # BUT! Will need to wait for setLabels() to hit v1 API so we can use the
- # GCPUtils feature to poll for the operation to be complete. For now,
- # we'll just update the output with what we have from the original
- # state of the resource.
- json_output.update(resource_info)
- json_output.update(module.params)
-
- module.exit_json(**json_output)
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/cloud/google/gce_lb.py b/lib/ansible/modules/cloud/google/gce_lb.py
deleted file mode 100644
index 1bfa0c58bf..0000000000
--- a/lib/ansible/modules/cloud/google/gce_lb.py
+++ /dev/null
@@ -1,302 +0,0 @@
-#!/usr/bin/python
-# Copyright 2013 Google Inc.
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'community'}
-
-
-DOCUMENTATION = '''
----
-module: gce_lb
-version_added: "1.5"
-short_description: create/destroy GCE load-balancer resources
-description:
- - This module can create and destroy Google Compute Engine C(loadbalancer)
- and C(httphealthcheck) resources. The primary LB resource is the
- C(load_balancer) resource and the health check parameters are all
- prefixed with I(httphealthcheck).
- The full documentation for Google Compute Engine load balancing is at
- U(https://developers.google.com/compute/docs/load-balancing/). However,
- the ansible module simplifies the configuration by following the
- libcloud model.
- Full install/configuration instructions for the gce* modules can
- be found in the comments of ansible/test/gce_tests.py.
-options:
- httphealthcheck_name:
- description:
- - the name identifier for the HTTP health check
- httphealthcheck_port:
- description:
- - the TCP port to use for HTTP health checking
- default: 80
- httphealthcheck_path:
- description:
- - the url path to use for HTTP health checking
- default: "/"
- httphealthcheck_interval:
- description:
- - the duration in seconds between each health check request
- default: 5
- httphealthcheck_timeout:
- description:
- - the timeout in seconds before a request is considered a failed check
- default: 5
- httphealthcheck_unhealthy_count:
- description:
- - number of consecutive failed checks before marking a node unhealthy
- default: 2
- httphealthcheck_healthy_count:
- description:
- - number of consecutive successful checks before marking a node healthy
- default: 2
- httphealthcheck_host:
- description:
- - host header to pass through on HTTP check requests
- name:
- description:
- - name of the load-balancer resource
- protocol:
- description:
- - the protocol used for the load-balancer packet forwarding, tcp or udp
- default: "tcp"
- choices: ['tcp', 'udp']
- region:
- description:
- - the GCE region where the load-balancer is defined
- external_ip:
- description:
- - the external static IPv4 (or auto-assigned) address for the LB
- port_range:
- description:
- - the port (range) to forward, e.g. 80 or 8000-8888 defaults to all ports
- members:
- description:
- - a list of zone/nodename pairs, e.g ['us-central1-a/www-a', ...]
- aliases: ['nodes']
- state:
- description:
- - desired state of the LB
- default: "present"
- choices: ["active", "present", "absent", "deleted"]
- service_account_email:
- version_added: "1.6"
- description:
- - service account email
- pem_file:
- version_added: "1.6"
- description:
- - path to the pem file associated with the service account email
- This option is deprecated. Use 'credentials_file'.
- credentials_file:
- version_added: "2.1.0"
- description:
- - path to the JSON file associated with the service account email
- project_id:
- version_added: "1.6"
- description:
- - your GCE project ID
-
-requirements:
- - "python >= 2.6"
- - "apache-libcloud >= 0.13.3, >= 0.17.0 if using JSON credentials"
-author: "Eric Johnson (@erjohnso) <erjohnso@google.com>"
-'''
-
-EXAMPLES = '''
-# Simple example of creating a new LB, adding members, and a health check
-- local_action:
- module: gce_lb
- name: testlb
- region: us-central1
- members: ["us-central1-a/www-a", "us-central1-b/www-b"]
- httphealthcheck_name: hc
- httphealthcheck_port: 80
- httphealthcheck_path: "/up"
-'''
-
-try:
- from libcloud.compute.types import Provider
- from libcloud.compute.providers import get_driver
- from libcloud.loadbalancer.types import Provider as Provider_lb
- from libcloud.loadbalancer.providers import get_driver as get_driver_lb
- from libcloud.common.google import GoogleBaseError, QuotaExceededError, ResourceExistsError, ResourceNotFoundError
-
- _ = Provider.GCE
- HAS_LIBCLOUD = True
-except ImportError:
- HAS_LIBCLOUD = False
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.gce import USER_AGENT_PRODUCT, USER_AGENT_VERSION, gce_connect, unexpected_error_msg
-
-
-def main():
- module = AnsibleModule(
- argument_spec=dict(
- httphealthcheck_name=dict(),
- httphealthcheck_port=dict(default=80, type='int'),
- httphealthcheck_path=dict(default='/'),
- httphealthcheck_interval=dict(default=5, type='int'),
- httphealthcheck_timeout=dict(default=5, type='int'),
- httphealthcheck_unhealthy_count=dict(default=2, type='int'),
- httphealthcheck_healthy_count=dict(default=2, type='int'),
- httphealthcheck_host=dict(),
- name=dict(),
- protocol=dict(default='tcp'),
- region=dict(),
- external_ip=dict(),
- port_range=dict(),
- members=dict(type='list'),
- state=dict(default='present'),
- service_account_email=dict(),
- pem_file=dict(type='path'),
- credentials_file=dict(type='path'),
- project_id=dict(),
- )
- )
-
- if not HAS_LIBCLOUD:
- module.fail_json(msg='libcloud with GCE support (0.13.3+) required for this module.')
-
- gce = gce_connect(module)
-
- httphealthcheck_name = module.params.get('httphealthcheck_name')
- httphealthcheck_port = module.params.get('httphealthcheck_port')
- httphealthcheck_path = module.params.get('httphealthcheck_path')
- httphealthcheck_interval = module.params.get('httphealthcheck_interval')
- httphealthcheck_timeout = module.params.get('httphealthcheck_timeout')
- httphealthcheck_unhealthy_count = module.params.get('httphealthcheck_unhealthy_count')
- httphealthcheck_healthy_count = module.params.get('httphealthcheck_healthy_count')
- httphealthcheck_host = module.params.get('httphealthcheck_host')
- name = module.params.get('name')
- protocol = module.params.get('protocol')
- region = module.params.get('region')
- external_ip = module.params.get('external_ip')
- port_range = module.params.get('port_range')
- members = module.params.get('members')
- state = module.params.get('state')
-
- try:
- gcelb = get_driver_lb(Provider_lb.GCE)(gce_driver=gce)
- gcelb.connection.user_agent_append("%s/%s" % (
- USER_AGENT_PRODUCT, USER_AGENT_VERSION))
- except Exception as e:
- module.fail_json(msg=unexpected_error_msg(e), changed=False)
-
- changed = False
- json_output = {'name': name, 'state': state}
-
- if not name and not httphealthcheck_name:
- module.fail_json(msg='Nothing to do, please specify a "name" ' + 'or "httphealthcheck_name" parameter', changed=False)
-
- if state in ['active', 'present']:
- # first, create the httphealthcheck if requested
- hc = None
- if httphealthcheck_name:
- json_output['httphealthcheck_name'] = httphealthcheck_name
- try:
- hc = gcelb.ex_create_healthcheck(httphealthcheck_name,
- host=httphealthcheck_host, path=httphealthcheck_path,
- port=httphealthcheck_port,
- interval=httphealthcheck_interval,
- timeout=httphealthcheck_timeout,
- unhealthy_threshold=httphealthcheck_unhealthy_count,
- healthy_threshold=httphealthcheck_healthy_count)
- changed = True
- except ResourceExistsError:
- hc = gce.ex_get_healthcheck(httphealthcheck_name)
- except Exception as e:
- module.fail_json(msg=unexpected_error_msg(e), changed=False)
-
- if hc is not None:
- json_output['httphealthcheck_host'] = hc.extra['host']
- json_output['httphealthcheck_path'] = hc.path
- json_output['httphealthcheck_port'] = hc.port
- json_output['httphealthcheck_interval'] = hc.interval
- json_output['httphealthcheck_timeout'] = hc.timeout
- json_output['httphealthcheck_unhealthy_count'] = hc.unhealthy_threshold
- json_output['httphealthcheck_healthy_count'] = hc.healthy_threshold
-
- # create the forwarding rule (and target pool under the hood)
- lb = None
- if name:
- if not region:
- module.fail_json(msg='Missing required region name',
- changed=False)
- nodes = []
- output_nodes = []
- json_output['name'] = name
- # members is a python list of 'zone/inst' strings
- if members:
- for node in members:
- try:
- zone, node_name = node.split('/')
- nodes.append(gce.ex_get_node(node_name, zone))
- output_nodes.append(node)
- except Exception:
- # skip nodes that are badly formatted or don't exist
- pass
- try:
- if hc is not None:
- lb = gcelb.create_balancer(name, port_range, protocol,
- None, nodes, ex_region=region, ex_healthchecks=[hc],
- ex_address=external_ip)
- else:
- lb = gcelb.create_balancer(name, port_range, protocol,
- None, nodes, ex_region=region, ex_address=external_ip)
- changed = True
- except ResourceExistsError:
- lb = gcelb.get_balancer(name)
- except Exception as e:
- module.fail_json(msg=unexpected_error_msg(e), changed=False)
-
- if lb is not None:
- json_output['members'] = output_nodes
- json_output['protocol'] = protocol
- json_output['region'] = region
- json_output['external_ip'] = lb.ip
- json_output['port_range'] = lb.port
- hc_names = []
- if 'healthchecks' in lb.extra:
- for hc in lb.extra['healthchecks']:
- hc_names.append(hc.name)
- json_output['httphealthchecks'] = hc_names
-
- if state in ['absent', 'deleted']:
- # first, delete the load balancer (forwarding rule and target pool)
- # if specified.
- if name:
- json_output['name'] = name
- try:
- lb = gcelb.get_balancer(name)
- gcelb.destroy_balancer(lb)
- changed = True
- except ResourceNotFoundError:
- pass
- except Exception as e:
- module.fail_json(msg=unexpected_error_msg(e), changed=False)
-
- # destroy the health check if specified
- if httphealthcheck_name:
- json_output['httphealthcheck_name'] = httphealthcheck_name
- try:
- hc = gce.ex_get_healthcheck(httphealthcheck_name)
- gce.ex_destroy_healthcheck(hc)
- changed = True
- except ResourceNotFoundError:
- pass
- except Exception as e:
- module.fail_json(msg=unexpected_error_msg(e), changed=False)
-
- json_output['changed'] = changed
- module.exit_json(**json_output)
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/cloud/google/gce_mig.py b/lib/ansible/modules/cloud/google/gce_mig.py
deleted file mode 100644
index 0a251517b7..0000000000
--- a/lib/ansible/modules/cloud/google/gce_mig.py
+++ /dev/null
@@ -1,887 +0,0 @@
-#!/usr/bin/python
-# Copyright 2016 Google Inc.
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'community'}
-
-
-DOCUMENTATION = '''
----
-module: gce_mig
-version_added: "2.2"
-short_description: Create, Update or Destroy a Managed Instance Group (MIG).
-description:
- - Create, Update or Destroy a Managed Instance Group (MIG). See
- U(https://cloud.google.com/compute/docs/instance-groups) for an overview.
- Full install/configuration instructions for the gce* modules can
- be found in the comments of ansible/test/gce_tests.py.
-requirements:
- - "python >= 2.6"
- - "apache-libcloud >= 1.2.0"
-notes:
- - Resizing and Recreating VM are also supported.
- - An existing instance template is required in order to create a
- Managed Instance Group.
-author:
- - "Tom Melendez (@supertom) <tom@supertom.com>"
-options:
- name:
- description:
- - Name of the Managed Instance Group.
- required: true
- template:
- description:
- - Instance Template to be used in creating the VMs. See
- U(https://cloud.google.com/compute/docs/instance-templates) to learn more
- about Instance Templates. Required for creating MIGs.
- size:
- description:
- - Size of Managed Instance Group. If MIG already exists, it will be
- resized to the number provided here. Required for creating MIGs.
- service_account_email:
- description:
- - service account email
- credentials_file:
- description:
- - Path to the JSON file associated with the service account email
- project_id:
- description:
- - GCE project ID
- state:
- description:
- - desired state of the resource
- default: "present"
- choices: ["absent", "present"]
- zone:
- description:
- - The GCE zone to use for this Managed Instance Group.
- required: true
- autoscaling:
- description:
- - A dictionary of configuration for the autoscaler. 'enabled (bool)', 'name (str)'
- and policy.max_instances (int) are required fields if autoscaling is used. See
- U(https://cloud.google.com/compute/docs/reference/beta/autoscalers) for more information
- on Autoscaling.
- named_ports:
- version_added: "2.3"
- description:
- - Define named ports that backend services can forward data to. Format is a a list of
- name:port dictionaries.
-'''
-
-EXAMPLES = '''
-# Following playbook creates, rebuilds instances, resizes and then deletes a MIG.
-# Notes:
-# - Two valid Instance Templates must exist in your GCE project in order to run
-# this playbook. Change the fields to match the templates used in your
-# project.
-# - The use of the 'pause' module is not required, it is just for convenience.
-- name: Managed Instance Group Example
- hosts: localhost
- gather_facts: False
- tasks:
- - name: Create MIG
- gce_mig:
- name: ansible-mig-example
- zone: us-central1-c
- state: present
- size: 1
- template: my-instance-template-1
- named_ports:
- - name: http
- port: 80
- - name: foobar
- port: 82
-
- - name: Pause for 30 seconds
- pause:
- seconds: 30
-
- - name: Recreate MIG Instances with Instance Template change.
- gce_mig:
- name: ansible-mig-example
- zone: us-central1-c
- state: present
- template: my-instance-template-2-small
- recreate_instances: yes
-
- - name: Pause for 30 seconds
- pause:
- seconds: 30
-
- - name: Resize MIG
- gce_mig:
- name: ansible-mig-example
- zone: us-central1-c
- state: present
- size: 3
-
- - name: Update MIG with Autoscaler
- gce_mig:
- name: ansible-mig-example
- zone: us-central1-c
- state: present
- size: 3
- template: my-instance-template-2-small
- recreate_instances: yes
- autoscaling:
- enabled: yes
- name: my-autoscaler
- policy:
- min_instances: 2
- max_instances: 5
- cool_down_period: 37
- cpu_utilization:
- target: .39
- load_balancing_utilization:
- target: 0.4
-
- - name: Pause for 30 seconds
- pause:
- seconds: 30
-
- - name: Delete MIG
- gce_mig:
- name: ansible-mig-example
- zone: us-central1-c
- state: absent
- autoscaling:
- enabled: no
- name: my-autoscaler
-'''
-RETURN = '''
-zone:
- description: Zone in which to launch MIG.
- returned: always
- type: str
- sample: "us-central1-b"
-
-template:
- description: Instance Template to use for VMs. Must exist prior to using with MIG.
- returned: changed
- type: str
- sample: "my-instance-template"
-
-name:
- description: Name of the Managed Instance Group.
- returned: changed
- type: str
- sample: "my-managed-instance-group"
-
-named_ports:
- description: list of named ports acted upon
- returned: when named_ports are initially set or updated
- type: list
- sample: [{ "name": "http", "port": 80 }, { "name": "foo", "port": 82 }]
-
-size:
- description: Number of VMs in Managed Instance Group.
- returned: changed
- type: int
- sample: 4
-
-created_instances:
- description: Names of instances created.
- returned: When instances are created.
- type: list
- sample: ["ansible-mig-new-0k4y", "ansible-mig-new-0zk5", "ansible-mig-new-kp68"]
-
-deleted_instances:
- description: Names of instances deleted.
- returned: When instances are deleted.
- type: list
- sample: ["ansible-mig-new-0k4y", "ansible-mig-new-0zk5", "ansible-mig-new-kp68"]
-
-resize_created_instances:
- description: Names of instances created during resizing.
- returned: When a resize results in the creation of instances.
- type: list
- sample: ["ansible-mig-new-0k4y", "ansible-mig-new-0zk5", "ansible-mig-new-kp68"]
-
-resize_deleted_instances:
- description: Names of instances deleted during resizing.
- returned: When a resize results in the deletion of instances.
- type: list
- sample: ["ansible-mig-new-0k4y", "ansible-mig-new-0zk5", "ansible-mig-new-kp68"]
-
-recreated_instances:
- description: Names of instances recreated.
- returned: When instances are recreated.
- type: list
- sample: ["ansible-mig-new-0k4y", "ansible-mig-new-0zk5", "ansible-mig-new-kp68"]
-
-created_autoscaler:
- description: True if Autoscaler was attempted and created. False otherwise.
- returned: When the creation of an Autoscaler was attempted.
- type: bool
- sample: true
-
-updated_autoscaler:
- description: True if an Autoscaler update was attempted and succeeded.
- False returned if update failed.
- returned: When the update of an Autoscaler was attempted.
- type: bool
- sample: true
-
-deleted_autoscaler:
- description: True if an Autoscaler delete attempted and succeeded.
- False returned if delete failed.
- returned: When the delete of an Autoscaler was attempted.
- type: bool
- sample: true
-
-set_named_ports:
- description: True if the named_ports have been set
- returned: named_ports have been set
- type: bool
- sample: true
-
-updated_named_ports:
- description: True if the named_ports have been updated
- returned: named_ports have been updated
- type: bool
- sample: true
-'''
-
-try:
- from ast import literal_eval
- HAS_PYTHON26 = True
-except ImportError:
- HAS_PYTHON26 = False
-
-try:
- import libcloud
- from libcloud.compute.types import Provider
- from libcloud.compute.providers import get_driver
- from libcloud.common.google import GoogleBaseError, QuotaExceededError, \
- ResourceExistsError, ResourceInUseError, ResourceNotFoundError
- from libcloud.compute.drivers.gce import GCEAddress
- _ = Provider.GCE
- HAS_LIBCLOUD = True
-except ImportError:
- HAS_LIBCLOUD = False
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.gce import gce_connect
-
-
-def _check_params(params, field_list):
- """
- Helper to validate params.
-
- Use this in function definitions if they require specific fields
- to be present.
-
- :param params: structure that contains the fields
- :type params: ``dict``
-
- :param field_list: list of dict representing the fields
- [{'name': str, 'required': True/False', 'type': cls}]
- :type field_list: ``list`` of ``dict``
-
- :return True, exits otherwise
- :rtype: ``bool``
- """
- for d in field_list:
- if not d['name'] in params:
- if d['required'] is True:
- return (False, "%s is required and must be of type: %s" %
- (d['name'], str(d['type'])))
- else:
- if not isinstance(params[d['name']], d['type']):
- return (False,
- "%s must be of type: %s" % (d['name'], str(d['type'])))
-
- return (True, '')
-
-
-def _validate_autoscaling_params(params):
- """
- Validate that the minimum configuration is present for autoscaling.
-
- :param params: Ansible dictionary containing autoscaling configuration
- It is expected that autoscaling config will be found at the
- key 'autoscaling'.
- :type params: ``dict``
-
- :return: Tuple containing a boolean and a string. True if autoscaler
- is valid, False otherwise, plus str for message.
- :rtype: ``(``bool``, ``str``)``
- """
- if not params['autoscaling']:
- # It's optional, so if not set at all, it's valid.
- return (True, '')
- if not isinstance(params['autoscaling'], dict):
- return (False,
- 'autoscaling: configuration expected to be a dictionary.')
-
- # check first-level required fields
- as_req_fields = [
- {'name': 'name', 'required': True, 'type': str},
- {'name': 'enabled', 'required': True, 'type': bool},
- {'name': 'policy', 'required': True, 'type': dict}
- ] # yapf: disable
-
- (as_req_valid, as_req_msg) = _check_params(params['autoscaling'],
- as_req_fields)
- if not as_req_valid:
- return (False, as_req_msg)
-
- # check policy configuration
- as_policy_fields = [
- {'name': 'max_instances', 'required': True, 'type': int},
- {'name': 'min_instances', 'required': False, 'type': int},
- {'name': 'cool_down_period', 'required': False, 'type': int}
- ] # yapf: disable
-
- (as_policy_valid, as_policy_msg) = _check_params(
- params['autoscaling']['policy'], as_policy_fields)
- if not as_policy_valid:
- return (False, as_policy_msg)
-
- # TODO(supertom): check utilization fields
-
- return (True, '')
-
-
-def _validate_named_port_params(params):
- """
- Validate the named ports parameters
-
- :param params: Ansible dictionary containing named_ports configuration
- It is expected that autoscaling config will be found at the
- key 'named_ports'. That key should contain a list of
- {name : port} dictionaries.
- :type params: ``dict``
-
- :return: Tuple containing a boolean and a string. True if params
- are valid, False otherwise, plus str for message.
- :rtype: ``(``bool``, ``str``)``
- """
- if not params['named_ports']:
- # It's optional, so if not set at all, it's valid.
- return (True, '')
- if not isinstance(params['named_ports'], list):
- return (False, 'named_ports: expected list of name:port dictionaries.')
- req_fields = [
- {'name': 'name', 'required': True, 'type': str},
- {'name': 'port', 'required': True, 'type': int}
- ] # yapf: disable
-
- for np in params['named_ports']:
- (valid_named_ports, np_msg) = _check_params(np, req_fields)
- if not valid_named_ports:
- return (False, np_msg)
-
- return (True, '')
-
-
-def _get_instance_list(mig, field='name', filter_list=None):
- """
- Helper to grab field from instances response.
-
- :param mig: Managed Instance Group Object from libcloud.
- :type mig: :class: `GCEInstanceGroupManager`
-
- :param field: Field name in list_managed_instances response. Defaults
- to 'name'.
- :type field: ``str``
-
- :param filter_list: list of 'currentAction' strings to filter on. Only
- items that match a currentAction in this list will
- be returned. Default is "['NONE']".
- :type filter_list: ``list`` of ``str``
-
- :return: List of strings from list_managed_instances response.
- :rtype: ``list``
- """
- filter_list = ['NONE'] if filter_list is None else filter_list
-
- return [x[field] for x in mig.list_managed_instances()
- if x['currentAction'] in filter_list]
-
-
-def _gen_gce_as_policy(as_params):
- """
- Take Autoscaler params and generate GCE-compatible policy.
-
- :param as_params: Dictionary in Ansible-playbook format
- containing policy arguments.
- :type as_params: ``dict``
-
- :return: GCE-compatible policy dictionary
- :rtype: ``dict``
- """
- asp_data = {}
- asp_data['maxNumReplicas'] = as_params['max_instances']
- if 'min_instances' in as_params:
- asp_data['minNumReplicas'] = as_params['min_instances']
- if 'cool_down_period' in as_params:
- asp_data['coolDownPeriodSec'] = as_params['cool_down_period']
- if 'cpu_utilization' in as_params and 'target' in as_params[
- 'cpu_utilization']:
- asp_data['cpuUtilization'] = {'utilizationTarget':
- as_params['cpu_utilization']['target']}
- if 'load_balancing_utilization' in as_params and 'target' in as_params[
- 'load_balancing_utilization']:
- asp_data['loadBalancingUtilization'] = {
- 'utilizationTarget':
- as_params['load_balancing_utilization']['target']
- }
-
- return asp_data
-
-
-def create_autoscaler(gce, mig, params):
- """
- Create a new Autoscaler for a MIG.
-
- :param gce: An initialized GCE driver object.
- :type gce: :class: `GCENodeDriver`
-
- :param mig: An initialized GCEInstanceGroupManager.
- :type mig: :class: `GCEInstanceGroupManager`
-
- :param params: Dictionary of autoscaling parameters.
- :type params: ``dict``
-
- :return: Tuple with changed stats.
- :rtype: tuple in the format of (bool, list)
- """
- changed = False
- as_policy = _gen_gce_as_policy(params['policy'])
- autoscaler = gce.ex_create_autoscaler(name=params['name'], zone=mig.zone,
- instance_group=mig, policy=as_policy)
- if autoscaler:
- changed = True
- return changed
-
-
-def update_autoscaler(gce, autoscaler, params):
- """
- Update an Autoscaler.
-
- Takes an existing Autoscaler object, and updates it with
- the supplied params before calling libcloud's update method.
-
- :param gce: An initialized GCE driver object.
- :type gce: :class: `GCENodeDriver`
-
- :param autoscaler: An initialized GCEAutoscaler.
- :type autoscaler: :class: `GCEAutoscaler`
-
- :param params: Dictionary of autoscaling parameters.
- :type params: ``dict``
-
- :return: True if changes, False otherwise.
- :rtype: ``bool``
- """
- as_policy = _gen_gce_as_policy(params['policy'])
- if autoscaler.policy != as_policy:
- autoscaler.policy = as_policy
- autoscaler = gce.ex_update_autoscaler(autoscaler)
- if autoscaler:
- return True
- return False
-
-
-def delete_autoscaler(autoscaler):
- """
- Delete an Autoscaler. Does not affect MIG.
-
- :param mig: Managed Instance Group Object from Libcloud.
- :type mig: :class: `GCEInstanceGroupManager`
-
- :return: Tuple with changed stats and a list of affected instances.
- :rtype: tuple in the format of (bool, list)
- """
- changed = False
- if autoscaler.destroy():
- changed = True
- return changed
-
-
-def get_autoscaler(gce, name, zone):
- """
- Get an Autoscaler from GCE.
-
- If the Autoscaler is not found, None is found.
-
- :param gce: An initialized GCE driver object.
- :type gce: :class: `GCENodeDriver`
-
- :param name: Name of the Autoscaler.
- :type name: ``str``
-
- :param zone: Zone that the Autoscaler is located in.
- :type zone: ``str``
-
- :return: A GCEAutoscaler object or None.
- :rtype: :class: `GCEAutoscaler` or None
- """
- try:
- # Does the Autoscaler already exist?
- return gce.ex_get_autoscaler(name, zone)
-
- except ResourceNotFoundError:
- return None
-
-
-def create_mig(gce, params):
- """
- Create a new Managed Instance Group.
-
- :param gce: An initialized GCE driver object.
- :type gce: :class: `GCENodeDriver`
-
- :param params: Dictionary of parameters needed by the module.
- :type params: ``dict``
-
- :return: Tuple with changed stats and a list of affected instances.
- :rtype: tuple in the format of (bool, list)
- """
-
- changed = False
- return_data = []
- actions_filter = ['CREATING']
-
- mig = gce.ex_create_instancegroupmanager(
- name=params['name'], size=params['size'], template=params['template'],
- zone=params['zone'])
-
- if mig:
- changed = True
- return_data = _get_instance_list(mig, filter_list=actions_filter)
-
- return (changed, return_data)
-
-
-def delete_mig(mig):
- """
- Delete a Managed Instance Group. All VMs in that MIG are also deleted."
-
- :param mig: Managed Instance Group Object from Libcloud.
- :type mig: :class: `GCEInstanceGroupManager`
-
- :return: Tuple with changed stats and a list of affected instances.
- :rtype: tuple in the format of (bool, list)
- """
- changed = False
- return_data = []
- actions_filter = ['NONE', 'CREATING', 'RECREATING', 'DELETING',
- 'ABANDONING', 'RESTARTING', 'REFRESHING']
- instance_names = _get_instance_list(mig, filter_list=actions_filter)
- if mig.destroy():
- changed = True
- return_data = instance_names
-
- return (changed, return_data)
-
-
-def recreate_instances_in_mig(mig):
- """
- Recreate the instances for a Managed Instance Group.
-
- :param mig: Managed Instance Group Object from libcloud.
- :type mig: :class: `GCEInstanceGroupManager`
-
- :return: Tuple with changed stats and a list of affected instances.
- :rtype: tuple in the format of (bool, list)
- """
- changed = False
- return_data = []
- actions_filter = ['RECREATING']
-
- if mig.recreate_instances():
- changed = True
- return_data = _get_instance_list(mig, filter_list=actions_filter)
-
- return (changed, return_data)
-
-
-def resize_mig(mig, size):
- """
- Resize a Managed Instance Group.
-
- Based on the size provided, GCE will automatically create and delete
- VMs as needed.
-
- :param mig: Managed Instance Group Object from libcloud.
- :type mig: :class: `GCEInstanceGroupManager`
-
- :return: Tuple with changed stats and a list of affected instances.
- :rtype: tuple in the format of (bool, list)
- """
- changed = False
- return_data = []
- actions_filter = ['CREATING', 'DELETING']
-
- if mig.resize(size):
- changed = True
- return_data = _get_instance_list(mig, filter_list=actions_filter)
-
- return (changed, return_data)
-
-
-def get_mig(gce, name, zone):
- """
- Get a Managed Instance Group from GCE.
-
- If the MIG is not found, None is found.
-
- :param gce: An initialized GCE driver object.
- :type gce: :class: `GCENodeDriver`
-
- :param name: Name of the Managed Instance Group.
- :type name: ``str``
-
- :param zone: Zone that the Managed Instance Group is located in.
- :type zone: ``str``
-
- :return: A GCEInstanceGroupManager object or None.
- :rtype: :class: `GCEInstanceGroupManager` or None
- """
- try:
- # Does the MIG already exist?
- return gce.ex_get_instancegroupmanager(name=name, zone=zone)
-
- except ResourceNotFoundError:
- return None
-
-
-def update_named_ports(mig, named_ports):
- """
- Set the named ports on a Managed Instance Group.
-
- Sort the existing named ports and new. If different, update.
- This also implicitly allows for the removal of named_por
-
- :param mig: Managed Instance Group Object from libcloud.
- :type mig: :class: `GCEInstanceGroupManager`
-
- :param named_ports: list of dictionaries in the format of {'name': port}
- :type named_ports: ``list`` of ``dict``
-
- :return: True if successful
- :rtype: ``bool``
- """
- changed = False
- existing_ports = []
- new_ports = []
- if hasattr(mig.instance_group, 'named_ports'):
- existing_ports = sorted(mig.instance_group.named_ports,
- key=lambda x: x['name'])
- if named_ports is not None:
- new_ports = sorted(named_ports, key=lambda x: x['name'])
-
- if existing_ports != new_ports:
- if mig.instance_group.set_named_ports(named_ports):
- changed = True
-
- return changed
-
-
-def main():
- module = AnsibleModule(argument_spec=dict(
- name=dict(required=True),
- template=dict(),
- recreate_instances=dict(type='bool', default=False),
- # Do not set a default size here. For Create and some update
- # operations, it is required and should be explicitly set.
- # Below, we set it to the existing value if it has not been set.
- size=dict(type='int'),
- state=dict(choices=['absent', 'present'], default='present'),
- zone=dict(required=True),
- autoscaling=dict(type='dict', default=None),
- named_ports=dict(type='list', default=None),
- service_account_email=dict(),
- service_account_permissions=dict(type='list'),
- pem_file=dict(type='path'),
- credentials_file=dict(type='path'),
- project_id=dict(), ), )
-
- if not HAS_PYTHON26:
- module.fail_json(
- msg="GCE module requires python's 'ast' module, python v2.6+")
- if not HAS_LIBCLOUD:
- module.fail_json(
- msg='libcloud with GCE Managed Instance Group support (1.2+) required for this module.')
-
- gce = gce_connect(module)
- if not hasattr(gce, 'ex_create_instancegroupmanager'):
- module.fail_json(
- msg='libcloud with GCE Managed Instance Group support (1.2+) required for this module.',
- changed=False)
-
- params = {}
- params['state'] = module.params.get('state')
- params['zone'] = module.params.get('zone')
- params['name'] = module.params.get('name')
- params['size'] = module.params.get('size')
- params['template'] = module.params.get('template')
- params['recreate_instances'] = module.params.get('recreate_instances')
- params['autoscaling'] = module.params.get('autoscaling', None)
- params['named_ports'] = module.params.get('named_ports', None)
-
- (valid_autoscaling, as_msg) = _validate_autoscaling_params(params)
- if not valid_autoscaling:
- module.fail_json(msg=as_msg, changed=False)
-
- if params['named_ports'] is not None and not hasattr(
- gce, 'ex_instancegroup_set_named_ports'):
- module.fail_json(
- msg="Apache Libcloud 1.3.0+ is required to use 'named_ports' option",
- changed=False)
-
- (valid_named_ports, np_msg) = _validate_named_port_params(params)
- if not valid_named_ports:
- module.fail_json(msg=np_msg, changed=False)
-
- changed = False
- json_output = {'state': params['state'], 'zone': params['zone']}
- mig = get_mig(gce, params['name'], params['zone'])
-
- if not mig:
- if params['state'] == 'absent':
- # Doesn't exist in GCE, and state==absent.
- changed = False
- module.fail_json(
- msg="Cannot delete unknown managed instance group: %s" %
- (params['name']))
- else:
- # Create MIG
- req_create_fields = [
- {'name': 'template', 'required': True, 'type': str},
- {'name': 'size', 'required': True, 'type': int}
- ] # yapf: disable
-
- (valid_create_fields, valid_create_msg) = _check_params(
- params, req_create_fields)
- if not valid_create_fields:
- module.fail_json(msg=valid_create_msg, changed=False)
-
- (changed, json_output['created_instances']) = create_mig(gce,
- params)
- if params['autoscaling'] and params['autoscaling'][
- 'enabled'] is True:
- # Fetch newly-created MIG and create Autoscaler for it.
- mig = get_mig(gce, params['name'], params['zone'])
- if not mig:
- module.fail_json(
- msg='Unable to fetch created MIG %s to create \
- autoscaler in zone: %s' % (
- params['name'], params['zone']), changed=False)
-
- if not create_autoscaler(gce, mig, params['autoscaling']):
- module.fail_json(
- msg='Unable to fetch MIG %s to create autoscaler \
- in zone: %s' % (params['name'], params['zone']),
- changed=False)
-
- json_output['created_autoscaler'] = True
- # Add named ports if available
- if params['named_ports']:
- mig = get_mig(gce, params['name'], params['zone'])
- if not mig:
- module.fail_json(
- msg='Unable to fetch created MIG %s to create \
- autoscaler in zone: %s' % (
- params['name'], params['zone']), changed=False)
- json_output['set_named_ports'] = update_named_ports(
- mig, params['named_ports'])
- if json_output['set_named_ports']:
- json_output['named_ports'] = params['named_ports']
-
- elif params['state'] == 'absent':
- # Delete MIG
-
- # First, check and remove the autoscaler, if present.
- # Note: multiple autoscalers can be associated to a single MIG. We
- # only handle the one that is named, but we might want to think about this.
- if params['autoscaling']:
- autoscaler = get_autoscaler(gce, params['autoscaling']['name'],
- params['zone'])
- if not autoscaler:
- module.fail_json(msg='Unable to fetch autoscaler %s to delete \
- in zone: %s' % (params['autoscaling']['name'], params['zone']),
- changed=False)
-
- changed = delete_autoscaler(autoscaler)
- json_output['deleted_autoscaler'] = changed
-
- # Now, delete the MIG.
- (changed, json_output['deleted_instances']) = delete_mig(mig)
-
- else:
- # Update MIG
-
- # If we're going to update a MIG, we need a size and template values.
- # If not specified, we use the values from the existing MIG.
- if not params['size']:
- params['size'] = mig.size
-
- if not params['template']:
- params['template'] = mig.template.name
-
- if params['template'] != mig.template.name:
- # Update Instance Template.
- new_template = gce.ex_get_instancetemplate(params['template'])
- mig.set_instancetemplate(new_template)
- json_output['updated_instancetemplate'] = True
- changed = True
- if params['recreate_instances'] is True:
- # Recreate Instances.
- (changed, json_output['recreated_instances']
- ) = recreate_instances_in_mig(mig)
-
- if params['size'] != mig.size:
- # Resize MIG.
- keystr = 'created' if params['size'] > mig.size else 'deleted'
- (changed, json_output['resize_%s_instances' %
- (keystr)]) = resize_mig(mig, params['size'])
-
- # Update Autoscaler
- if params['autoscaling']:
- autoscaler = get_autoscaler(gce, params['autoscaling']['name'],
- params['zone'])
- if not autoscaler:
- # Try to create autoscaler.
- # Note: this isn't perfect, if the autoscaler name has changed
- # we wouldn't know that here.
- if not create_autoscaler(gce, mig, params['autoscaling']):
- module.fail_json(
- msg='Unable to create autoscaler %s for existing MIG %s\
- in zone: %s' % (params['autoscaling']['name'],
- params['name'], params['zone']),
- changed=False)
- json_output['created_autoscaler'] = True
- changed = True
- else:
- if params['autoscaling']['enabled'] is False:
- # Delete autoscaler
- changed = delete_autoscaler(autoscaler)
- json_output['delete_autoscaler'] = changed
- else:
- # Update policy, etc.
- changed = update_autoscaler(gce, autoscaler,
- params['autoscaling'])
- json_output['updated_autoscaler'] = changed
- named_ports = params['named_ports'] or []
- json_output['updated_named_ports'] = update_named_ports(mig,
- named_ports)
- if json_output['updated_named_ports']:
- json_output['named_ports'] = named_ports
-
- json_output['changed'] = changed
- json_output.update(params)
- module.exit_json(**json_output)
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/cloud/google/gce_net.py b/lib/ansible/modules/cloud/google/gce_net.py
deleted file mode 100644
index a1a418eb61..0000000000
--- a/lib/ansible/modules/cloud/google/gce_net.py
+++ /dev/null
@@ -1,513 +0,0 @@
-#!/usr/bin/python
-# Copyright 2013 Google Inc.
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'community'}
-
-
-DOCUMENTATION = '''
----
-module: gce_net
-version_added: "1.5"
-short_description: create/destroy GCE networks and firewall rules
-description:
- - This module can create and destroy Google Compute Engine networks and
- firewall rules U(https://cloud.google.com/compute/docs/networking).
- The I(name) parameter is reserved for referencing a network while the
- I(fwname) parameter is used to reference firewall rules.
- IPv4 Address ranges must be specified using the CIDR
- U(http://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing) format.
- Full install/configuration instructions for the gce* modules can
- be found in the comments of ansible/test/gce_tests.py.
-options:
- allowed:
- description:
- - the protocol:ports to allow (I(tcp:80) or I(tcp:80,443) or I(tcp:80-800;udp:1-25))
- this parameter is mandatory when creating or updating a firewall rule
- ipv4_range:
- description:
- - the IPv4 address range in CIDR notation for the network
- this parameter is not mandatory when you specified existing network in name parameter,
- but when you create new network, this parameter is mandatory
- aliases: ['cidr']
- fwname:
- description:
- - name of the firewall rule
- aliases: ['fwrule']
- name:
- description:
- - name of the network
- src_range:
- description:
- - the source IPv4 address range in CIDR notation
- default: []
- aliases: ['src_cidr']
- src_tags:
- description:
- - the source instance tags for creating a firewall rule
- default: []
- target_tags:
- version_added: "1.9"
- description:
- - the target instance tags for creating a firewall rule
- default: []
- state:
- description:
- - desired state of the network or firewall
- default: "present"
- choices: ["active", "present", "absent", "deleted"]
- service_account_email:
- version_added: "1.6"
- description:
- - service account email
- pem_file:
- version_added: "1.6"
- description:
- - path to the pem file associated with the service account email
- This option is deprecated. Use C(credentials_file).
- credentials_file:
- version_added: "2.1.0"
- description:
- - path to the JSON file associated with the service account email
- project_id:
- version_added: "1.6"
- description:
- - your GCE project ID
- mode:
- version_added: "2.2"
- description:
- - network mode for Google Cloud
- C(legacy) indicates a network with an IP address range;
- C(auto) automatically generates subnetworks in different regions;
- C(custom) uses networks to group subnets of user specified IP address ranges
- https://cloud.google.com/compute/docs/networking#network_types
- default: "legacy"
- choices: ["legacy", "auto", "custom"]
- subnet_name:
- version_added: "2.2"
- description:
- - name of subnet to create
- subnet_region:
- version_added: "2.2"
- description:
- - region of subnet to create
- subnet_desc:
- version_added: "2.2"
- description:
- - description of subnet to create
-
-requirements:
- - "python >= 2.6"
- - "apache-libcloud >= 0.13.3, >= 0.17.0 if using JSON credentials"
-author: "Eric Johnson (@erjohnso) <erjohnso@google.com>, Tom Melendez (@supertom) <supertom@google.com>"
-'''
-
-EXAMPLES = '''
-# Create a 'legacy' Network
-- name: Create Legacy Network
- gce_net:
- name: legacynet
- ipv4_range: '10.24.17.0/24'
- mode: legacy
- state: present
-
-# Create an 'auto' Network
-- name: Create Auto Network
- gce_net:
- name: autonet
- mode: auto
- state: present
-
-# Create a 'custom' Network
-- name: Create Custom Network
- gce_net:
- name: customnet
- mode: custom
- subnet_name: "customsubnet"
- subnet_region: us-east1
- ipv4_range: '10.240.16.0/24'
- state: "present"
-
-# Create Firewall Rule with Source Tags
-- name: Create Firewall Rule w/Source Tags
- gce_net:
- name: default
- fwname: "my-firewall-rule"
- allowed: tcp:80
- state: "present"
- src_tags: "foo,bar"
-
-# Create Firewall Rule with Source Range
-- name: Create Firewall Rule w/Source Range
- gce_net:
- name: default
- fwname: "my-firewall-rule"
- allowed: tcp:80
- state: "present"
- src_range: ['10.1.1.1/32']
-
-# Create Custom Subnetwork
-- name: Create Custom Subnetwork
- gce_net:
- name: privatenet
- mode: custom
- subnet_name: subnet_example
- subnet_region: us-central1
- ipv4_range: '10.0.0.0/16'
-'''
-
-RETURN = '''
-allowed:
- description: Rules (ports and protocols) specified by this firewall rule.
- returned: When specified
- type: str
- sample: "tcp:80;icmp"
-
-fwname:
- description: Name of the firewall rule.
- returned: When specified
- type: str
- sample: "my-fwname"
-
-ipv4_range:
- description: IPv4 range of the specified network or subnetwork.
- returned: when specified or when a subnetwork is created
- type: str
- sample: "10.0.0.0/16"
-
-name:
- description: Name of the network.
- returned: always
- type: str
- sample: "my-network"
-
-src_range:
- description: IP address blocks a firewall rule applies to.
- returned: when specified
- type: list
- sample: [ '10.1.1.12/8' ]
-
-src_tags:
- description: Instance Tags firewall rule applies to.
- returned: when specified while creating a firewall rule
- type: list
- sample: [ 'foo', 'bar' ]
-
-state:
- description: State of the item operated on.
- returned: always
- type: str
- sample: "present"
-
-subnet_name:
- description: Name of the subnetwork.
- returned: when specified or when a subnetwork is created
- type: str
- sample: "my-subnetwork"
-
-subnet_region:
- description: Region of the specified subnet.
- returned: when specified or when a subnetwork is created
- type: str
- sample: "us-east1"
-
-target_tags:
- description: Instance Tags with these tags receive traffic allowed by firewall rule.
- returned: when specified while creating a firewall rule
- type: list
- sample: [ 'foo', 'bar' ]
-'''
-try:
- from libcloud.compute.types import Provider
- from libcloud.compute.providers import get_driver
- from libcloud.common.google import GoogleBaseError, QuotaExceededError, ResourceExistsError, ResourceNotFoundError
- _ = Provider.GCE
- HAS_LIBCLOUD = True
-except ImportError:
- HAS_LIBCLOUD = False
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.gce import gce_connect, unexpected_error_msg
-
-
-def format_allowed_section(allowed):
- """Format each section of the allowed list"""
- if allowed.count(":") == 0:
- protocol = allowed
- ports = []
- elif allowed.count(":") == 1:
- protocol, ports = allowed.split(":")
- else:
- return []
- if ports.count(","):
- ports = ports.split(",")
- elif ports:
- ports = [ports]
- return_val = {"IPProtocol": protocol}
- if ports:
- return_val["ports"] = ports
- return return_val
-
-
-def format_allowed(allowed):
- """Format the 'allowed' value so that it is GCE compatible."""
- return_value = []
- if allowed.count(";") == 0:
- return [format_allowed_section(allowed)]
- else:
- sections = allowed.split(";")
- for section in sections:
- return_value.append(format_allowed_section(section))
- return return_value
-
-
-def sorted_allowed_list(allowed_list):
- """Sort allowed_list (output of format_allowed) by protocol and port."""
- # sort by protocol
- allowed_by_protocol = sorted(allowed_list, key=lambda x: x['IPProtocol'])
- # sort the ports list
- return sorted(allowed_by_protocol, key=lambda y: sorted(y.get('ports', [])))
-
-
-def main():
- module = AnsibleModule(
- argument_spec=dict(
- allowed=dict(),
- ipv4_range=dict(),
- fwname=dict(),
- name=dict(),
- src_range=dict(default=[], type='list'),
- src_tags=dict(default=[], type='list'),
- target_tags=dict(default=[], type='list'),
- state=dict(default='present'),
- service_account_email=dict(),
- pem_file=dict(type='path'),
- credentials_file=dict(type='path'),
- project_id=dict(),
- mode=dict(default='legacy', choices=['legacy', 'auto', 'custom']),
- subnet_name=dict(),
- subnet_region=dict(),
- subnet_desc=dict(),
- )
- )
-
- if not HAS_LIBCLOUD:
- module.fail_json(msg='libcloud with GCE support (0.17.0+) required for this module')
-
- gce = gce_connect(module)
-
- allowed = module.params.get('allowed')
- ipv4_range = module.params.get('ipv4_range')
- fwname = module.params.get('fwname')
- name = module.params.get('name')
- src_range = module.params.get('src_range')
- src_tags = module.params.get('src_tags')
- target_tags = module.params.get('target_tags')
- state = module.params.get('state')
- mode = module.params.get('mode')
- subnet_name = module.params.get('subnet_name')
- subnet_region = module.params.get('subnet_region')
- subnet_desc = module.params.get('subnet_desc')
-
- changed = False
- json_output = {'state': state}
-
- if state in ['active', 'present']:
- network = None
- subnet = None
- try:
- network = gce.ex_get_network(name)
- json_output['name'] = name
- if mode == 'legacy':
- json_output['ipv4_range'] = network.cidr
- if network and mode == 'custom' and subnet_name:
- if not hasattr(gce, 'ex_get_subnetwork'):
- module.fail_json(msg="Update libcloud to a more recent version (>1.0) that supports network 'mode' parameter", changed=False)
-
- subnet = gce.ex_get_subnetwork(subnet_name, region=subnet_region)
- json_output['subnet_name'] = subnet_name
- json_output['ipv4_range'] = subnet.cidr
- except ResourceNotFoundError:
- pass
- except Exception as e:
- module.fail_json(msg=unexpected_error_msg(e), changed=False)
-
- # user wants to create a new network that doesn't yet exist
- if name and not network:
- if not ipv4_range and mode != 'auto':
- module.fail_json(msg="Network '" + name + "' is not found. To create network in legacy or custom mode, 'ipv4_range' parameter is required",
- changed=False)
- args = [ipv4_range if mode == 'legacy' else None]
- kwargs = {}
- if mode != 'legacy':
- kwargs['mode'] = mode
-
- try:
- network = gce.ex_create_network(name, *args, **kwargs)
- json_output['name'] = name
- json_output['ipv4_range'] = ipv4_range
- changed = True
- except TypeError:
- module.fail_json(msg="Update libcloud to a more recent version (>1.0) that supports network 'mode' parameter", changed=False)
- except Exception as e:
- module.fail_json(msg=unexpected_error_msg(e), changed=False)
-
- if (subnet_name or ipv4_range) and not subnet and mode == 'custom':
- if not hasattr(gce, 'ex_create_subnetwork'):
- module.fail_json(msg='Update libcloud to a more recent version (>1.0) that supports subnetwork creation', changed=changed)
- if not subnet_name or not ipv4_range or not subnet_region:
- module.fail_json(msg="subnet_name, ipv4_range, and subnet_region required for custom mode", changed=changed)
-
- try:
- subnet = gce.ex_create_subnetwork(subnet_name, cidr=ipv4_range, network=name, region=subnet_region, description=subnet_desc)
- json_output['subnet_name'] = subnet_name
- json_output['ipv4_range'] = ipv4_range
- changed = True
- except Exception as e:
- module.fail_json(msg=unexpected_error_msg(e), changed=changed)
-
- if fwname:
- # user creating a firewall rule
- if not allowed and not src_range and not src_tags:
- if changed and network:
- module.fail_json(
- msg="Network created, but missing required " + "firewall rule parameter(s)", changed=True)
- module.fail_json(
- msg="Missing required firewall rule parameter(s)",
- changed=False)
-
- allowed_list = format_allowed(allowed)
-
- # Fetch existing rule and if it exists, compare attributes
- # update if attributes changed. Create if doesn't exist.
- try:
- fw_changed = False
- fw = gce.ex_get_firewall(fwname)
-
- # If old and new attributes are different, we update the firewall rule.
- # This implicitly lets us clear out attributes as well.
- # allowed_list is required and must not be None for firewall rules.
- if allowed_list and (sorted_allowed_list(allowed_list) != sorted_allowed_list(fw.allowed)):
- fw.allowed = allowed_list
- fw_changed = True
-
- # source_ranges might not be set in the project; cast it to an empty list
- fw.source_ranges = fw.source_ranges or []
-
- # If these attributes are lists, we sort them first, then compare.
- # Otherwise, we update if they differ.
- if fw.source_ranges != src_range:
- if isinstance(src_range, list):
- if sorted(fw.source_ranges) != sorted(src_range):
- fw.source_ranges = src_range
- fw_changed = True
- else:
- fw.source_ranges = src_range
- fw_changed = True
-
- # source_tags might not be set in the project; cast it to an empty list
- fw.source_tags = fw.source_tags or []
-
- if fw.source_tags != src_tags:
- if isinstance(src_tags, list):
- if sorted(fw.source_tags) != sorted(src_tags):
- fw.source_tags = src_tags
- fw_changed = True
- else:
- fw.source_tags = src_tags
- fw_changed = True
-
- # target_tags might not be set in the project; cast it to an empty list
- fw.target_tags = fw.target_tags or []
-
- if fw.target_tags != target_tags:
- if isinstance(target_tags, list):
- if sorted(fw.target_tags) != sorted(target_tags):
- fw.target_tags = target_tags
- fw_changed = True
- else:
- fw.target_tags = target_tags
- fw_changed = True
-
- if fw_changed is True:
- try:
- gce.ex_update_firewall(fw)
- changed = True
- except Exception as e:
- module.fail_json(msg=unexpected_error_msg(e), changed=False)
-
- # Firewall rule not found so we try to create it.
- except ResourceNotFoundError:
- try:
- gce.ex_create_firewall(fwname, allowed_list, network=name,
- source_ranges=src_range, source_tags=src_tags, target_tags=target_tags)
- changed = True
-
- except Exception as e:
- module.fail_json(msg=unexpected_error_msg(e), changed=False)
-
- except Exception as e:
- module.fail_json(msg=unexpected_error_msg(e), changed=False)
-
- json_output['fwname'] = fwname
- json_output['allowed'] = allowed
- json_output['src_range'] = src_range
- json_output['src_tags'] = src_tags
- json_output['target_tags'] = target_tags
-
- if state in ['absent', 'deleted']:
- if fwname:
- json_output['fwname'] = fwname
- fw = None
- try:
- fw = gce.ex_get_firewall(fwname)
- except ResourceNotFoundError:
- pass
- except Exception as e:
- module.fail_json(msg=unexpected_error_msg(e), changed=False)
- if fw:
- gce.ex_destroy_firewall(fw)
- changed = True
- elif subnet_name:
- if not hasattr(gce, 'ex_get_subnetwork') or not hasattr(gce, 'ex_destroy_subnetwork'):
- module.fail_json(msg='Update libcloud to a more recent version (>1.0) that supports subnetwork creation', changed=changed)
- json_output['name'] = subnet_name
- subnet = None
- try:
- subnet = gce.ex_get_subnetwork(subnet_name, region=subnet_region)
- except ResourceNotFoundError:
- pass
- except Exception as e:
- module.fail_json(msg=unexpected_error_msg(e), changed=False)
- if subnet:
- gce.ex_destroy_subnetwork(subnet)
- changed = True
- elif name:
- json_output['name'] = name
- network = None
- try:
- network = gce.ex_get_network(name)
-
- except ResourceNotFoundError:
- pass
- except Exception as e:
- module.fail_json(msg=unexpected_error_msg(e), changed=False)
- if network:
- try:
- gce.ex_destroy_network(network)
- except Exception as e:
- module.fail_json(msg=unexpected_error_msg(e), changed=False)
- changed = True
-
- json_output['changed'] = changed
- module.exit_json(**json_output)
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/cloud/google/gce_pd.py b/lib/ansible/modules/cloud/google/gce_pd.py
deleted file mode 100644
index d26bf5c177..0000000000
--- a/lib/ansible/modules/cloud/google/gce_pd.py
+++ /dev/null
@@ -1,286 +0,0 @@
-#!/usr/bin/python
-# Copyright 2013 Google Inc.
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'community'}
-
-
-DOCUMENTATION = '''
----
-module: gce_pd
-version_added: "1.4"
-short_description: utilize GCE persistent disk resources
-description:
- - This module can create and destroy unformatted GCE persistent disks
- U(https://developers.google.com/compute/docs/disks#persistentdisks).
- It also supports attaching and detaching disks from running instances.
- Full install/configuration instructions for the gce* modules can
- be found in the comments of ansible/test/gce_tests.py.
-options:
- detach_only:
- description:
- - do not destroy the disk, merely detach it from an instance
- type: bool
- default: 'no'
- instance_name:
- description:
- - instance name if you wish to attach or detach the disk
- mode:
- description:
- - GCE mount mode of disk, READ_ONLY (default) or READ_WRITE
- default: "READ_ONLY"
- choices: ["READ_WRITE", "READ_ONLY"]
- name:
- description:
- - name of the disk
- required: true
- size_gb:
- description:
- - whole integer size of disk (in GB) to create, default is 10 GB
- default: 10
- image:
- description:
- - the source image to use for the disk
- version_added: "1.7"
- snapshot:
- description:
- - the source snapshot to use for the disk
- version_added: "1.7"
- state:
- description:
- - desired state of the persistent disk
- default: "present"
- choices: ["active", "present", "absent", "deleted"]
- zone:
- description:
- - zone in which to create the disk
- default: "us-central1-b"
- service_account_email:
- version_added: "1.6"
- description:
- - service account email
- pem_file:
- version_added: "1.6"
- description:
- - path to the pem file associated with the service account email
- This option is deprecated. Use 'credentials_file'.
- credentials_file:
- version_added: "2.1.0"
- description:
- - path to the JSON file associated with the service account email
- project_id:
- version_added: "1.6"
- description:
- - your GCE project ID
- disk_type:
- version_added: "1.9"
- description:
- - type of disk provisioned
- default: "pd-standard"
- choices: ["pd-standard", "pd-ssd"]
- delete_on_termination:
- version_added: "2.3"
- description:
- - If C(yes), deletes the volume when instance is terminated
- type: bool
- default: 'no'
-
-requirements:
- - "python >= 2.6"
- - "apache-libcloud >= 0.13.3, >= 0.17.0 if using JSON credentials"
-author: "Eric Johnson (@erjohnso) <erjohnso@google.com>"
-'''
-
-EXAMPLES = '''
-# Simple attachment action to an existing instance
-- local_action:
- module: gce_pd
- instance_name: notlocalhost
- size_gb: 5
- name: pd
-'''
-
-try:
- from libcloud.compute.types import Provider
- from libcloud.compute.providers import get_driver
- from libcloud.common.google import GoogleBaseError, QuotaExceededError, ResourceExistsError, ResourceNotFoundError, ResourceInUseError
- _ = Provider.GCE
- HAS_LIBCLOUD = True
-except ImportError:
- HAS_LIBCLOUD = False
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.gce import gce_connect, unexpected_error_msg
-
-
-def main():
- module = AnsibleModule(
- argument_spec=dict(
- delete_on_termination=dict(type='bool'),
- detach_only=dict(type='bool'),
- instance_name=dict(),
- mode=dict(default='READ_ONLY', choices=['READ_WRITE', 'READ_ONLY']),
- name=dict(required=True),
- size_gb=dict(default=10),
- disk_type=dict(default='pd-standard'),
- image=dict(),
- image_family=dict(),
- external_projects=dict(type='list'),
- snapshot=dict(),
- state=dict(default='present'),
- zone=dict(default='us-central1-b'),
- service_account_email=dict(),
- pem_file=dict(type='path'),
- credentials_file=dict(type='path'),
- project_id=dict(),
- )
- )
- if not HAS_LIBCLOUD:
- module.fail_json(msg='libcloud with GCE support (0.17.0+) is required for this module')
-
- gce = gce_connect(module)
-
- delete_on_termination = module.params.get('delete_on_termination')
- detach_only = module.params.get('detach_only')
- instance_name = module.params.get('instance_name')
- mode = module.params.get('mode')
- name = module.params.get('name')
- size_gb = module.params.get('size_gb')
- disk_type = module.params.get('disk_type')
- image = module.params.get('image')
- image_family = module.params.get('image_family')
- external_projects = module.params.get('external_projects')
- snapshot = module.params.get('snapshot')
- state = module.params.get('state')
- zone = module.params.get('zone')
-
- if delete_on_termination and not instance_name:
- module.fail_json(
- msg='Must specify an instance name when requesting delete on termination',
- changed=False)
-
- if detach_only and not instance_name:
- module.fail_json(
- msg='Must specify an instance name when detaching a disk',
- changed=False)
-
- disk = inst = None
- changed = is_attached = False
-
- json_output = {'name': name, 'zone': zone, 'state': state, 'disk_type': disk_type}
- if detach_only:
- json_output['detach_only'] = True
- json_output['detached_from_instance'] = instance_name
-
- if instance_name:
- # user wants to attach/detach from an existing instance
- try:
- inst = gce.ex_get_node(instance_name, zone)
- # is the disk attached?
- for d in inst.extra['disks']:
- if d['deviceName'] == name:
- is_attached = True
- json_output['attached_mode'] = d['mode']
- json_output['attached_to_instance'] = inst.name
- except Exception:
- pass
-
- # find disk if it already exists
- try:
- disk = gce.ex_get_volume(name)
- json_output['size_gb'] = int(disk.size)
- except ResourceNotFoundError:
- pass
- except Exception as e:
- module.fail_json(msg=unexpected_error_msg(e), changed=False)
-
- # user wants a disk to exist. If "instance_name" is supplied the user
- # also wants it attached
- if state in ['active', 'present']:
-
- if not size_gb:
- module.fail_json(msg="Must supply a size_gb", changed=False)
- try:
- size_gb = int(round(float(size_gb)))
- if size_gb < 1:
- raise Exception
- except Exception:
- module.fail_json(msg="Must supply a size_gb larger than 1 GB",
- changed=False)
-
- if instance_name and inst is None:
- module.fail_json(msg='Instance %s does not exist in zone %s' % (
- instance_name, zone), changed=False)
-
- if not disk:
- if image is not None and snapshot is not None:
- module.fail_json(
- msg='Cannot give both image (%s) and snapshot (%s)' % (
- image, snapshot), changed=False)
- lc_image = None
- lc_snapshot = None
- if image_family is not None:
- lc_image = gce.ex_get_image_from_family(image_family, ex_project_list=external_projects)
- elif image is not None:
- lc_image = gce.ex_get_image(image, ex_project_list=external_projects)
- elif snapshot is not None:
- lc_snapshot = gce.ex_get_snapshot(snapshot)
- try:
- disk = gce.create_volume(
- size_gb, name, location=zone, image=lc_image,
- snapshot=lc_snapshot, ex_disk_type=disk_type)
- except ResourceExistsError:
- pass
- except QuotaExceededError:
- module.fail_json(msg='Requested disk size exceeds quota',
- changed=False)
- except Exception as e:
- module.fail_json(msg=unexpected_error_msg(e), changed=False)
- json_output['size_gb'] = size_gb
- if image is not None:
- json_output['image'] = image
- if snapshot is not None:
- json_output['snapshot'] = snapshot
- changed = True
- if inst and not is_attached:
- try:
- gce.attach_volume(inst, disk, device=name, ex_mode=mode,
- ex_auto_delete=delete_on_termination)
- except Exception as e:
- module.fail_json(msg=unexpected_error_msg(e), changed=False)
- json_output['attached_to_instance'] = inst.name
- json_output['attached_mode'] = mode
- if delete_on_termination:
- json_output['delete_on_termination'] = True
- changed = True
-
- # user wants to delete a disk (or perhaps just detach it).
- if state in ['absent', 'deleted'] and disk:
-
- if inst and is_attached:
- try:
- gce.detach_volume(disk, ex_node=inst)
- except Exception as e:
- module.fail_json(msg=unexpected_error_msg(e), changed=False)
- changed = True
- if not detach_only:
- try:
- gce.destroy_volume(disk)
- except ResourceInUseError as e:
- module.fail_json(msg=str(e.value), changed=False)
- except Exception as e:
- module.fail_json(msg=unexpected_error_msg(e), changed=False)
- changed = True
-
- json_output['changed'] = changed
- module.exit_json(**json_output)
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/cloud/google/gce_snapshot.py b/lib/ansible/modules/cloud/google/gce_snapshot.py
deleted file mode 100644
index d6bb430e92..0000000000
--- a/lib/ansible/modules/cloud/google/gce_snapshot.py
+++ /dev/null
@@ -1,227 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: Ansible Project
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'community'}
-
-
-DOCUMENTATION = '''
----
-module: gce_snapshot
-version_added: "2.3"
-short_description: Create or destroy snapshots for GCE storage volumes
-description:
- - Manages snapshots for GCE instances. This module manages snapshots for
- the storage volumes of a GCE compute instance. If there are multiple
- volumes, each snapshot will be prepended with the disk name
-options:
- instance_name:
- description:
- - The GCE instance to snapshot
- required: True
- snapshot_name:
- description:
- - The name of the snapshot to manage
- disks:
- description:
- - A list of disks to create snapshots for. If none is provided,
- all of the volumes will be snapshotted
- default: all
- required: False
- state:
- description:
- - Whether a snapshot should be C(present) or C(absent)
- required: false
- default: present
- choices: [present, absent]
- service_account_email:
- description:
- - GCP service account email for the project where the instance resides
- required: true
- credentials_file:
- description:
- - The path to the credentials file associated with the service account
- required: true
- project_id:
- description:
- - The GCP project ID to use
- required: true
-requirements:
- - "python >= 2.6"
- - "apache-libcloud >= 0.19.0"
-author: Rob Wagner (@robwagner33)
-'''
-
-EXAMPLES = '''
-- name: Create gce snapshot
- gce_snapshot:
- instance_name: example-instance
- snapshot_name: example-snapshot
- state: present
- service_account_email: project_name@appspot.gserviceaccount.com
- credentials_file: /path/to/credentials
- project_id: project_name
- delegate_to: localhost
-
-- name: Delete gce snapshot
- gce_snapshot:
- instance_name: example-instance
- snapshot_name: example-snapshot
- state: absent
- service_account_email: project_name@appspot.gserviceaccount.com
- credentials_file: /path/to/credentials
- project_id: project_name
- delegate_to: localhost
-
-# This example creates snapshots for only two of the available disks as
-# disk0-example-snapshot and disk1-example-snapshot
-- name: Create snapshots of specific disks
- gce_snapshot:
- instance_name: example-instance
- snapshot_name: example-snapshot
- state: present
- disks:
- - disk0
- - disk1
- service_account_email: project_name@appspot.gserviceaccount.com
- credentials_file: /path/to/credentials
- project_id: project_name
- delegate_to: localhost
-'''
-
-RETURN = '''
-snapshots_created:
- description: List of newly created snapshots
- returned: When snapshots are created
- type: list
- sample: "[disk0-example-snapshot, disk1-example-snapshot]"
-
-snapshots_deleted:
- description: List of destroyed snapshots
- returned: When snapshots are deleted
- type: list
- sample: "[disk0-example-snapshot, disk1-example-snapshot]"
-
-snapshots_existing:
- description: List of snapshots that already existed (no-op)
- returned: When snapshots were already present
- type: list
- sample: "[disk0-example-snapshot, disk1-example-snapshot]"
-
-snapshots_absent:
- description: List of snapshots that were already absent (no-op)
- returned: When snapshots were already absent
- type: list
- sample: "[disk0-example-snapshot, disk1-example-snapshot]"
-'''
-
-try:
- from libcloud.compute.types import Provider
- _ = Provider.GCE
- HAS_LIBCLOUD = True
-except ImportError:
- HAS_LIBCLOUD = False
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.gce import gce_connect
-
-
-def find_snapshot(volume, name):
- '''
- Check if there is a snapshot already created with the given name for
- the passed in volume.
-
- Args:
- volume: A gce StorageVolume object to manage
- name: The name of the snapshot to look for
-
- Returns:
- The VolumeSnapshot object if one is found
- '''
- found_snapshot = None
- snapshots = volume.list_snapshots()
- for snapshot in snapshots:
- if name == snapshot.name:
- found_snapshot = snapshot
- return found_snapshot
-
-
-def main():
- module = AnsibleModule(
- argument_spec=dict(
- instance_name=dict(required=True),
- snapshot_name=dict(required=True),
- state=dict(choices=['present', 'absent'], default='present'),
- disks=dict(default=None, type='list'),
- service_account_email=dict(type='str'),
- credentials_file=dict(type='path'),
- project_id=dict(type='str')
- )
- )
-
- if not HAS_LIBCLOUD:
- module.fail_json(msg='libcloud with GCE support (0.19.0+) is required for this module')
-
- gce = gce_connect(module)
-
- instance_name = module.params.get('instance_name')
- snapshot_name = module.params.get('snapshot_name')
- disks = module.params.get('disks')
- state = module.params.get('state')
-
- json_output = dict(
- changed=False,
- snapshots_created=[],
- snapshots_deleted=[],
- snapshots_existing=[],
- snapshots_absent=[]
- )
-
- snapshot = None
-
- instance = gce.ex_get_node(instance_name, 'all')
- instance_disks = instance.extra['disks']
-
- for instance_disk in instance_disks:
- disk_snapshot_name = snapshot_name
- disk_info = gce._get_components_from_path(instance_disk['source'])
- device_name = disk_info['name']
- device_zone = disk_info['zone']
- if disks is None or device_name in disks:
- volume_obj = gce.ex_get_volume(device_name, device_zone)
-
- # If we have more than one disk to snapshot, prepend the disk name
- if len(instance_disks) > 1:
- disk_snapshot_name = device_name + "-" + disk_snapshot_name
-
- snapshot = find_snapshot(volume_obj, disk_snapshot_name)
-
- if snapshot and state == 'present':
- json_output['snapshots_existing'].append(disk_snapshot_name)
-
- elif snapshot and state == 'absent':
- snapshot.destroy()
- json_output['changed'] = True
- json_output['snapshots_deleted'].append(disk_snapshot_name)
-
- elif not snapshot and state == 'present':
- volume_obj.snapshot(disk_snapshot_name)
- json_output['changed'] = True
- json_output['snapshots_created'].append(disk_snapshot_name)
-
- elif not snapshot and state == 'absent':
- json_output['snapshots_absent'].append(disk_snapshot_name)
-
- module.exit_json(**json_output)
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/cloud/google/gce_tag.py b/lib/ansible/modules/cloud/google/gce_tag.py
deleted file mode 100644
index e3adebe56e..0000000000
--- a/lib/ansible/modules/cloud/google/gce_tag.py
+++ /dev/null
@@ -1,216 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-
-# Copyright: (c) 2017, Ansible Project
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'community'}
-
-DOCUMENTATION = '''
----
-module: gce_tag
-version_added: "2.0"
-short_description: add or remove tag(s) to/from GCE instances
-description:
- - This module can add or remove tags U(https://cloud.google.com/compute/docs/label-or-tag-resources#tags)
- to/from GCE instances. Use 'instance_pattern' to update multiple instances in a specify zone.
-options:
- instance_name:
- description:
- - The name of the GCE instance to add/remove tags.
- - Required if C(instance_pattern) is not specified.
- instance_pattern:
- description:
- - The pattern of GCE instance names to match for adding/removing tags. Full-Python regex is supported.
- See U(https://docs.python.org/2/library/re.html) for details.
- - If C(instance_name) is not specified, this field is required.
- version_added: "2.3"
- tags:
- description:
- - Comma-separated list of tags to add or remove.
- required: yes
- state:
- description:
- - Desired state of the tags.
- choices: [ absent, present ]
- default: present
- zone:
- description:
- - The zone of the disk specified by source.
- default: us-central1-a
- service_account_email:
- description:
- - Service account email.
- pem_file:
- description:
- - Path to the PEM file associated with the service account email.
- project_id:
- description:
- - Your GCE project ID.
-requirements:
- - python >= 2.6
- - apache-libcloud >= 0.17.0
-notes:
- - Either I(instance_name) or I(instance_pattern) is required.
-author:
- - Do Hoang Khiem (@dohoangkhiem) <(dohoangkhiem@gmail.com>
- - Tom Melendez (@supertom)
-'''
-
-EXAMPLES = '''
-- name: Add tags to instance
- gce_tag:
- instance_name: staging-server
- tags: http-server,https-server,staging
- zone: us-central1-a
- state: present
-
-- name: Remove tags from instance in default zone (us-central1-a)
- gce_tag:
- instance_name: test-server
- tags: foo,bar
- state: absent
-
-- name: Add tags to instances in zone that match pattern
- gce_tag:
- instance_pattern: test-server-*
- tags: foo,bar
- zone: us-central1-a
- state: present
-'''
-
-import re
-import traceback
-
-try:
- from libcloud.compute.types import Provider
- from libcloud.compute.providers import get_driver
- from libcloud.common.google import GoogleBaseError, QuotaExceededError, \
- ResourceExistsError, ResourceNotFoundError, InvalidRequestError
-
- _ = Provider.GCE
- HAS_LIBCLOUD = True
-except ImportError:
- HAS_LIBCLOUD = False
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.gce import gce_connect
-
-
-def _union_items(baselist, comparelist):
- """Combine two lists, removing duplicates."""
- return list(set(baselist) | set(comparelist))
-
-
-def _intersect_items(baselist, comparelist):
- """Return matching items in both lists."""
- return list(set(baselist) & set(comparelist))
-
-
-def _get_changed_items(baselist, comparelist):
- """Return changed items as they relate to baselist."""
- return list(set(baselist) & set(set(baselist) ^ set(comparelist)))
-
-
-def modify_tags(gce, module, node, tags, state='present'):
- """Modify tags on an instance."""
-
- existing_tags = node.extra['tags']
- tags = [x.lower() for x in tags]
- tags_changed = []
-
- if state == 'absent':
- # tags changed are any that intersect
- tags_changed = _intersect_items(existing_tags, tags)
- if not tags_changed:
- return False, None
- # update instance with tags in existing tags that weren't specified
- node_tags = _get_changed_items(existing_tags, tags)
- else:
- # tags changed are any that in the new list that weren't in existing
- tags_changed = _get_changed_items(tags, existing_tags)
- if not tags_changed:
- return False, None
- # update instance with the combined list
- node_tags = _union_items(existing_tags, tags)
-
- try:
- gce.ex_set_node_tags(node, node_tags)
- return True, tags_changed
- except (GoogleBaseError, InvalidRequestError) as e:
- module.fail_json(msg=str(e), changed=False)
-
-
-def main():
- module = AnsibleModule(
- argument_spec=dict(
- instance_name=dict(type='str'),
- instance_pattern=dict(type='str'),
- tags=dict(type='list', required=True),
- state=dict(type='str', default='present', choices=['absent', 'present']),
- zone=dict(type='str', default='us-central1-a'),
- service_account_email=dict(type='str'),
- pem_file=dict(type='path'),
- project_id=dict(type='str'),
- ),
- mutually_exclusive=[
- ['instance_name', 'instance_pattern']
- ],
- required_one_of=[
- ['instance_name', 'instance_pattern']
- ],
- )
-
- instance_name = module.params.get('instance_name')
- instance_pattern = module.params.get('instance_pattern')
- state = module.params.get('state')
- tags = module.params.get('tags')
- zone = module.params.get('zone')
- changed = False
-
- if not HAS_LIBCLOUD:
- module.fail_json(msg='libcloud with GCE support (0.17.0+) required for this module')
-
- gce = gce_connect(module)
-
- # Create list of nodes to operate on
- matching_nodes = []
- try:
- if instance_pattern:
- instances = gce.list_nodes(ex_zone=zone)
- # no instances in zone
- if not instances:
- module.exit_json(changed=False, tags=tags, zone=zone, instances_updated=[])
- try:
- # Python regex fully supported: https://docs.python.org/2/library/re.html
- p = re.compile(instance_pattern)
- matching_nodes = [i for i in instances if p.search(i.name) is not None]
- except re.error as e:
- module.fail_json(msg='Regex error for pattern %s: %s' % (instance_pattern, e), changed=False)
- else:
- matching_nodes = [gce.ex_get_node(instance_name, zone=zone)]
- except ResourceNotFoundError:
- module.fail_json(msg='Instance %s not found in zone %s' % (instance_name, zone), changed=False)
- except GoogleBaseError as e:
- module.fail_json(msg=str(e), changed=False, exception=traceback.format_exc())
-
- # Tag nodes
- instance_pattern_matches = []
- tags_changed = []
- for node in matching_nodes:
- changed, tags_changed = modify_tags(gce, module, node, tags, state)
- if changed:
- instance_pattern_matches.append({'instance_name': node.name, 'tags_changed': tags_changed})
- if instance_pattern:
- module.exit_json(changed=changed, instance_pattern=instance_pattern, tags=tags_changed, zone=zone, instances_updated=instance_pattern_matches)
- else:
- module.exit_json(changed=changed, instance_name=instance_name, tags=tags_changed, zone=zone)
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/cloud/google/gcpubsub.py b/lib/ansible/modules/cloud/google/gcpubsub.py
deleted file mode 100644
index 4d0add65e3..0000000000
--- a/lib/ansible/modules/cloud/google/gcpubsub.py
+++ /dev/null
@@ -1,333 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-
-# Copyright: (c) 2016, Google Inc.
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'community'}
-
-DOCUMENTATION = '''
----
-module: gcpubsub
-version_added: "2.3"
-short_description: Create and Delete Topics/Subscriptions, Publish and pull messages on PubSub
-description:
- - Create and Delete Topics/Subscriptions, Publish and pull messages on PubSub.
- See U(https://cloud.google.com/pubsub/docs) for an overview.
-requirements:
- - google-auth >= 0.5.0
- - google-cloud-pubsub >= 0.22.0
-notes:
- - Subscription pull happens before publish. You cannot publish and pull in the same task.
-author:
- - Tom Melendez (@supertom) <tom@supertom.com>
-options:
- topic:
- description:
- - GCP pubsub topic name.
- - Only the name, not the full path, is required.
- required: yes
- subscription:
- description:
- - Dictionary containing a subscription name associated with a topic (required), along with optional ack_deadline, push_endpoint and pull.
- For pulling from a subscription, message_ack (bool), max_messages (int) and return_immediate are available as subfields.
- See subfields name, push_endpoint and ack_deadline for more information.
- name:
- description: Subfield of subscription. Required if subscription is specified. See examples.
- ack_deadline:
- description: Subfield of subscription. Not required. Default deadline for subscriptions to ACK the message before it is resent. See examples.
- pull:
- description:
- - Subfield of subscription. Not required. If specified, messages will be retrieved from topic via the provided subscription name.
- max_messages (int; default None; max number of messages to pull), message_ack (bool; default False; acknowledge the message) and return_immediately
- (bool; default True, don't wait for messages to appear). If the messages are acknowledged, changed is set to True, otherwise, changed is False.
- push_endpoint:
- description:
- - Subfield of subscription. Not required. If specified, message will be sent to an endpoint.
- See U(https://cloud.google.com/pubsub/docs/advanced#push_endpoints) for more information.
- publish:
- description:
- - List of dictionaries describing messages and attributes to be published. Dictionary is in message(str):attributes(dict) format.
- Only message is required.
- state:
- description:
- - State of the topic or queue.
- - Applies to the most granular resource.
- - If subscription isspecified we remove it.
- - If only topic is specified, that is what is removed.
- - NOTE - A topic can be removed without first removing the subscription.
- choices: [ absent, present ]
- default: present
-'''
-
-EXAMPLES = '''
-# (Message will be pushed; there is no check to see if the message was pushed before
-- name: Create a topic and publish a message to it
- gcpubsub:
- topic: ansible-topic-example
- state: present
-
-# Subscriptions associated with topic are not deleted.
-- name: Delete Topic
- gcpubsub:
- topic: ansible-topic-example
- state: absent
-
-# Setting absent will keep the messages from being sent
-- name: Publish multiple messages, with attributes (key:value available with the message)
- gcpubsub:
- topic: '{{ topic_name }}'
- state: present
- publish:
- - message: this is message 1
- attributes:
- mykey1: myvalue
- mykey2: myvalu2
- mykey3: myvalue3
- - message: this is message 2
- attributes:
- server: prod
- sla: "99.9999"
- owner: fred
-
-- name: Create Subscription (pull)
- gcpubsub:
- topic: ansible-topic-example
- subscription:
- - name: mysub
- state: present
-
-# pull is default, ack_deadline is not required
-- name: Create Subscription with ack_deadline and push endpoint
- gcpubsub:
- topic: ansible-topic-example
- subscription:
- - name: mysub
- ack_deadline: "60"
- push_endpoint: http://pushendpoint.example.com
- state: present
-
-# Setting push_endpoint to "None" converts subscription to pull.
-- name: Subscription change from push to pull
- gcpubsub:
- topic: ansible-topic-example
- subscription:
- name: mysub
- push_endpoint: "None"
-
-### Topic will not be deleted
-- name: Delete subscription
- gcpubsub:
- topic: ansible-topic-example
- subscription:
- - name: mysub
- state: absent
-
-# only pull keyword is required.
-- name: Pull messages from subscription
- gcpubsub:
- topic: ansible-topic-example
- subscription:
- name: ansible-topic-example-sub
- pull:
- message_ack: yes
- max_messages: "100"
-'''
-
-RETURN = '''
-publish:
- description: List of dictionaries describing messages and attributes to be published. Dictionary is in message(str):attributes(dict) format.
- Only message is required.
- returned: Only when specified
- type: list
- sample: "publish: ['message': 'my message', attributes: {'key1': 'value1'}]"
-
-pulled_messages:
- description: list of dictionaries containing message info. Fields are ack_id, attributes, data, message_id.
- returned: Only when subscription.pull is specified
- type: list
- sample: [{ "ack_id": "XkASTCcYREl...","attributes": {"key1": "val1",...}, "data": "this is message 1", "message_id": "49107464153705"},..]
-
-state:
- description: The state of the topic or subscription. Value will be either 'absent' or 'present'.
- returned: Always
- type: str
- sample: "present"
-
-subscription:
- description: Name of subscription.
- returned: When subscription fields are specified
- type: str
- sample: "mysubscription"
-
-topic:
- description: Name of topic.
- returned: Always
- type: str
- sample: "mytopic"
-'''
-
-try:
- from ast import literal_eval
- HAS_PYTHON26 = True
-except ImportError:
- HAS_PYTHON26 = False
-
-try:
- from google.cloud import pubsub
- HAS_GOOGLE_CLOUD_PUBSUB = True
-except ImportError as e:
- HAS_GOOGLE_CLOUD_PUBSUB = False
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.gcp import check_min_pkg_version, get_google_cloud_credentials
-
-
-CLOUD_CLIENT = 'google-cloud-pubsub'
-CLOUD_CLIENT_MINIMUM_VERSION = '0.22.0'
-CLOUD_CLIENT_USER_AGENT = 'ansible-pubsub-0.1'
-
-
-def publish_messages(message_list, topic):
- with topic.batch() as batch:
- for message in message_list:
- msg = message['message']
- attrs = {}
- if 'attributes' in message:
- attrs = message['attributes']
- batch.publish(bytes(msg), **attrs)
- return True
-
-
-def pull_messages(pull_params, sub):
- """
- :rtype: tuple (output, changed)
- """
- changed = False
- max_messages = pull_params.get('max_messages', None)
- message_ack = pull_params.get('message_ack', 'no')
- return_immediately = pull_params.get('return_immediately', False)
-
- output = []
- pulled = sub.pull(return_immediately=return_immediately, max_messages=max_messages)
-
- for ack_id, msg in pulled:
- msg_dict = {'message_id': msg.message_id,
- 'attributes': msg.attributes,
- 'data': msg.data,
- 'ack_id': ack_id}
- output.append(msg_dict)
-
- if message_ack:
- ack_ids = [m['ack_id'] for m in output]
- if ack_ids:
- sub.acknowledge(ack_ids)
- changed = True
- return (output, changed)
-
-
-def main():
-
- module = AnsibleModule(
- argument_spec=dict(
- topic=dict(type='str', required=True),
- state=dict(type='str', default='present', choices=['absent', 'present']),
- publish=dict(type='list'),
- subscription=dict(type='dict'),
- service_account_email=dict(type='str'),
- credentials_file=dict(type='str'),
- project_id=dict(type='str'),
- ),
- )
-
- if not HAS_PYTHON26:
- module.fail_json(
- msg="GCE module requires python's 'ast' module, python v2.6+")
-
- if not HAS_GOOGLE_CLOUD_PUBSUB:
- module.fail_json(msg="Please install google-cloud-pubsub library.")
-
- if not check_min_pkg_version(CLOUD_CLIENT, CLOUD_CLIENT_MINIMUM_VERSION):
- module.fail_json(msg="Please install %s client version %s" % (CLOUD_CLIENT, CLOUD_CLIENT_MINIMUM_VERSION))
-
- mod_params = {}
- mod_params['publish'] = module.params.get('publish')
- mod_params['state'] = module.params.get('state')
- mod_params['topic'] = module.params.get('topic')
- mod_params['subscription'] = module.params.get('subscription')
-
- creds, params = get_google_cloud_credentials(module)
- pubsub_client = pubsub.Client(project=params['project_id'], credentials=creds, use_gax=False)
- pubsub_client.user_agent = CLOUD_CLIENT_USER_AGENT
-
- changed = False
- json_output = {}
-
- t = None
- if mod_params['topic']:
- t = pubsub_client.topic(mod_params['topic'])
- s = None
- if mod_params['subscription']:
- # Note: default ack deadline cannot be changed without deleting/recreating subscription
- s = t.subscription(mod_params['subscription']['name'],
- ack_deadline=mod_params['subscription'].get('ack_deadline', None),
- push_endpoint=mod_params['subscription'].get('push_endpoint', None))
-
- if mod_params['state'] == 'absent':
- # Remove the most granular resource. If subscription is specified
- # we remove it. If only topic is specified, that is what is removed.
- # Note that a topic can be removed without first removing the subscription.
- # TODO(supertom): Enhancement: Provide an option to only delete a topic
- # if there are no subscriptions associated with it (which the API does not support).
- if s is not None:
- if s.exists():
- s.delete()
- changed = True
- else:
- if t.exists():
- t.delete()
- changed = True
- elif mod_params['state'] == 'present':
- if not t.exists():
- t.create()
- changed = True
- if s:
- if not s.exists():
- s.create()
- s.reload()
- changed = True
- else:
- # Subscription operations
- # TODO(supertom): if more 'update' operations arise, turn this into a function.
- s.reload()
- push_endpoint = mod_params['subscription'].get('push_endpoint', None)
- if push_endpoint is not None:
- if push_endpoint != s.push_endpoint:
- if push_endpoint == 'None':
- push_endpoint = None
- s.modify_push_configuration(push_endpoint=push_endpoint)
- s.reload()
- changed = push_endpoint == s.push_endpoint
-
- if 'pull' in mod_params['subscription']:
- if s.push_endpoint is not None:
- module.fail_json(msg="Cannot pull messages, push_endpoint is configured.")
- (json_output['pulled_messages'], changed) = pull_messages(
- mod_params['subscription']['pull'], s)
-
- # publish messages to the topic
- if mod_params['publish'] and len(mod_params['publish']) > 0:
- changed = publish_messages(mod_params['publish'], t)
-
- json_output['changed'] = changed
- json_output.update(mod_params)
- module.exit_json(**json_output)
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/cloud/google/gcpubsub_info.py b/lib/ansible/modules/cloud/google/gcpubsub_info.py
deleted file mode 100644
index 11b1f75b62..0000000000
--- a/lib/ansible/modules/cloud/google/gcpubsub_info.py
+++ /dev/null
@@ -1,151 +0,0 @@
-#!/usr/bin/python
-# Copyright 2016 Google Inc.
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'community'}
-
-
-DOCUMENTATION = '''
----
-module: gcpubsub_info
-version_added: "2.3"
-short_description: List Topics/Subscriptions and Messages from Google PubSub.
-description:
- - List Topics/Subscriptions from Google PubSub. Use the gcpubsub module for
- topic/subscription management.
- See U(https://cloud.google.com/pubsub/docs) for an overview.
- - This module was called C(gcpubsub_facts) before Ansible 2.9. The usage did not change.
-requirements:
- - "python >= 2.6"
- - "google-auth >= 0.5.0"
- - "google-cloud-pubsub >= 0.22.0"
-notes:
- - list state enables user to list topics or subscriptions in the project. See examples for details.
-author:
- - "Tom Melendez (@supertom) <tom@supertom.com>"
-options:
- topic:
- description:
- - GCP pubsub topic name. Only the name, not the full path, is required.
- required: False
- view:
- description:
- - Choices are 'topics' or 'subscriptions'
- required: True
- state:
- description:
- - list is the only valid option.
- required: False
-'''
-
-EXAMPLES = '''
-## List all Topics in a project
-- gcpubsub_info:
- view: topics
- state: list
-
-## List all Subscriptions in a project
-- gcpubsub_info:
- view: subscriptions
- state: list
-
-## List all Subscriptions for a Topic in a project
-- gcpubsub_info:
- view: subscriptions
- topic: my-topic
- state: list
-'''
-
-RETURN = '''
-subscriptions:
- description: List of subscriptions.
- returned: When view is set to subscriptions.
- type: list
- sample: ["mysubscription", "mysubscription2"]
-topic:
- description: Name of topic. Used to filter subscriptions.
- returned: Always
- type: str
- sample: "mytopic"
-topics:
- description: List of topics.
- returned: When view is set to topics.
- type: list
- sample: ["mytopic", "mytopic2"]
-'''
-
-try:
- from ast import literal_eval
- HAS_PYTHON26 = True
-except ImportError:
- HAS_PYTHON26 = False
-
-try:
- from google.cloud import pubsub
- HAS_GOOGLE_CLOUD_PUBSUB = True
-except ImportError as e:
- HAS_GOOGLE_CLOUD_PUBSUB = False
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.gcp import check_min_pkg_version, get_google_cloud_credentials
-
-
-def list_func(data, member='name'):
- """Used for state=list."""
- return [getattr(x, member) for x in data]
-
-
-def main():
- module = AnsibleModule(argument_spec=dict(
- view=dict(choices=['topics', 'subscriptions'], default='topics'),
- topic=dict(required=False),
- state=dict(choices=['list'], default='list'),
- service_account_email=dict(),
- credentials_file=dict(),
- project_id=dict(), ),)
- if module._name == 'gcpubsub_facts':
- module.deprecate("The 'gcpubsub_facts' module has been renamed to 'gcpubsub_info'", version='2.13')
-
- if not HAS_PYTHON26:
- module.fail_json(
- msg="GCE module requires python's 'ast' module, python v2.6+")
-
- if not HAS_GOOGLE_CLOUD_PUBSUB:
- module.fail_json(msg="Please install google-cloud-pubsub library.")
-
- CLIENT_MINIMUM_VERSION = '0.22.0'
- if not check_min_pkg_version('google-cloud-pubsub', CLIENT_MINIMUM_VERSION):
- module.fail_json(msg="Please install google-cloud-pubsub library version %s" % CLIENT_MINIMUM_VERSION)
-
- mod_params = {}
- mod_params['state'] = module.params.get('state')
- mod_params['topic'] = module.params.get('topic')
- mod_params['view'] = module.params.get('view')
-
- creds, params = get_google_cloud_credentials(module)
- pubsub_client = pubsub.Client(project=params['project_id'], credentials=creds, use_gax=False)
- pubsub_client.user_agent = 'ansible-pubsub-0.1'
-
- json_output = {}
- if mod_params['view'] == 'topics':
- json_output['topics'] = list_func(pubsub_client.list_topics())
- elif mod_params['view'] == 'subscriptions':
- if mod_params['topic']:
- t = pubsub_client.topic(mod_params['topic'])
- json_output['subscriptions'] = list_func(t.list_subscriptions())
- else:
- json_output['subscriptions'] = list_func(pubsub_client.list_subscriptions())
-
- json_output['changed'] = False
- json_output.update(mod_params)
- module.exit_json(**json_output)
-
-
-if __name__ == '__main__':
- main()