mirror of
https://github.com/ansible-collections/community.general.git
synced 2024-09-14 20:13:21 +02:00
Remove modules that were moved to the google.cloud collection according to ansible/ansible's ansible_builtin_runtime.yml.
This commit is contained in:
parent
c929fe3f17
commit
a1442ccc35
9 changed files with 0 additions and 1555 deletions
|
@ -1,400 +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
|
||||
|
||||
|
||||
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(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_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()
|
|
@ -1,349 +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
|
||||
|
||||
|
||||
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(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_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()
|
|
@ -1,444 +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
|
||||
|
||||
|
||||
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(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:
|
||||
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_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()
|
|
@ -1,328 +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
|
||||
|
||||
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
|
||||
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_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 +0,0 @@
|
|||
./cloud/google/gcp_backend_service.py
|
|
@ -1 +0,0 @@
|
|||
./cloud/google/gcp_forwarding_rule.py
|
|
@ -1 +0,0 @@
|
|||
./cloud/google/gcp_healthcheck.py
|
|
@ -1 +0,0 @@
|
|||
./cloud/google/gcpubsub.py
|
|
@ -1,30 +0,0 @@
|
|||
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