#!/usr/bin/python # -*- coding: utf-8 -*- # Copyright Ansible Project # GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) # SPDX-License-Identifier: GPL-3.0-or-later from __future__ import absolute_import, division, print_function __metaclass__ = type DOCUMENTATION = ''' --- module: ovh_ip_failover short_description: Manage OVH IP failover address description: - Manage OVH (French European hosting provider) IP Failover Address. For now, this module can only be used to move an ip failover (or failover block) between services author: "Pascal HERAUD (@pascalheraud)" notes: - Uses the python OVH Api U(https://github.com/ovh/python-ovh). You have to create an application (a key and secret) with a consumer key as described into U(https://docs.ovh.com/gb/en/customer/first-steps-with-ovh-api/) requirements: - ovh >= 0.4.8 extends_documentation_fragment: - community.general.attributes attributes: check_mode: support: full diff_mode: support: none options: name: required: true description: - The IP address to manage (can be a single IP like 1.1.1.1 or a block like 1.1.1.1/28 ) type: str service: required: true description: - The name of the OVH service this IP address should be routed type: str endpoint: required: true description: - The endpoint to use ( for instance ovh-eu) type: str wait_completion: required: false default: true type: bool description: - If true, the module will wait for the IP address to be moved. If false, exit without waiting. The taskId will be returned in module output wait_task_completion: required: false default: 0 description: - If not 0, the module will wait for this task id to be completed. Use wait_task_completion if you want to wait for completion of a previously executed task with wait_completion=false. You can execute this module repeatedly on a list of failover IPs using wait_completion=false (see examples) type: int application_key: required: true description: - The applicationKey to use type: str application_secret: required: true description: - The application secret to use type: str consumer_key: required: true description: - The consumer key to use type: str timeout: required: false default: 120 description: - The timeout in seconds used to wait for a task to be completed. Default is 120 seconds. type: int ''' EXAMPLES = ''' # Route an IP address 1.1.1.1 to the service ns666.ovh.net - community.general.ovh_ip_failover: name: 1.1.1.1 service: ns666.ovh.net endpoint: ovh-eu application_key: yourkey application_secret: yoursecret consumer_key: yourconsumerkey - community.general.ovh_ip_failover: name: 1.1.1.1 service: ns666.ovh.net endpoint: ovh-eu wait_completion: false application_key: yourkey application_secret: yoursecret consumer_key: yourconsumerkey register: moved - community.general.ovh_ip_failover: name: 1.1.1.1 service: ns666.ovh.net endpoint: ovh-eu wait_task_completion: "{{moved.taskId}}" application_key: yourkey application_secret: yoursecret consumer_key: yourconsumerkey ''' RETURN = ''' ''' import time try: import ovh import ovh.exceptions from ovh.exceptions import APIError HAS_OVH = True except ImportError: HAS_OVH = False from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.six.moves.urllib.parse import quote_plus def getOvhClient(ansibleModule): endpoint = ansibleModule.params.get('endpoint') application_key = ansibleModule.params.get('application_key') application_secret = ansibleModule.params.get('application_secret') consumer_key = ansibleModule.params.get('consumer_key') return ovh.Client( endpoint=endpoint, application_key=application_key, application_secret=application_secret, consumer_key=consumer_key ) def waitForNoTask(client, name, timeout): currentTimeout = timeout while client.get('/ip/{0}/task'.format(quote_plus(name)), function='genericMoveFloatingIp', status='todo'): time.sleep(1) # Delay for 1 sec currentTimeout -= 1 if currentTimeout < 0: return False return True def waitForTaskDone(client, name, taskId, timeout): currentTimeout = timeout while True: task = client.get('/ip/{0}/task/{1}'.format(quote_plus(name), taskId)) if task['status'] == 'done': return True time.sleep(5) # Delay for 5 sec because it's long to wait completion, do not harass the API currentTimeout -= 5 if currentTimeout < 0: return False def main(): module = AnsibleModule( argument_spec=dict( name=dict(required=True), service=dict(required=True), endpoint=dict(required=True), wait_completion=dict(default=True, type='bool'), wait_task_completion=dict(default=0, type='int'), application_key=dict(required=True, no_log=True), application_secret=dict(required=True, no_log=True), consumer_key=dict(required=True, no_log=True), timeout=dict(default=120, type='int') ), supports_check_mode=True ) result = dict( changed=False ) if not HAS_OVH: module.fail_json(msg='ovh-api python module is required to run this module ') # Get parameters name = module.params.get('name') service = module.params.get('service') timeout = module.params.get('timeout') wait_completion = module.params.get('wait_completion') wait_task_completion = module.params.get('wait_task_completion') # Connect to OVH API client = getOvhClient(module) # Check that the load balancing exists try: ips = client.get('/ip', ip=name, type='failover') except APIError as apiError: module.fail_json( msg='Unable to call OVH api for getting the list of ips, ' 'check application key, secret, consumerkey and parameters. ' 'Error returned by OVH api was : {0}'.format(apiError)) if name not in ips and '{0}/32'.format(name) not in ips: module.fail_json(msg='IP {0} does not exist'.format(name)) # Check that no task is pending before going on try: if not waitForNoTask(client, name, timeout): module.fail_json( msg='Timeout of {0} seconds while waiting for no pending ' 'tasks before executing the module '.format(timeout)) except APIError as apiError: module.fail_json( msg='Unable to call OVH api for getting the list of pending tasks ' 'of the ip, check application key, secret, consumerkey ' 'and parameters. Error returned by OVH api was : {0}' .format(apiError)) try: ipproperties = client.get('/ip/{0}'.format(quote_plus(name))) except APIError as apiError: module.fail_json( msg='Unable to call OVH api for getting the properties ' 'of the ip, check application key, secret, consumerkey ' 'and parameters. Error returned by OVH api was : {0}' .format(apiError)) if ipproperties['routedTo']['serviceName'] != service: if not module.check_mode: if wait_task_completion == 0: # Move the IP and get the created taskId task = client.post('/ip/{0}/move'.format(quote_plus(name)), to=service) taskId = task['taskId'] result['moved'] = True else: # Just wait for the given taskId to be completed taskId = wait_task_completion result['moved'] = False result['taskId'] = taskId if wait_completion or wait_task_completion != 0: if not waitForTaskDone(client, name, taskId, timeout): module.fail_json( msg='Timeout of {0} seconds while waiting for completion ' 'of move ip to service'.format(timeout)) result['waited'] = True else: result['waited'] = False result['changed'] = True module.exit_json(**result) if __name__ == '__main__': main()