1
0
Fork 0
mirror of https://github.com/ansible-collections/community.general.git synced 2024-09-14 20:13:21 +02:00
community.general/plugins/modules/cloud/scaleway/scaleway_lb.py
2022-08-24 20:16:25 +02:00

359 lines
10 KiB
Python

#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Scaleway Load-balancer management module
#
# Copyright (C) 2018 Online SAS.
# https://www.scaleway.com
#
# 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: scaleway_lb
short_description: Scaleway load-balancer management module
author: Remy Leone (@remyleone)
description:
- "This module manages load-balancers on Scaleway."
extends_documentation_fragment:
- community.general.scaleway
options:
name:
type: str
description:
- Name of the load-balancer
required: true
description:
type: str
description:
- Description of the load-balancer
required: true
organization_id:
type: str
description:
- Organization identifier
required: true
state:
type: str
description:
- Indicate desired state of the instance.
default: present
choices:
- present
- absent
region:
type: str
description:
- Scaleway zone
required: true
choices:
- nl-ams
- fr-par
- pl-waw
tags:
type: list
elements: str
description:
- List of tags to apply to the load-balancer
wait:
description:
- Wait for the load-balancer to reach its desired state before returning.
type: bool
default: false
wait_timeout:
type: int
description:
- Time to wait for the load-balancer to reach the expected state
required: false
default: 300
wait_sleep_time:
type: int
description:
- Time to wait before every attempt to check the state of the load-balancer
required: false
default: 3
'''
EXAMPLES = '''
- name: Create a load-balancer
community.general.scaleway_lb:
name: foobar
state: present
organization_id: 951df375-e094-4d26-97c1-ba548eeb9c42
region: fr-par
tags:
- hello
- name: Delete a load-balancer
community.general.scaleway_lb:
name: foobar
state: absent
organization_id: 951df375-e094-4d26-97c1-ba548eeb9c42
region: fr-par
'''
RETURNS = '''
{
"scaleway_lb": {
"backend_count": 0,
"frontend_count": 0,
"description": "Description of my load-balancer",
"id": "00000000-0000-0000-0000-000000000000",
"instances": [
{
"id": "00000000-0000-0000-0000-000000000000",
"ip_address": "10.0.0.1",
"region": "fr-par",
"status": "ready"
},
{
"id": "00000000-0000-0000-0000-000000000000",
"ip_address": "10.0.0.2",
"region": "fr-par",
"status": "ready"
}
],
"ip": [
{
"id": "00000000-0000-0000-0000-000000000000",
"ip_address": "192.168.0.1",
"lb_id": "00000000-0000-0000-0000-000000000000",
"region": "fr-par",
"organization_id": "00000000-0000-0000-0000-000000000000",
"reverse": ""
}
],
"name": "lb_ansible_test",
"organization_id": "00000000-0000-0000-0000-000000000000",
"region": "fr-par",
"status": "ready",
"tags": [
"first_tag",
"second_tag"
]
}
}
'''
import datetime
import time
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.community.general.plugins.module_utils.scaleway import SCALEWAY_REGIONS, SCALEWAY_ENDPOINT, scaleway_argument_spec, Scaleway
STABLE_STATES = (
"ready",
"absent"
)
MUTABLE_ATTRIBUTES = (
"name",
"description"
)
def payload_from_wished_lb(wished_lb):
return {
"organization_id": wished_lb["organization_id"],
"name": wished_lb["name"],
"tags": wished_lb["tags"],
"description": wished_lb["description"]
}
def fetch_state(api, lb):
api.module.debug("fetch_state of load-balancer: %s" % lb["id"])
response = api.get(path=api.api_path + "/%s" % lb["id"])
if response.status_code == 404:
return "absent"
if not response.ok:
msg = 'Error during state fetching: (%s) %s' % (response.status_code, response.json)
api.module.fail_json(msg=msg)
try:
api.module.debug("Load-balancer %s in state: %s" % (lb["id"], response.json["status"]))
return response.json["status"]
except KeyError:
api.module.fail_json(msg="Could not fetch state in %s" % response.json)
def wait_to_complete_state_transition(api, lb, force_wait=False):
wait = api.module.params["wait"]
if not (wait or force_wait):
return
wait_timeout = api.module.params["wait_timeout"]
wait_sleep_time = api.module.params["wait_sleep_time"]
start = datetime.datetime.utcnow()
end = start + datetime.timedelta(seconds=wait_timeout)
while datetime.datetime.utcnow() < end:
api.module.debug("We are going to wait for the load-balancer to finish its transition")
state = fetch_state(api, lb)
if state in STABLE_STATES:
api.module.debug("It seems that the load-balancer is not in transition anymore.")
api.module.debug("load-balancer in state: %s" % fetch_state(api, lb))
break
time.sleep(wait_sleep_time)
else:
api.module.fail_json(msg="Server takes too long to finish its transition")
def lb_attributes_should_be_changed(target_lb, wished_lb):
diff = dict((attr, wished_lb[attr]) for attr in MUTABLE_ATTRIBUTES if target_lb[attr] != wished_lb[attr])
if diff:
return dict((attr, wished_lb[attr]) for attr in MUTABLE_ATTRIBUTES)
else:
return diff
def present_strategy(api, wished_lb):
changed = False
response = api.get(path=api.api_path)
if not response.ok:
api.module.fail_json(msg='Error getting load-balancers [{0}: {1}]'.format(
response.status_code, response.json['message']))
lbs_list = response.json["lbs"]
lb_lookup = dict((lb["name"], lb)
for lb in lbs_list)
if wished_lb["name"] not in lb_lookup.keys():
changed = True
if api.module.check_mode:
return changed, {"status": "A load-balancer would be created."}
# Create Load-balancer
api.warn(payload_from_wished_lb(wished_lb))
creation_response = api.post(path=api.api_path,
data=payload_from_wished_lb(wished_lb))
if not creation_response.ok:
msg = "Error during lb creation: %s: '%s' (%s)" % (creation_response.info['msg'],
creation_response.json['message'],
creation_response.json)
api.module.fail_json(msg=msg)
wait_to_complete_state_transition(api=api, lb=creation_response.json)
response = api.get(path=api.api_path + "/%s" % creation_response.json["id"])
return changed, response.json
target_lb = lb_lookup[wished_lb["name"]]
patch_payload = lb_attributes_should_be_changed(target_lb=target_lb,
wished_lb=wished_lb)
if not patch_payload:
return changed, target_lb
changed = True
if api.module.check_mode:
return changed, {"status": "Load-balancer attributes would be changed."}
lb_patch_response = api.put(path=api.api_path + "/%s" % target_lb["id"],
data=patch_payload)
if not lb_patch_response.ok:
api.module.fail_json(msg='Error during load-balancer attributes update: [{0}: {1}]'.format(
lb_patch_response.status_code, lb_patch_response.json['message']))
wait_to_complete_state_transition(api=api, lb=target_lb)
return changed, lb_patch_response.json
def absent_strategy(api, wished_lb):
response = api.get(path=api.api_path)
changed = False
status_code = response.status_code
lbs_json = response.json
lbs_list = lbs_json["lbs"]
if not response.ok:
api.module.fail_json(msg='Error getting load-balancers [{0}: {1}]'.format(
status_code, response.json['message']))
lb_lookup = dict((lb["name"], lb)
for lb in lbs_list)
if wished_lb["name"] not in lb_lookup.keys():
return changed, {}
target_lb = lb_lookup[wished_lb["name"]]
changed = True
if api.module.check_mode:
return changed, {"status": "Load-balancer would be destroyed"}
wait_to_complete_state_transition(api=api, lb=target_lb, force_wait=True)
response = api.delete(path=api.api_path + "/%s" % target_lb["id"])
if not response.ok:
api.module.fail_json(msg='Error deleting load-balancer [{0}: {1}]'.format(
response.status_code, response.json))
wait_to_complete_state_transition(api=api, lb=target_lb)
return changed, response.json
state_strategy = {
"present": present_strategy,
"absent": absent_strategy
}
def core(module):
region = module.params["region"]
wished_load_balancer = {
"state": module.params["state"],
"name": module.params["name"],
"description": module.params["description"],
"tags": module.params["tags"],
"organization_id": module.params["organization_id"]
}
module.params['api_url'] = SCALEWAY_ENDPOINT
api = Scaleway(module=module)
api.api_path = "lb/v1/regions/%s/lbs" % region
changed, summary = state_strategy[wished_load_balancer["state"]](api=api,
wished_lb=wished_load_balancer)
module.exit_json(changed=changed, scaleway_lb=summary)
def main():
argument_spec = scaleway_argument_spec()
argument_spec.update(dict(
name=dict(required=True),
description=dict(required=True),
region=dict(required=True, choices=SCALEWAY_REGIONS),
state=dict(choices=list(state_strategy.keys()), default='present'),
tags=dict(type="list", elements="str", default=[]),
organization_id=dict(required=True),
wait=dict(type="bool", default=False),
wait_timeout=dict(type="int", default=300),
wait_sleep_time=dict(type="int", default=3),
))
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
)
core(module)
if __name__ == '__main__':
main()