mirror of
https://github.com/ansible-collections/community.general.git
synced 2024-09-14 20:13:21 +02:00
Restore removed google modules (#675)
* Revert "Remove entries of modules that no longer exist." partially. This reverts commitc1e1b37da4
. * Revert "The _info module is in google.cloud." This reverts commit26f5c84924
. * Revert "Remove modules that were moved to the google.cloud collection according to ansible/ansible's ansible_builtin_runtime.yml." This reverts commita1442ccc35
. * Fix FQCNs in examples and module references. * Add changelog fragment. * Update ignore.txt. * Remove bad lines.
This commit is contained in:
parent
52cce0b7af
commit
7ac467a359
18 changed files with 1804 additions and 169 deletions
3
changelogs/fragments/google-modules.yml
Normal file
3
changelogs/fragments/google-modules.yml
Normal file
|
@ -0,0 +1,3 @@
|
|||
minor_changes:
|
||||
- Add the deprecated ``gcp_backend_service``, ``gcp_forwarding_rule`` and ``gcp_healthcheck`` modules, which will be removed in 2.0.0. These were originally in community.general, but removed on the assumption that they have been moved to google.cloud. Since this turned out to be incorrect, we re-added them for 1.0.0.
|
||||
- Add the ``gcpubsub``, ``gcpubsub_info`` and ``gcpubsub_facts`` (to be removed in 3.0.0) modules. These were originally in community.general, but removed on the assumption that they have been moved to google.cloud. Since this turned out to be incorrect, we re-added them for 1.0.0.
|
|
@ -258,6 +258,18 @@ plugin_routing:
|
|||
deprecation:
|
||||
removal_version: 2.0.0
|
||||
warning_text: see plugin documentation for details
|
||||
gcp_backend_service:
|
||||
deprecation:
|
||||
removal_version: 2.0.0
|
||||
warning_text: see plugin documentation for details
|
||||
gcp_forwarding_rule:
|
||||
deprecation:
|
||||
removal_version: 2.0.0
|
||||
warning_text: see plugin documentation for details
|
||||
gcp_healthcheck:
|
||||
deprecation:
|
||||
removal_version: 2.0.0
|
||||
warning_text: see plugin documentation for details
|
||||
gcp_target_proxy:
|
||||
deprecation:
|
||||
removal_version: 2.0.0
|
||||
|
|
400
plugins/modules/cloud/google/gcp_backend_service.py
Normal file
400
plugins/modules/cloud/google/gcp_backend_service.py
Normal file
|
@ -0,0 +1,400 @@
|
|||
#!/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
|
||||
|
||||
|
||||
DOCUMENTATION = '''
|
||||
module: gcp_backend_service
|
||||
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.0.0 # was Ansible 2.12
|
||||
why: Updated modules released with increased functionality
|
||||
alternative: Use M(google.cloud.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
|
||||
community.general.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
|
||||
community.general.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_collections.community.general.plugins.module_utils.gce import gce_connect
|
||||
from ansible_collections.community.general.plugins.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()
|
349
plugins/modules/cloud/google/gcp_forwarding_rule.py
Normal file
349
plugins/modules/cloud/google/gcp_forwarding_rule.py
Normal file
|
@ -0,0 +1,349 @@
|
|||
#!/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
|
||||
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: gcp_forwarding_rule
|
||||
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.0.0 # was Ansible 2.12
|
||||
why: Updated modules released with increased functionality
|
||||
alternative: Use M(google.cloud.gcp_compute_forwarding_rule) or M(google.cloud.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
|
||||
community.general.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
|
||||
community.general.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_collections.community.general.plugins.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()
|
444
plugins/modules/cloud/google/gcp_healthcheck.py
Normal file
444
plugins/modules/cloud/google/gcp_healthcheck.py
Normal file
|
@ -0,0 +1,444 @@
|
|||
#!/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
|
||||
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: gcp_healthcheck
|
||||
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.0.0 # was Ansible 2.12
|
||||
why: Updated modules released with increased functionality
|
||||
alternative: >
|
||||
Use M(google.cloud.gcp_compute_health_check), M(google.cloud.gcp_compute_http_health_check) or
|
||||
M(google.cloud.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:
|
||||
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
|
||||
community.general.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
|
||||
community.general.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
|
||||
community.general.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_collections.community.general.plugins.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()
|
328
plugins/modules/cloud/google/gcpubsub.py
Normal file
328
plugins/modules/cloud/google/gcpubsub.py
Normal file
|
@ -0,0 +1,328 @@
|
|||
#!/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
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: gcpubsub
|
||||
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
|
||||
community.general.gcpubsub:
|
||||
topic: ansible-topic-example
|
||||
state: present
|
||||
|
||||
# Subscriptions associated with topic are not deleted.
|
||||
- name: Delete Topic
|
||||
community.general.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)
|
||||
community.general.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)
|
||||
community.general.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
|
||||
community.general.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
|
||||
community.general.gcpubsub:
|
||||
topic: ansible-topic-example
|
||||
subscription:
|
||||
name: mysub
|
||||
push_endpoint: "None"
|
||||
|
||||
### Topic will not be deleted
|
||||
- name: Delete subscription
|
||||
community.general.gcpubsub:
|
||||
topic: ansible-topic-example
|
||||
subscription:
|
||||
- name: mysub
|
||||
state: absent
|
||||
|
||||
# only pull keyword is required.
|
||||
- name: Pull messages from subscription
|
||||
community.general.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_collections.community.general.plugins.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()
|
|
@ -1,150 +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
|
||||
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: gcpubsub_facts
|
||||
deprecated:
|
||||
removed_in: 3.0.0 # was Ansible 2.13
|
||||
why: The module does not return Ansible facts
|
||||
alternative: Use C(gcpubsub_info) from the C(google.cloud) collection instead
|
||||
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 = '''
|
||||
- name: List all Topics in a project
|
||||
gcpubsub_info:
|
||||
view: topics
|
||||
state: list
|
||||
|
||||
- name: List all Subscriptions in a project
|
||||
gcpubsub_info:
|
||||
view: subscriptions
|
||||
state: list
|
||||
|
||||
- name: 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_collections.community.general.plugins.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 in ('gcpubsub_facts', 'community.general.gcpubsub_facts'):
|
||||
module.deprecate("The 'gcpubsub_facts' module has been renamed to 'gcpubsub_info'",
|
||||
version='3.0.0', collection_name='community.general') # was Ansible 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()
|
1
plugins/modules/cloud/google/gcpubsub_facts.py
Symbolic link
1
plugins/modules/cloud/google/gcpubsub_facts.py
Symbolic link
|
@ -0,0 +1 @@
|
|||
gcpubsub_info.py
|
146
plugins/modules/cloud/google/gcpubsub_info.py
Normal file
146
plugins/modules/cloud/google/gcpubsub_info.py
Normal file
|
@ -0,0 +1,146 @@
|
|||
#!/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
|
||||
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: gcpubsub_info
|
||||
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 = '''
|
||||
- name: List all Topics in a project
|
||||
community.general.gcpubsub_info:
|
||||
view: topics
|
||||
state: list
|
||||
|
||||
- name: List all Subscriptions in a project
|
||||
community.general.gcpubsub_info:
|
||||
view: subscriptions
|
||||
state: list
|
||||
|
||||
- name: List all Subscriptions for a Topic in a project
|
||||
community.general.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_collections.community.general.plugins.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 in ('gcpubsub_facts', 'community.general.gcpubsub_facts'):
|
||||
module.deprecate("The 'gcpubsub_facts' module has been renamed to 'gcpubsub_info'",
|
||||
version='3.0.0', collection_name='community.general') # was Ansible 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()
|
1
plugins/modules/gcp_backend_service.py
Symbolic link
1
plugins/modules/gcp_backend_service.py
Symbolic link
|
@ -0,0 +1 @@
|
|||
./cloud/google/gcp_backend_service.py
|
1
plugins/modules/gcp_forwarding_rule.py
Symbolic link
1
plugins/modules/gcp_forwarding_rule.py
Symbolic link
|
@ -0,0 +1 @@
|
|||
./cloud/google/gcp_forwarding_rule.py
|
1
plugins/modules/gcp_healthcheck.py
Symbolic link
1
plugins/modules/gcp_healthcheck.py
Symbolic link
|
@ -0,0 +1 @@
|
|||
./cloud/google/gcp_healthcheck.py
|
1
plugins/modules/gcpubsub.py
Symbolic link
1
plugins/modules/gcpubsub.py
Symbolic link
|
@ -0,0 +1 @@
|
|||
./cloud/google/gcpubsub.py
|
|
@ -1 +0,0 @@
|
|||
cloud/google/gcpubsub_facts.py
|
1
plugins/modules/gcpubsub_info.py
Symbolic link
1
plugins/modules/gcpubsub_info.py
Symbolic link
|
@ -0,0 +1 @@
|
|||
./cloud/google/gcpubsub_info.py
|
|
@ -123,6 +123,27 @@ plugins/modules/cloud/google/gce_snapshot.py validate-modules:parameter-type-not
|
|||
plugins/modules/cloud/google/gce_tag.py pylint:blacklisted-name
|
||||
plugins/modules/cloud/google/gce_tag.py validate-modules:parameter-list-no-elements
|
||||
plugins/modules/cloud/google/gce_tag.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/cloud/google/gcp_backend_service.py pylint:blacklisted-name
|
||||
plugins/modules/cloud/google/gcp_backend_service.py validate-modules:doc-choices-do-not-match-spec
|
||||
plugins/modules/cloud/google/gcp_backend_service.py validate-modules:doc-default-does-not-match-spec
|
||||
plugins/modules/cloud/google/gcp_backend_service.py validate-modules:doc-missing-type
|
||||
plugins/modules/cloud/google/gcp_backend_service.py validate-modules:parameter-list-no-elements
|
||||
plugins/modules/cloud/google/gcp_backend_service.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/cloud/google/gcp_backend_service.py validate-modules:undocumented-parameter
|
||||
plugins/modules/cloud/google/gcp_forwarding_rule.py validate-modules:doc-choices-do-not-match-spec
|
||||
plugins/modules/cloud/google/gcp_forwarding_rule.py validate-modules:doc-default-does-not-match-spec
|
||||
plugins/modules/cloud/google/gcp_forwarding_rule.py validate-modules:doc-missing-type
|
||||
plugins/modules/cloud/google/gcp_forwarding_rule.py validate-modules:doc-required-mismatch
|
||||
plugins/modules/cloud/google/gcp_forwarding_rule.py validate-modules:parameter-list-no-elements
|
||||
plugins/modules/cloud/google/gcp_forwarding_rule.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/cloud/google/gcp_forwarding_rule.py validate-modules:undocumented-parameter
|
||||
plugins/modules/cloud/google/gcp_healthcheck.py pylint:blacklisted-name
|
||||
plugins/modules/cloud/google/gcp_healthcheck.py validate-modules:doc-choices-do-not-match-spec
|
||||
plugins/modules/cloud/google/gcp_healthcheck.py validate-modules:doc-default-does-not-match-spec
|
||||
plugins/modules/cloud/google/gcp_healthcheck.py validate-modules:doc-missing-type
|
||||
plugins/modules/cloud/google/gcp_healthcheck.py validate-modules:doc-required-mismatch
|
||||
plugins/modules/cloud/google/gcp_healthcheck.py validate-modules:parameter-list-no-elements
|
||||
plugins/modules/cloud/google/gcp_healthcheck.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/cloud/google/gcp_target_proxy.py validate-modules:doc-choices-do-not-match-spec
|
||||
plugins/modules/cloud/google/gcp_target_proxy.py validate-modules:doc-missing-type
|
||||
plugins/modules/cloud/google/gcp_target_proxy.py validate-modules:doc-required-mismatch
|
||||
|
@ -135,12 +156,16 @@ plugins/modules/cloud/google/gcp_url_map.py validate-modules:doc-missing-type
|
|||
plugins/modules/cloud/google/gcp_url_map.py validate-modules:parameter-list-no-elements
|
||||
plugins/modules/cloud/google/gcp_url_map.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/cloud/google/gcp_url_map.py validate-modules:undocumented-parameter
|
||||
plugins/modules/cloud/google/gcpubsub_facts.py validate-modules:doc-choices-do-not-match-spec
|
||||
plugins/modules/cloud/google/gcpubsub_facts.py validate-modules:doc-default-does-not-match-spec
|
||||
plugins/modules/cloud/google/gcpubsub_facts.py validate-modules:doc-missing-type
|
||||
plugins/modules/cloud/google/gcpubsub_facts.py validate-modules:doc-required-mismatch
|
||||
plugins/modules/cloud/google/gcpubsub_facts.py validate-modules:parameter-state-invalid-choice
|
||||
plugins/modules/cloud/google/gcpubsub_facts.py validate-modules:undocumented-parameter
|
||||
plugins/modules/cloud/google/gcpubsub.py validate-modules:nonexistent-parameter-documented
|
||||
plugins/modules/cloud/google/gcpubsub.py validate-modules:parameter-list-no-elements
|
||||
plugins/modules/cloud/google/gcpubsub.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/cloud/google/gcpubsub.py validate-modules:undocumented-parameter
|
||||
plugins/modules/cloud/google/gcpubsub_info.py validate-modules:doc-choices-do-not-match-spec
|
||||
plugins/modules/cloud/google/gcpubsub_info.py validate-modules:doc-default-does-not-match-spec
|
||||
plugins/modules/cloud/google/gcpubsub_info.py validate-modules:doc-missing-type
|
||||
plugins/modules/cloud/google/gcpubsub_info.py validate-modules:doc-required-mismatch
|
||||
plugins/modules/cloud/google/gcpubsub_info.py validate-modules:parameter-state-invalid-choice
|
||||
plugins/modules/cloud/google/gcpubsub_info.py validate-modules:undocumented-parameter
|
||||
plugins/modules/cloud/google/gcspanner.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/cloud/google/gcspanner.py validate-modules:undocumented-parameter
|
||||
plugins/modules/cloud/heroku/heroku_collaborator.py validate-modules:parameter-list-no-elements
|
||||
|
@ -1309,6 +1334,8 @@ plugins/modules/web_infrastructure/taiga_issue.py validate-modules:doc-missing-t
|
|||
plugins/modules/web_infrastructure/taiga_issue.py validate-modules:parameter-list-no-elements
|
||||
plugins/modules/web_infrastructure/taiga_issue.py validate-modules:parameter-type-not-in-doc
|
||||
scripts/inventory/gce.py pylint:blacklisted-name
|
||||
tests/unit/plugins/modules/cloud/google/test_gcp_forwarding_rule.py future-import-boilerplate
|
||||
tests/unit/plugins/modules/cloud/google/test_gcp_forwarding_rule.py metaclass-boilerplate
|
||||
tests/unit/plugins/modules/system/interfaces_file/test_interfaces_file.py pylint:blacklisted-name
|
||||
tests/utils/shippable/check_matrix.py replace-urlopen
|
||||
tests/utils/shippable/timing.py shebang
|
||||
|
|
|
@ -123,6 +123,27 @@ plugins/modules/cloud/google/gce_snapshot.py validate-modules:parameter-type-not
|
|||
plugins/modules/cloud/google/gce_tag.py pylint:blacklisted-name
|
||||
plugins/modules/cloud/google/gce_tag.py validate-modules:parameter-list-no-elements
|
||||
plugins/modules/cloud/google/gce_tag.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/cloud/google/gcp_backend_service.py pylint:blacklisted-name
|
||||
plugins/modules/cloud/google/gcp_backend_service.py validate-modules:doc-choices-do-not-match-spec
|
||||
plugins/modules/cloud/google/gcp_backend_service.py validate-modules:doc-default-does-not-match-spec
|
||||
plugins/modules/cloud/google/gcp_backend_service.py validate-modules:doc-missing-type
|
||||
plugins/modules/cloud/google/gcp_backend_service.py validate-modules:parameter-list-no-elements
|
||||
plugins/modules/cloud/google/gcp_backend_service.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/cloud/google/gcp_backend_service.py validate-modules:undocumented-parameter
|
||||
plugins/modules/cloud/google/gcp_forwarding_rule.py validate-modules:doc-choices-do-not-match-spec
|
||||
plugins/modules/cloud/google/gcp_forwarding_rule.py validate-modules:doc-default-does-not-match-spec
|
||||
plugins/modules/cloud/google/gcp_forwarding_rule.py validate-modules:doc-missing-type
|
||||
plugins/modules/cloud/google/gcp_forwarding_rule.py validate-modules:doc-required-mismatch
|
||||
plugins/modules/cloud/google/gcp_forwarding_rule.py validate-modules:parameter-list-no-elements
|
||||
plugins/modules/cloud/google/gcp_forwarding_rule.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/cloud/google/gcp_forwarding_rule.py validate-modules:undocumented-parameter
|
||||
plugins/modules/cloud/google/gcp_healthcheck.py pylint:blacklisted-name
|
||||
plugins/modules/cloud/google/gcp_healthcheck.py validate-modules:doc-choices-do-not-match-spec
|
||||
plugins/modules/cloud/google/gcp_healthcheck.py validate-modules:doc-default-does-not-match-spec
|
||||
plugins/modules/cloud/google/gcp_healthcheck.py validate-modules:doc-missing-type
|
||||
plugins/modules/cloud/google/gcp_healthcheck.py validate-modules:doc-required-mismatch
|
||||
plugins/modules/cloud/google/gcp_healthcheck.py validate-modules:parameter-list-no-elements
|
||||
plugins/modules/cloud/google/gcp_healthcheck.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/cloud/google/gcp_target_proxy.py validate-modules:doc-choices-do-not-match-spec
|
||||
plugins/modules/cloud/google/gcp_target_proxy.py validate-modules:doc-missing-type
|
||||
plugins/modules/cloud/google/gcp_target_proxy.py validate-modules:doc-required-mismatch
|
||||
|
@ -135,12 +156,16 @@ plugins/modules/cloud/google/gcp_url_map.py validate-modules:doc-missing-type
|
|||
plugins/modules/cloud/google/gcp_url_map.py validate-modules:parameter-list-no-elements
|
||||
plugins/modules/cloud/google/gcp_url_map.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/cloud/google/gcp_url_map.py validate-modules:undocumented-parameter
|
||||
plugins/modules/cloud/google/gcpubsub_facts.py validate-modules:doc-choices-do-not-match-spec
|
||||
plugins/modules/cloud/google/gcpubsub_facts.py validate-modules:doc-default-does-not-match-spec
|
||||
plugins/modules/cloud/google/gcpubsub_facts.py validate-modules:doc-missing-type
|
||||
plugins/modules/cloud/google/gcpubsub_facts.py validate-modules:doc-required-mismatch
|
||||
plugins/modules/cloud/google/gcpubsub_facts.py validate-modules:parameter-state-invalid-choice
|
||||
plugins/modules/cloud/google/gcpubsub_facts.py validate-modules:undocumented-parameter
|
||||
plugins/modules/cloud/google/gcpubsub.py validate-modules:nonexistent-parameter-documented
|
||||
plugins/modules/cloud/google/gcpubsub.py validate-modules:parameter-list-no-elements
|
||||
plugins/modules/cloud/google/gcpubsub.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/cloud/google/gcpubsub.py validate-modules:undocumented-parameter
|
||||
plugins/modules/cloud/google/gcpubsub_info.py validate-modules:doc-choices-do-not-match-spec
|
||||
plugins/modules/cloud/google/gcpubsub_info.py validate-modules:doc-default-does-not-match-spec
|
||||
plugins/modules/cloud/google/gcpubsub_info.py validate-modules:doc-missing-type
|
||||
plugins/modules/cloud/google/gcpubsub_info.py validate-modules:doc-required-mismatch
|
||||
plugins/modules/cloud/google/gcpubsub_info.py validate-modules:parameter-state-invalid-choice
|
||||
plugins/modules/cloud/google/gcpubsub_info.py validate-modules:undocumented-parameter
|
||||
plugins/modules/cloud/google/gcspanner.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/cloud/google/gcspanner.py validate-modules:undocumented-parameter
|
||||
plugins/modules/cloud/heroku/heroku_collaborator.py validate-modules:parameter-list-no-elements
|
||||
|
@ -1309,6 +1334,8 @@ plugins/modules/web_infrastructure/taiga_issue.py validate-modules:doc-missing-t
|
|||
plugins/modules/web_infrastructure/taiga_issue.py validate-modules:parameter-list-no-elements
|
||||
plugins/modules/web_infrastructure/taiga_issue.py validate-modules:parameter-type-not-in-doc
|
||||
scripts/inventory/gce.py pylint:blacklisted-name
|
||||
tests/unit/plugins/modules/cloud/google/test_gcp_forwarding_rule.py future-import-boilerplate
|
||||
tests/unit/plugins/modules/cloud/google/test_gcp_forwarding_rule.py metaclass-boilerplate
|
||||
tests/unit/plugins/modules/system/interfaces_file/test_interfaces_file.py pylint:blacklisted-name
|
||||
tests/utils/shippable/check_matrix.py replace-urlopen
|
||||
tests/utils/shippable/timing.py shebang
|
||||
|
|
|
@ -97,18 +97,30 @@ plugins/modules/cloud/google/gce_snapshot.py validate-modules:doc-missing-type
|
|||
plugins/modules/cloud/google/gce_snapshot.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/cloud/google/gce_tag.py pylint:blacklisted-name
|
||||
plugins/modules/cloud/google/gce_tag.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/cloud/google/gcp_backend_service.py pylint:blacklisted-name
|
||||
plugins/modules/cloud/google/gcp_backend_service.py validate-modules:deprecation-mismatch
|
||||
plugins/modules/cloud/google/gcp_backend_service.py validate-modules:invalid-documentation
|
||||
plugins/modules/cloud/google/gcp_backend_service.py validate-modules:missing-main-call
|
||||
plugins/modules/cloud/google/gcp_forwarding_rule.py validate-modules:deprecation-mismatch
|
||||
plugins/modules/cloud/google/gcp_forwarding_rule.py validate-modules:invalid-documentation
|
||||
plugins/modules/cloud/google/gcp_forwarding_rule.py validate-modules:missing-main-call
|
||||
plugins/modules/cloud/google/gcp_healthcheck.py pylint:blacklisted-name
|
||||
plugins/modules/cloud/google/gcp_healthcheck.py validate-modules:deprecation-mismatch
|
||||
plugins/modules/cloud/google/gcp_healthcheck.py validate-modules:invalid-documentation
|
||||
plugins/modules/cloud/google/gcp_healthcheck.py validate-modules:missing-main-call
|
||||
plugins/modules/cloud/google/gcp_target_proxy.py validate-modules:deprecation-mismatch
|
||||
plugins/modules/cloud/google/gcp_target_proxy.py validate-modules:invalid-documentation
|
||||
plugins/modules/cloud/google/gcp_target_proxy.py validate-modules:missing-main-call
|
||||
plugins/modules/cloud/google/gcp_url_map.py validate-modules:deprecation-mismatch
|
||||
plugins/modules/cloud/google/gcp_url_map.py validate-modules:invalid-documentation
|
||||
plugins/modules/cloud/google/gcp_url_map.py validate-modules:missing-main-call
|
||||
plugins/modules/cloud/google/gcpubsub_facts.py validate-modules:deprecation-mismatch
|
||||
plugins/modules/cloud/google/gcpubsub_facts.py validate-modules:doc-choices-do-not-match-spec
|
||||
plugins/modules/cloud/google/gcpubsub_facts.py validate-modules:doc-default-does-not-match-spec
|
||||
plugins/modules/cloud/google/gcpubsub_facts.py validate-modules:doc-missing-type
|
||||
plugins/modules/cloud/google/gcpubsub_facts.py validate-modules:invalid-documentation
|
||||
plugins/modules/cloud/google/gcpubsub_facts.py validate-modules:undocumented-parameter
|
||||
plugins/modules/cloud/google/gcpubsub.py validate-modules:nonexistent-parameter-documented
|
||||
plugins/modules/cloud/google/gcpubsub.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/cloud/google/gcpubsub.py validate-modules:undocumented-parameter
|
||||
plugins/modules/cloud/google/gcpubsub_info.py validate-modules:doc-choices-do-not-match-spec
|
||||
plugins/modules/cloud/google/gcpubsub_info.py validate-modules:doc-default-does-not-match-spec
|
||||
plugins/modules/cloud/google/gcpubsub_info.py validate-modules:doc-missing-type
|
||||
plugins/modules/cloud/google/gcpubsub_info.py validate-modules:undocumented-parameter
|
||||
plugins/modules/cloud/google/gcspanner.py validate-modules:deprecation-mismatch
|
||||
plugins/modules/cloud/google/gcspanner.py validate-modules:invalid-documentation
|
||||
plugins/modules/cloud/google/gcspanner.py validate-modules:missing-main-call
|
||||
|
@ -1018,6 +1030,8 @@ plugins/modules/web_infrastructure/supervisorctl.py validate-modules:parameter-t
|
|||
plugins/modules/web_infrastructure/taiga_issue.py validate-modules:doc-missing-type
|
||||
plugins/modules/web_infrastructure/taiga_issue.py validate-modules:parameter-type-not-in-doc
|
||||
scripts/inventory/gce.py pylint:blacklisted-name
|
||||
tests/unit/plugins/modules/cloud/google/test_gcp_forwarding_rule.py future-import-boilerplate
|
||||
tests/unit/plugins/modules/cloud/google/test_gcp_forwarding_rule.py metaclass-boilerplate
|
||||
tests/unit/plugins/modules/system/interfaces_file/test_interfaces_file.py pylint:blacklisted-name
|
||||
tests/utils/shippable/check_matrix.py replace-urlopen
|
||||
tests/utils/shippable/timing.py shebang
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
import unittest
|
||||
|
||||
from ansible_collections.community.general.plugins.modules.cloud.google.gcp_forwarding_rule import _build_global_forwarding_rule_dict
|
||||
|
||||
|
||||
class TestGCPFowardingRule(unittest.TestCase):
|
||||
"""Unit tests for gcp_fowarding_rule module."""
|
||||
params_dict = {
|
||||
'forwarding_rule_name': 'foo_fowarding_rule_name',
|
||||
'address': 'foo_external_address',
|
||||
'target': 'foo_targetproxy',
|
||||
'region': 'global',
|
||||
'port_range': 80,
|
||||
'protocol': 'TCP',
|
||||
'state': 'present',
|
||||
}
|
||||
|
||||
def test__build_global_forwarding_rule_dict(self):
|
||||
|
||||
expected = {
|
||||
'name': 'foo_fowarding_rule_name',
|
||||
'IPAddress': 'https://www.googleapis.com/compute/v1/projects/my-project/global/addresses/foo_external_address',
|
||||
'target': 'https://www.googleapis.com/compute/v1/projects/my-project/global/targetHttpProxies/foo_targetproxy',
|
||||
'region': 'global',
|
||||
'portRange': 80,
|
||||
'IPProtocol': 'TCP',
|
||||
}
|
||||
actual = _build_global_forwarding_rule_dict(
|
||||
self.params_dict, 'my-project')
|
||||
self.assertEqual(expected, actual)
|
Loading…
Reference in a new issue