mirror of
https://github.com/ansible-collections/community.general.git
synced 2025-07-22 21:00:22 -07:00
Initial commit
This commit is contained in:
commit
aebc1b03fd
4861 changed files with 812621 additions and 0 deletions
660
plugins/modules/cloud/scaleway/scaleway_compute.py
Normal file
660
plugins/modules/cloud/scaleway/scaleway_compute.py
Normal file
|
@ -0,0 +1,660 @@
|
|||
#!/usr/bin/python
|
||||
#
|
||||
# Scaleway Compute management module
|
||||
#
|
||||
# Copyright (C) 2018 Online SAS.
|
||||
# https://www.scaleway.com
|
||||
#
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
ANSIBLE_METADATA = {
|
||||
'metadata_version': '1.1',
|
||||
'status': ['preview'],
|
||||
'supported_by': 'community'
|
||||
}
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: scaleway_compute
|
||||
short_description: Scaleway compute management module
|
||||
author: Remy Leone (@sieben)
|
||||
description:
|
||||
- "This module manages compute instances on Scaleway."
|
||||
extends_documentation_fragment:
|
||||
- community.general.scaleway
|
||||
|
||||
|
||||
options:
|
||||
|
||||
public_ip:
|
||||
description:
|
||||
- Manage public IP on a Scaleway server
|
||||
- Could be Scaleway IP address UUID
|
||||
- C(dynamic) Means that IP is destroyed at the same time the host is destroyed
|
||||
- C(absent) Means no public IP at all
|
||||
default: absent
|
||||
|
||||
enable_ipv6:
|
||||
description:
|
||||
- Enable public IPv6 connectivity on the instance
|
||||
default: false
|
||||
type: bool
|
||||
|
||||
image:
|
||||
description:
|
||||
- Image identifier used to start the instance with
|
||||
required: true
|
||||
|
||||
name:
|
||||
description:
|
||||
- Name of the instance
|
||||
|
||||
organization:
|
||||
description:
|
||||
- Organization identifier
|
||||
required: true
|
||||
|
||||
state:
|
||||
description:
|
||||
- Indicate desired state of the instance.
|
||||
default: present
|
||||
choices:
|
||||
- present
|
||||
- absent
|
||||
- running
|
||||
- restarted
|
||||
- stopped
|
||||
|
||||
tags:
|
||||
description:
|
||||
- List of tags to apply to the instance (5 max)
|
||||
required: false
|
||||
default: []
|
||||
|
||||
region:
|
||||
description:
|
||||
- Scaleway compute zone
|
||||
required: true
|
||||
choices:
|
||||
- ams1
|
||||
- EMEA-NL-EVS
|
||||
- par1
|
||||
- EMEA-FR-PAR1
|
||||
|
||||
commercial_type:
|
||||
description:
|
||||
- Commercial name of the compute node
|
||||
required: true
|
||||
|
||||
wait:
|
||||
description:
|
||||
- Wait for the instance to reach its desired state before returning.
|
||||
type: bool
|
||||
default: 'no'
|
||||
|
||||
wait_timeout:
|
||||
description:
|
||||
- Time to wait for the server to reach the expected state
|
||||
required: false
|
||||
default: 300
|
||||
|
||||
wait_sleep_time:
|
||||
description:
|
||||
- Time to wait before every attempt to check the state of the server
|
||||
required: false
|
||||
default: 3
|
||||
|
||||
security_group:
|
||||
description:
|
||||
- Security group unique identifier
|
||||
- If no value provided, the default security group or current security group will be used
|
||||
required: false
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
- name: Create a server
|
||||
scaleway_compute:
|
||||
name: foobar
|
||||
state: present
|
||||
image: 89ee4018-f8c3-4dc4-a6b5-bca14f985ebe
|
||||
organization: 951df375-e094-4d26-97c1-ba548eeb9c42
|
||||
region: ams1
|
||||
commercial_type: VC1S
|
||||
tags:
|
||||
- test
|
||||
- www
|
||||
|
||||
- name: Create a server attached to a security group
|
||||
scaleway_compute:
|
||||
name: foobar
|
||||
state: present
|
||||
image: 89ee4018-f8c3-4dc4-a6b5-bca14f985ebe
|
||||
organization: 951df375-e094-4d26-97c1-ba548eeb9c42
|
||||
region: ams1
|
||||
commercial_type: VC1S
|
||||
security_group: 4a31b633-118e-4900-bd52-facf1085fc8d
|
||||
tags:
|
||||
- test
|
||||
- www
|
||||
|
||||
- name: Destroy it right after
|
||||
scaleway_compute:
|
||||
name: foobar
|
||||
state: absent
|
||||
image: 89ee4018-f8c3-4dc4-a6b5-bca14f985ebe
|
||||
organization: 951df375-e094-4d26-97c1-ba548eeb9c42
|
||||
region: ams1
|
||||
commercial_type: VC1S
|
||||
'''
|
||||
|
||||
RETURN = '''
|
||||
'''
|
||||
|
||||
import datetime
|
||||
import time
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible.module_utils.six.moves.urllib.parse import quote as urlquote
|
||||
from ansible_collections.community.general.plugins.module_utils.scaleway import SCALEWAY_LOCATION, scaleway_argument_spec, Scaleway
|
||||
|
||||
SCALEWAY_SERVER_STATES = (
|
||||
'stopped',
|
||||
'stopping',
|
||||
'starting',
|
||||
'running',
|
||||
'locked'
|
||||
)
|
||||
|
||||
SCALEWAY_TRANSITIONS_STATES = (
|
||||
"stopping",
|
||||
"starting",
|
||||
"pending"
|
||||
)
|
||||
|
||||
|
||||
def check_image_id(compute_api, image_id):
|
||||
response = compute_api.get(path="images/%s" % image_id)
|
||||
|
||||
if not response.ok:
|
||||
msg = 'Error in getting image %s on %s : %s' % (image_id, compute_api.module.params.get('api_url'), response.json)
|
||||
compute_api.module.fail_json(msg=msg)
|
||||
|
||||
|
||||
def fetch_state(compute_api, server):
|
||||
compute_api.module.debug("fetch_state of server: %s" % server["id"])
|
||||
response = compute_api.get(path="servers/%s" % server["id"])
|
||||
|
||||
if response.status_code == 404:
|
||||
return "absent"
|
||||
|
||||
if not response.ok:
|
||||
msg = 'Error during state fetching: (%s) %s' % (response.status_code, response.json)
|
||||
compute_api.module.fail_json(msg=msg)
|
||||
|
||||
try:
|
||||
compute_api.module.debug("Server %s in state: %s" % (server["id"], response.json["server"]["state"]))
|
||||
return response.json["server"]["state"]
|
||||
except KeyError:
|
||||
compute_api.module.fail_json(msg="Could not fetch state in %s" % response.json)
|
||||
|
||||
|
||||
def wait_to_complete_state_transition(compute_api, server):
|
||||
wait = compute_api.module.params["wait"]
|
||||
if not wait:
|
||||
return
|
||||
wait_timeout = compute_api.module.params["wait_timeout"]
|
||||
wait_sleep_time = compute_api.module.params["wait_sleep_time"]
|
||||
|
||||
start = datetime.datetime.utcnow()
|
||||
end = start + datetime.timedelta(seconds=wait_timeout)
|
||||
while datetime.datetime.utcnow() < end:
|
||||
compute_api.module.debug("We are going to wait for the server to finish its transition")
|
||||
if fetch_state(compute_api, server) not in SCALEWAY_TRANSITIONS_STATES:
|
||||
compute_api.module.debug("It seems that the server is not in transition anymore.")
|
||||
compute_api.module.debug("Server in state: %s" % fetch_state(compute_api, server))
|
||||
break
|
||||
time.sleep(wait_sleep_time)
|
||||
else:
|
||||
compute_api.module.fail_json(msg="Server takes too long to finish its transition")
|
||||
|
||||
|
||||
def public_ip_payload(compute_api, public_ip):
|
||||
# We don't want a public ip
|
||||
if public_ip in ("absent",):
|
||||
return {"dynamic_ip_required": False}
|
||||
|
||||
# IP is only attached to the instance and is released as soon as the instance terminates
|
||||
if public_ip in ("dynamic", "allocated"):
|
||||
return {"dynamic_ip_required": True}
|
||||
|
||||
# We check that the IP we want to attach exists, if so its ID is returned
|
||||
response = compute_api.get("ips")
|
||||
if not response.ok:
|
||||
msg = 'Error during public IP validation: (%s) %s' % (response.status_code, response.json)
|
||||
compute_api.module.fail_json(msg=msg)
|
||||
|
||||
ip_list = []
|
||||
try:
|
||||
ip_list = response.json["ips"]
|
||||
except KeyError:
|
||||
compute_api.module.fail_json(msg="Error in getting the IP information from: %s" % response.json)
|
||||
|
||||
lookup = [ip["id"] for ip in ip_list]
|
||||
if public_ip in lookup:
|
||||
return {"public_ip": public_ip}
|
||||
|
||||
|
||||
def create_server(compute_api, server):
|
||||
compute_api.module.debug("Starting a create_server")
|
||||
target_server = None
|
||||
data = {"enable_ipv6": server["enable_ipv6"],
|
||||
"tags": server["tags"],
|
||||
"commercial_type": server["commercial_type"],
|
||||
"image": server["image"],
|
||||
"dynamic_ip_required": server["dynamic_ip_required"],
|
||||
"name": server["name"],
|
||||
"organization": server["organization"]
|
||||
}
|
||||
|
||||
if server["security_group"]:
|
||||
data["security_group"] = server["security_group"]
|
||||
|
||||
response = compute_api.post(path="servers", data=data)
|
||||
|
||||
if not response.ok:
|
||||
msg = 'Error during server creation: (%s) %s' % (response.status_code, response.json)
|
||||
compute_api.module.fail_json(msg=msg)
|
||||
|
||||
try:
|
||||
target_server = response.json["server"]
|
||||
except KeyError:
|
||||
compute_api.module.fail_json(msg="Error in getting the server information from: %s" % response.json)
|
||||
|
||||
wait_to_complete_state_transition(compute_api=compute_api, server=target_server)
|
||||
|
||||
return target_server
|
||||
|
||||
|
||||
def restart_server(compute_api, server):
|
||||
return perform_action(compute_api=compute_api, server=server, action="reboot")
|
||||
|
||||
|
||||
def stop_server(compute_api, server):
|
||||
return perform_action(compute_api=compute_api, server=server, action="poweroff")
|
||||
|
||||
|
||||
def start_server(compute_api, server):
|
||||
return perform_action(compute_api=compute_api, server=server, action="poweron")
|
||||
|
||||
|
||||
def perform_action(compute_api, server, action):
|
||||
response = compute_api.post(path="servers/%s/action" % server["id"],
|
||||
data={"action": action})
|
||||
if not response.ok:
|
||||
msg = 'Error during server %s: (%s) %s' % (action, response.status_code, response.json)
|
||||
compute_api.module.fail_json(msg=msg)
|
||||
|
||||
wait_to_complete_state_transition(compute_api=compute_api, server=server)
|
||||
|
||||
return response
|
||||
|
||||
|
||||
def remove_server(compute_api, server):
|
||||
compute_api.module.debug("Starting remove server strategy")
|
||||
response = compute_api.delete(path="servers/%s" % server["id"])
|
||||
if not response.ok:
|
||||
msg = 'Error during server deletion: (%s) %s' % (response.status_code, response.json)
|
||||
compute_api.module.fail_json(msg=msg)
|
||||
|
||||
wait_to_complete_state_transition(compute_api=compute_api, server=server)
|
||||
|
||||
return response
|
||||
|
||||
|
||||
def present_strategy(compute_api, wished_server):
|
||||
compute_api.module.debug("Starting present strategy")
|
||||
changed = False
|
||||
query_results = find(compute_api=compute_api, wished_server=wished_server, per_page=1)
|
||||
|
||||
if not query_results:
|
||||
changed = True
|
||||
if compute_api.module.check_mode:
|
||||
return changed, {"status": "A server would be created."}
|
||||
|
||||
target_server = create_server(compute_api=compute_api, server=wished_server)
|
||||
else:
|
||||
target_server = query_results[0]
|
||||
|
||||
if server_attributes_should_be_changed(compute_api=compute_api, target_server=target_server,
|
||||
wished_server=wished_server):
|
||||
changed = True
|
||||
|
||||
if compute_api.module.check_mode:
|
||||
return changed, {"status": "Server %s attributes would be changed." % target_server["id"]}
|
||||
|
||||
target_server = server_change_attributes(compute_api=compute_api, target_server=target_server, wished_server=wished_server)
|
||||
|
||||
return changed, target_server
|
||||
|
||||
|
||||
def absent_strategy(compute_api, wished_server):
|
||||
compute_api.module.debug("Starting absent strategy")
|
||||
changed = False
|
||||
target_server = None
|
||||
query_results = find(compute_api=compute_api, wished_server=wished_server, per_page=1)
|
||||
|
||||
if not query_results:
|
||||
return changed, {"status": "Server already absent."}
|
||||
else:
|
||||
target_server = query_results[0]
|
||||
|
||||
changed = True
|
||||
|
||||
if compute_api.module.check_mode:
|
||||
return changed, {"status": "Server %s would be made absent." % target_server["id"]}
|
||||
|
||||
# A server MUST be stopped to be deleted.
|
||||
while fetch_state(compute_api=compute_api, server=target_server) != "stopped":
|
||||
wait_to_complete_state_transition(compute_api=compute_api, server=target_server)
|
||||
response = stop_server(compute_api=compute_api, server=target_server)
|
||||
|
||||
if not response.ok:
|
||||
err_msg = 'Error while stopping a server before removing it [{0}: {1}]'.format(response.status_code,
|
||||
response.json)
|
||||
compute_api.module.fail_json(msg=err_msg)
|
||||
|
||||
wait_to_complete_state_transition(compute_api=compute_api, server=target_server)
|
||||
|
||||
response = remove_server(compute_api=compute_api, server=target_server)
|
||||
|
||||
if not response.ok:
|
||||
err_msg = 'Error while removing server [{0}: {1}]'.format(response.status_code, response.json)
|
||||
compute_api.module.fail_json(msg=err_msg)
|
||||
|
||||
return changed, {"status": "Server %s deleted" % target_server["id"]}
|
||||
|
||||
|
||||
def running_strategy(compute_api, wished_server):
|
||||
compute_api.module.debug("Starting running strategy")
|
||||
changed = False
|
||||
query_results = find(compute_api=compute_api, wished_server=wished_server, per_page=1)
|
||||
|
||||
if not query_results:
|
||||
changed = True
|
||||
if compute_api.module.check_mode:
|
||||
return changed, {"status": "A server would be created before being run."}
|
||||
|
||||
target_server = create_server(compute_api=compute_api, server=wished_server)
|
||||
else:
|
||||
target_server = query_results[0]
|
||||
|
||||
if server_attributes_should_be_changed(compute_api=compute_api, target_server=target_server,
|
||||
wished_server=wished_server):
|
||||
changed = True
|
||||
|
||||
if compute_api.module.check_mode:
|
||||
return changed, {"status": "Server %s attributes would be changed before running it." % target_server["id"]}
|
||||
|
||||
target_server = server_change_attributes(compute_api=compute_api, target_server=target_server, wished_server=wished_server)
|
||||
|
||||
current_state = fetch_state(compute_api=compute_api, server=target_server)
|
||||
if current_state not in ("running", "starting"):
|
||||
compute_api.module.debug("running_strategy: Server in state: %s" % current_state)
|
||||
changed = True
|
||||
|
||||
if compute_api.module.check_mode:
|
||||
return changed, {"status": "Server %s attributes would be changed." % target_server["id"]}
|
||||
|
||||
response = start_server(compute_api=compute_api, server=target_server)
|
||||
if not response.ok:
|
||||
msg = 'Error while running server [{0}: {1}]'.format(response.status_code, response.json)
|
||||
compute_api.module.fail_json(msg=msg)
|
||||
|
||||
return changed, target_server
|
||||
|
||||
|
||||
def stop_strategy(compute_api, wished_server):
|
||||
compute_api.module.debug("Starting stop strategy")
|
||||
query_results = find(compute_api=compute_api, wished_server=wished_server, per_page=1)
|
||||
|
||||
changed = False
|
||||
|
||||
if not query_results:
|
||||
|
||||
if compute_api.module.check_mode:
|
||||
return changed, {"status": "A server would be created before being stopped."}
|
||||
|
||||
target_server = create_server(compute_api=compute_api, server=wished_server)
|
||||
changed = True
|
||||
else:
|
||||
target_server = query_results[0]
|
||||
|
||||
compute_api.module.debug("stop_strategy: Servers are found.")
|
||||
|
||||
if server_attributes_should_be_changed(compute_api=compute_api, target_server=target_server,
|
||||
wished_server=wished_server):
|
||||
changed = True
|
||||
|
||||
if compute_api.module.check_mode:
|
||||
return changed, {
|
||||
"status": "Server %s attributes would be changed before stopping it." % target_server["id"]}
|
||||
|
||||
target_server = server_change_attributes(compute_api=compute_api, target_server=target_server, wished_server=wished_server)
|
||||
|
||||
wait_to_complete_state_transition(compute_api=compute_api, server=target_server)
|
||||
|
||||
current_state = fetch_state(compute_api=compute_api, server=target_server)
|
||||
if current_state not in ("stopped",):
|
||||
compute_api.module.debug("stop_strategy: Server in state: %s" % current_state)
|
||||
|
||||
changed = True
|
||||
|
||||
if compute_api.module.check_mode:
|
||||
return changed, {"status": "Server %s would be stopped." % target_server["id"]}
|
||||
|
||||
response = stop_server(compute_api=compute_api, server=target_server)
|
||||
compute_api.module.debug(response.json)
|
||||
compute_api.module.debug(response.ok)
|
||||
|
||||
if not response.ok:
|
||||
msg = 'Error while stopping server [{0}: {1}]'.format(response.status_code, response.json)
|
||||
compute_api.module.fail_json(msg=msg)
|
||||
|
||||
return changed, target_server
|
||||
|
||||
|
||||
def restart_strategy(compute_api, wished_server):
|
||||
compute_api.module.debug("Starting restart strategy")
|
||||
changed = False
|
||||
query_results = find(compute_api=compute_api, wished_server=wished_server, per_page=1)
|
||||
|
||||
if not query_results:
|
||||
changed = True
|
||||
if compute_api.module.check_mode:
|
||||
return changed, {"status": "A server would be created before being rebooted."}
|
||||
|
||||
target_server = create_server(compute_api=compute_api, server=wished_server)
|
||||
else:
|
||||
target_server = query_results[0]
|
||||
|
||||
if server_attributes_should_be_changed(compute_api=compute_api,
|
||||
target_server=target_server,
|
||||
wished_server=wished_server):
|
||||
changed = True
|
||||
|
||||
if compute_api.module.check_mode:
|
||||
return changed, {
|
||||
"status": "Server %s attributes would be changed before rebooting it." % target_server["id"]}
|
||||
|
||||
target_server = server_change_attributes(compute_api=compute_api, target_server=target_server, wished_server=wished_server)
|
||||
|
||||
changed = True
|
||||
if compute_api.module.check_mode:
|
||||
return changed, {"status": "Server %s would be rebooted." % target_server["id"]}
|
||||
|
||||
wait_to_complete_state_transition(compute_api=compute_api, server=target_server)
|
||||
|
||||
if fetch_state(compute_api=compute_api, server=target_server) in ("running",):
|
||||
response = restart_server(compute_api=compute_api, server=target_server)
|
||||
wait_to_complete_state_transition(compute_api=compute_api, server=target_server)
|
||||
if not response.ok:
|
||||
msg = 'Error while restarting server that was running [{0}: {1}].'.format(response.status_code,
|
||||
response.json)
|
||||
compute_api.module.fail_json(msg=msg)
|
||||
|
||||
if fetch_state(compute_api=compute_api, server=target_server) in ("stopped",):
|
||||
response = restart_server(compute_api=compute_api, server=target_server)
|
||||
wait_to_complete_state_transition(compute_api=compute_api, server=target_server)
|
||||
if not response.ok:
|
||||
msg = 'Error while restarting server that was stopped [{0}: {1}].'.format(response.status_code,
|
||||
response.json)
|
||||
compute_api.module.fail_json(msg=msg)
|
||||
|
||||
return changed, target_server
|
||||
|
||||
|
||||
state_strategy = {
|
||||
"present": present_strategy,
|
||||
"restarted": restart_strategy,
|
||||
"stopped": stop_strategy,
|
||||
"running": running_strategy,
|
||||
"absent": absent_strategy
|
||||
}
|
||||
|
||||
|
||||
def find(compute_api, wished_server, per_page=1):
|
||||
compute_api.module.debug("Getting inside find")
|
||||
# Only the name attribute is accepted in the Compute query API
|
||||
response = compute_api.get("servers", params={"name": wished_server["name"],
|
||||
"per_page": per_page})
|
||||
|
||||
if not response.ok:
|
||||
msg = 'Error during server search: (%s) %s' % (response.status_code, response.json)
|
||||
compute_api.module.fail_json(msg=msg)
|
||||
|
||||
search_results = response.json["servers"]
|
||||
|
||||
return search_results
|
||||
|
||||
|
||||
PATCH_MUTABLE_SERVER_ATTRIBUTES = (
|
||||
"ipv6",
|
||||
"tags",
|
||||
"name",
|
||||
"dynamic_ip_required",
|
||||
"security_group",
|
||||
)
|
||||
|
||||
|
||||
def server_attributes_should_be_changed(compute_api, target_server, wished_server):
|
||||
compute_api.module.debug("Checking if server attributes should be changed")
|
||||
compute_api.module.debug("Current Server: %s" % target_server)
|
||||
compute_api.module.debug("Wished Server: %s" % wished_server)
|
||||
debug_dict = dict((x, (target_server[x], wished_server[x]))
|
||||
for x in PATCH_MUTABLE_SERVER_ATTRIBUTES
|
||||
if x in target_server and x in wished_server)
|
||||
compute_api.module.debug("Debug dict %s" % debug_dict)
|
||||
try:
|
||||
for key in PATCH_MUTABLE_SERVER_ATTRIBUTES:
|
||||
if key in target_server and key in wished_server:
|
||||
# When you are working with dict, only ID matter as we ask user to put only the resource ID in the playbook
|
||||
if isinstance(target_server[key], dict) and wished_server[key] and "id" in target_server[key].keys(
|
||||
) and target_server[key]["id"] != wished_server[key]:
|
||||
return True
|
||||
# Handling other structure compare simply the two objects content
|
||||
elif not isinstance(target_server[key], dict) and target_server[key] != wished_server[key]:
|
||||
return True
|
||||
return False
|
||||
except AttributeError:
|
||||
compute_api.module.fail_json(msg="Error while checking if attributes should be changed")
|
||||
|
||||
|
||||
def server_change_attributes(compute_api, target_server, wished_server):
|
||||
compute_api.module.debug("Starting patching server attributes")
|
||||
patch_payload = dict()
|
||||
|
||||
for key in PATCH_MUTABLE_SERVER_ATTRIBUTES:
|
||||
if key in target_server and key in wished_server:
|
||||
# When you are working with dict, only ID matter as we ask user to put only the resource ID in the playbook
|
||||
if isinstance(target_server[key], dict) and "id" in target_server[key] and wished_server[key]:
|
||||
# Setting all key to current value except ID
|
||||
key_dict = dict((x, target_server[key][x]) for x in target_server[key].keys() if x != "id")
|
||||
# Setting ID to the user specified ID
|
||||
key_dict["id"] = wished_server[key]
|
||||
patch_payload[key] = key_dict
|
||||
elif not isinstance(target_server[key], dict):
|
||||
patch_payload[key] = wished_server[key]
|
||||
|
||||
response = compute_api.patch(path="servers/%s" % target_server["id"],
|
||||
data=patch_payload)
|
||||
if not response.ok:
|
||||
msg = 'Error during server attributes patching: (%s) %s' % (response.status_code, response.json)
|
||||
compute_api.module.fail_json(msg=msg)
|
||||
|
||||
try:
|
||||
target_server = response.json["server"]
|
||||
except KeyError:
|
||||
compute_api.module.fail_json(msg="Error in getting the server information from: %s" % response.json)
|
||||
|
||||
wait_to_complete_state_transition(compute_api=compute_api, server=target_server)
|
||||
|
||||
return target_server
|
||||
|
||||
|
||||
def core(module):
|
||||
region = module.params["region"]
|
||||
wished_server = {
|
||||
"state": module.params["state"],
|
||||
"image": module.params["image"],
|
||||
"name": module.params["name"],
|
||||
"commercial_type": module.params["commercial_type"],
|
||||
"enable_ipv6": module.params["enable_ipv6"],
|
||||
"tags": module.params["tags"],
|
||||
"organization": module.params["organization"],
|
||||
"security_group": module.params["security_group"]
|
||||
}
|
||||
module.params['api_url'] = SCALEWAY_LOCATION[region]["api_endpoint"]
|
||||
|
||||
compute_api = Scaleway(module=module)
|
||||
|
||||
check_image_id(compute_api, wished_server["image"])
|
||||
|
||||
# IP parameters of the wished server depends on the configuration
|
||||
ip_payload = public_ip_payload(compute_api=compute_api, public_ip=module.params["public_ip"])
|
||||
wished_server.update(ip_payload)
|
||||
|
||||
changed, summary = state_strategy[wished_server["state"]](compute_api=compute_api, wished_server=wished_server)
|
||||
module.exit_json(changed=changed, msg=summary)
|
||||
|
||||
|
||||
def main():
|
||||
argument_spec = scaleway_argument_spec()
|
||||
argument_spec.update(dict(
|
||||
image=dict(required=True),
|
||||
name=dict(),
|
||||
region=dict(required=True, choices=SCALEWAY_LOCATION.keys()),
|
||||
commercial_type=dict(required=True),
|
||||
enable_ipv6=dict(default=False, type="bool"),
|
||||
public_ip=dict(default="absent"),
|
||||
state=dict(choices=state_strategy.keys(), default='present'),
|
||||
tags=dict(type="list", default=[]),
|
||||
organization=dict(required=True),
|
||||
wait=dict(type="bool", default=False),
|
||||
wait_timeout=dict(type="int", default=300),
|
||||
wait_sleep_time=dict(type="int", default=3),
|
||||
security_group=dict(),
|
||||
))
|
||||
module = AnsibleModule(
|
||||
argument_spec=argument_spec,
|
||||
supports_check_mode=True,
|
||||
)
|
||||
|
||||
core(module)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
125
plugins/modules/cloud/scaleway/scaleway_image_facts.py
Normal file
125
plugins/modules/cloud/scaleway/scaleway_image_facts.py
Normal file
|
@ -0,0 +1,125 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# (c) 2018, Yanis Guenane <yanis+ansible@guenane.org>
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
||||
'status': ['deprecated'],
|
||||
'supported_by': 'community'}
|
||||
|
||||
DOCUMENTATION = r'''
|
||||
---
|
||||
module: scaleway_image_facts
|
||||
deprecated:
|
||||
removed_in: '2.13'
|
||||
why: Deprecated in favour of C(_info) module.
|
||||
alternative: Use M(scaleway_image_info) instead.
|
||||
short_description: Gather facts about the Scaleway images available.
|
||||
description:
|
||||
- Gather facts about the Scaleway images available.
|
||||
author:
|
||||
- "Yanis Guenane (@Spredzy)"
|
||||
- "Remy Leone (@sieben)"
|
||||
extends_documentation_fragment:
|
||||
- community.general.scaleway
|
||||
|
||||
|
||||
options:
|
||||
|
||||
region:
|
||||
description:
|
||||
- Scaleway compute zone
|
||||
required: true
|
||||
choices:
|
||||
- ams1
|
||||
- EMEA-NL-EVS
|
||||
- par1
|
||||
- EMEA-FR-PAR1
|
||||
'''
|
||||
|
||||
EXAMPLES = r'''
|
||||
- name: Gather Scaleway images facts
|
||||
scaleway_image_facts:
|
||||
region: par1
|
||||
'''
|
||||
|
||||
RETURN = r'''
|
||||
---
|
||||
scaleway_image_facts:
|
||||
description: Response from Scaleway API
|
||||
returned: success
|
||||
type: complex
|
||||
sample:
|
||||
"scaleway_image_facts": [
|
||||
{
|
||||
"arch": "x86_64",
|
||||
"creation_date": "2018-07-17T16:18:49.276456+00:00",
|
||||
"default_bootscript": {
|
||||
"architecture": "x86_64",
|
||||
"bootcmdargs": "LINUX_COMMON scaleway boot=local nbd.max_part=16",
|
||||
"default": false,
|
||||
"dtb": "",
|
||||
"id": "15fbd2f7-a0f9-412b-8502-6a44da8d98b8",
|
||||
"initrd": "http://169.254.42.24/initrd/initrd-Linux-x86_64-v3.14.5.gz",
|
||||
"kernel": "http://169.254.42.24/kernel/x86_64-mainline-lts-4.9-4.9.93-rev1/vmlinuz-4.9.93",
|
||||
"organization": "11111111-1111-4111-8111-111111111111",
|
||||
"public": true,
|
||||
"title": "x86_64 mainline 4.9.93 rev1"
|
||||
},
|
||||
"extra_volumes": [],
|
||||
"from_server": null,
|
||||
"id": "00ae4a88-3252-4eda-9feb-5f6b56bf5ef0",
|
||||
"modification_date": "2018-07-17T16:42:06.319315+00:00",
|
||||
"name": "Debian Stretch",
|
||||
"organization": "51b656e3-4865-41e8-adbc-0c45bdd780db",
|
||||
"public": true,
|
||||
"root_volume": {
|
||||
"id": "da32dfbb-c5ff-476d-ae2d-c297dd09b7dd",
|
||||
"name": "snapshot-2a7229dc-d431-4dc5-b66e-95db08b773af-2018-07-17_16:18",
|
||||
"size": 25000000000,
|
||||
"volume_type": "l_ssd"
|
||||
},
|
||||
"state": "available"
|
||||
}
|
||||
]
|
||||
'''
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible_collections.community.general.plugins.module_utils.scaleway import (
|
||||
Scaleway, ScalewayException, scaleway_argument_spec, SCALEWAY_LOCATION)
|
||||
|
||||
|
||||
class ScalewayImageFacts(Scaleway):
|
||||
|
||||
def __init__(self, module):
|
||||
super(ScalewayImageFacts, self).__init__(module)
|
||||
self.name = 'images'
|
||||
|
||||
region = module.params["region"]
|
||||
self.module.params['api_url'] = SCALEWAY_LOCATION[region]["api_endpoint"]
|
||||
|
||||
|
||||
def main():
|
||||
argument_spec = scaleway_argument_spec()
|
||||
argument_spec.update(dict(
|
||||
region=dict(required=True, choices=SCALEWAY_LOCATION.keys()),
|
||||
))
|
||||
module = AnsibleModule(
|
||||
argument_spec=argument_spec,
|
||||
supports_check_mode=True,
|
||||
)
|
||||
|
||||
try:
|
||||
module.exit_json(
|
||||
ansible_facts={'scaleway_image_facts': ScalewayImageFacts(module).get_resources()}
|
||||
)
|
||||
except ScalewayException as exc:
|
||||
module.fail_json(msg=exc.message)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
125
plugins/modules/cloud/scaleway/scaleway_image_info.py
Normal file
125
plugins/modules/cloud/scaleway/scaleway_image_info.py
Normal file
|
@ -0,0 +1,125 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# (c) 2018, Yanis Guenane <yanis+ansible@guenane.org>
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
||||
'status': ['preview'],
|
||||
'supported_by': 'community'}
|
||||
|
||||
DOCUMENTATION = r'''
|
||||
---
|
||||
module: scaleway_image_info
|
||||
short_description: Gather information about the Scaleway images available.
|
||||
description:
|
||||
- Gather information about the Scaleway images available.
|
||||
author:
|
||||
- "Yanis Guenane (@Spredzy)"
|
||||
- "Remy Leone (@sieben)"
|
||||
extends_documentation_fragment:
|
||||
- community.general.scaleway
|
||||
|
||||
|
||||
options:
|
||||
|
||||
region:
|
||||
description:
|
||||
- Scaleway compute zone
|
||||
required: true
|
||||
choices:
|
||||
- ams1
|
||||
- EMEA-NL-EVS
|
||||
- par1
|
||||
- EMEA-FR-PAR1
|
||||
'''
|
||||
|
||||
EXAMPLES = r'''
|
||||
- name: Gather Scaleway images information
|
||||
scaleway_image_info:
|
||||
region: par1
|
||||
register: result
|
||||
|
||||
- debug:
|
||||
msg: "{{ result.scaleway_image_info }}"
|
||||
'''
|
||||
|
||||
RETURN = r'''
|
||||
---
|
||||
scaleway_image_info:
|
||||
description: Response from Scaleway API
|
||||
returned: success
|
||||
type: complex
|
||||
sample:
|
||||
"scaleway_image_info": [
|
||||
{
|
||||
"arch": "x86_64",
|
||||
"creation_date": "2018-07-17T16:18:49.276456+00:00",
|
||||
"default_bootscript": {
|
||||
"architecture": "x86_64",
|
||||
"bootcmdargs": "LINUX_COMMON scaleway boot=local nbd.max_part=16",
|
||||
"default": false,
|
||||
"dtb": "",
|
||||
"id": "15fbd2f7-a0f9-412b-8502-6a44da8d98b8",
|
||||
"initrd": "http://169.254.42.24/initrd/initrd-Linux-x86_64-v3.14.5.gz",
|
||||
"kernel": "http://169.254.42.24/kernel/x86_64-mainline-lts-4.9-4.9.93-rev1/vmlinuz-4.9.93",
|
||||
"organization": "11111111-1111-4111-8111-111111111111",
|
||||
"public": true,
|
||||
"title": "x86_64 mainline 4.9.93 rev1"
|
||||
},
|
||||
"extra_volumes": [],
|
||||
"from_server": null,
|
||||
"id": "00ae4a88-3252-4eda-9feb-5f6b56bf5ef0",
|
||||
"modification_date": "2018-07-17T16:42:06.319315+00:00",
|
||||
"name": "Debian Stretch",
|
||||
"organization": "51b656e3-4865-41e8-adbc-0c45bdd780db",
|
||||
"public": true,
|
||||
"root_volume": {
|
||||
"id": "da32dfbb-c5ff-476d-ae2d-c297dd09b7dd",
|
||||
"name": "snapshot-2a7229dc-d431-4dc5-b66e-95db08b773af-2018-07-17_16:18",
|
||||
"size": 25000000000,
|
||||
"volume_type": "l_ssd"
|
||||
},
|
||||
"state": "available"
|
||||
}
|
||||
]
|
||||
'''
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible_collections.community.general.plugins.module_utils.scaleway import (
|
||||
Scaleway, ScalewayException, scaleway_argument_spec, SCALEWAY_LOCATION)
|
||||
|
||||
|
||||
class ScalewayImageInfo(Scaleway):
|
||||
|
||||
def __init__(self, module):
|
||||
super(ScalewayImageInfo, self).__init__(module)
|
||||
self.name = 'images'
|
||||
|
||||
region = module.params["region"]
|
||||
self.module.params['api_url'] = SCALEWAY_LOCATION[region]["api_endpoint"]
|
||||
|
||||
|
||||
def main():
|
||||
argument_spec = scaleway_argument_spec()
|
||||
argument_spec.update(dict(
|
||||
region=dict(required=True, choices=SCALEWAY_LOCATION.keys()),
|
||||
))
|
||||
module = AnsibleModule(
|
||||
argument_spec=argument_spec,
|
||||
supports_check_mode=True,
|
||||
)
|
||||
|
||||
try:
|
||||
module.exit_json(
|
||||
scaleway_image_info=ScalewayImageInfo(module).get_resources()
|
||||
)
|
||||
except ScalewayException as exc:
|
||||
module.fail_json(msg=exc.message)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
258
plugins/modules/cloud/scaleway/scaleway_ip.py
Normal file
258
plugins/modules/cloud/scaleway/scaleway_ip.py
Normal file
|
@ -0,0 +1,258 @@
|
|||
#!/usr/bin/python
|
||||
#
|
||||
# Scaleway IP management module
|
||||
#
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
ANSIBLE_METADATA = {
|
||||
'metadata_version': '1.1',
|
||||
'status': ['preview'],
|
||||
'supported_by': 'community'
|
||||
}
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: scaleway_ip
|
||||
short_description: Scaleway IP management module
|
||||
author: Remy Leone (@sieben)
|
||||
description:
|
||||
- This module manages IP on Scaleway account
|
||||
U(https://developer.scaleway.com)
|
||||
extends_documentation_fragment:
|
||||
- community.general.scaleway
|
||||
|
||||
|
||||
options:
|
||||
state:
|
||||
description:
|
||||
- Indicate desired state of the IP.
|
||||
default: present
|
||||
choices:
|
||||
- present
|
||||
- absent
|
||||
|
||||
organization:
|
||||
description:
|
||||
- Scaleway organization identifier
|
||||
required: true
|
||||
|
||||
region:
|
||||
description:
|
||||
- Scaleway region to use (for example par1).
|
||||
required: true
|
||||
choices:
|
||||
- ams1
|
||||
- EMEA-NL-EVS
|
||||
- par1
|
||||
- EMEA-FR-PAR1
|
||||
|
||||
id:
|
||||
description:
|
||||
- id of the Scaleway IP (UUID)
|
||||
|
||||
server:
|
||||
description:
|
||||
- id of the server you want to attach an IP to.
|
||||
- To unattach an IP don't specify this option
|
||||
|
||||
reverse:
|
||||
description:
|
||||
- Reverse to assign to the IP
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
- name: Create an IP
|
||||
scaleway_ip:
|
||||
organization: '{{ scw_org }}'
|
||||
state: present
|
||||
region: par1
|
||||
register: ip_creation_task
|
||||
|
||||
- name: Make sure IP deleted
|
||||
scaleway_ip:
|
||||
id: '{{ ip_creation_task.scaleway_ip.id }}'
|
||||
state: absent
|
||||
region: par1
|
||||
|
||||
'''
|
||||
|
||||
RETURN = '''
|
||||
data:
|
||||
description: This is only present when C(state=present)
|
||||
returned: when C(state=present)
|
||||
type: dict
|
||||
sample: {
|
||||
"ips": [
|
||||
{
|
||||
"organization": "951df375-e094-4d26-97c1-ba548eeb9c42",
|
||||
"reverse": null,
|
||||
"id": "dd9e8df6-6775-4863-b517-e0b0ee3d7477",
|
||||
"server": {
|
||||
"id": "3f1568ca-b1a2-4e98-b6f7-31a0588157f1",
|
||||
"name": "ansible_tuto-1"
|
||||
},
|
||||
"address": "212.47.232.136"
|
||||
}
|
||||
]
|
||||
}
|
||||
'''
|
||||
|
||||
from ansible_collections.community.general.plugins.module_utils.scaleway import SCALEWAY_LOCATION, scaleway_argument_spec, Scaleway
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
|
||||
|
||||
def ip_attributes_should_be_changed(api, target_ip, wished_ip):
|
||||
patch_payload = {}
|
||||
|
||||
if target_ip["reverse"] != wished_ip["reverse"]:
|
||||
patch_payload["reverse"] = wished_ip["reverse"]
|
||||
|
||||
# IP is assigned to a server
|
||||
if target_ip["server"] is None and wished_ip["server"]:
|
||||
patch_payload["server"] = wished_ip["server"]
|
||||
|
||||
# IP is unassigned to a server
|
||||
try:
|
||||
if target_ip["server"]["id"] and wished_ip["server"] is None:
|
||||
patch_payload["server"] = wished_ip["server"]
|
||||
except (TypeError, KeyError):
|
||||
pass
|
||||
|
||||
# IP is migrated between 2 different servers
|
||||
try:
|
||||
if target_ip["server"]["id"] != wished_ip["server"]:
|
||||
patch_payload["server"] = wished_ip["server"]
|
||||
except (TypeError, KeyError):
|
||||
pass
|
||||
|
||||
return patch_payload
|
||||
|
||||
|
||||
def payload_from_wished_ip(wished_ip):
|
||||
return dict(
|
||||
(k, v)
|
||||
for k, v in wished_ip.items()
|
||||
if k != 'id' and v is not None
|
||||
)
|
||||
|
||||
|
||||
def present_strategy(api, wished_ip):
|
||||
changed = False
|
||||
|
||||
response = api.get('ips')
|
||||
if not response.ok:
|
||||
api.module.fail_json(msg='Error getting IPs [{0}: {1}]'.format(
|
||||
response.status_code, response.json['message']))
|
||||
|
||||
ips_list = response.json["ips"]
|
||||
ip_lookup = dict((ip["id"], ip)
|
||||
for ip in ips_list)
|
||||
|
||||
if wished_ip["id"] not in ip_lookup.keys():
|
||||
changed = True
|
||||
if api.module.check_mode:
|
||||
return changed, {"status": "An IP would be created."}
|
||||
|
||||
# Create IP
|
||||
creation_response = api.post('/ips',
|
||||
data=payload_from_wished_ip(wished_ip))
|
||||
|
||||
if not creation_response.ok:
|
||||
msg = "Error during ip creation: %s: '%s' (%s)" % (creation_response.info['msg'],
|
||||
creation_response.json['message'],
|
||||
creation_response.json)
|
||||
api.module.fail_json(msg=msg)
|
||||
return changed, creation_response.json["ip"]
|
||||
|
||||
target_ip = ip_lookup[wished_ip["id"]]
|
||||
patch_payload = ip_attributes_should_be_changed(api=api, target_ip=target_ip, wished_ip=wished_ip)
|
||||
|
||||
if not patch_payload:
|
||||
return changed, target_ip
|
||||
|
||||
changed = True
|
||||
if api.module.check_mode:
|
||||
return changed, {"status": "IP attributes would be changed."}
|
||||
|
||||
ip_patch_response = api.patch(path="ips/%s" % target_ip["id"],
|
||||
data=patch_payload)
|
||||
|
||||
if not ip_patch_response.ok:
|
||||
api.module.fail_json(msg='Error during IP attributes update: [{0}: {1}]'.format(
|
||||
ip_patch_response.status_code, ip_patch_response.json['message']))
|
||||
|
||||
return changed, ip_patch_response.json["ip"]
|
||||
|
||||
|
||||
def absent_strategy(api, wished_ip):
|
||||
response = api.get('ips')
|
||||
changed = False
|
||||
|
||||
status_code = response.status_code
|
||||
ips_json = response.json
|
||||
ips_list = ips_json["ips"]
|
||||
|
||||
if not response.ok:
|
||||
api.module.fail_json(msg='Error getting IPs [{0}: {1}]'.format(
|
||||
status_code, response.json['message']))
|
||||
|
||||
ip_lookup = dict((ip["id"], ip)
|
||||
for ip in ips_list)
|
||||
if wished_ip["id"] not in ip_lookup.keys():
|
||||
return changed, {}
|
||||
|
||||
changed = True
|
||||
if api.module.check_mode:
|
||||
return changed, {"status": "IP would be destroyed"}
|
||||
|
||||
response = api.delete('/ips/' + wished_ip["id"])
|
||||
if not response.ok:
|
||||
api.module.fail_json(msg='Error deleting IP [{0}: {1}]'.format(
|
||||
response.status_code, response.json))
|
||||
|
||||
return changed, response.json
|
||||
|
||||
|
||||
def core(module):
|
||||
wished_ip = {
|
||||
"organization": module.params['organization'],
|
||||
"reverse": module.params["reverse"],
|
||||
"id": module.params["id"],
|
||||
"server": module.params["server"]
|
||||
}
|
||||
|
||||
region = module.params["region"]
|
||||
module.params['api_url'] = SCALEWAY_LOCATION[region]["api_endpoint"]
|
||||
|
||||
api = Scaleway(module=module)
|
||||
if module.params["state"] == "absent":
|
||||
changed, summary = absent_strategy(api=api, wished_ip=wished_ip)
|
||||
else:
|
||||
changed, summary = present_strategy(api=api, wished_ip=wished_ip)
|
||||
module.exit_json(changed=changed, scaleway_ip=summary)
|
||||
|
||||
|
||||
def main():
|
||||
argument_spec = scaleway_argument_spec()
|
||||
argument_spec.update(dict(
|
||||
state=dict(default='present', choices=['absent', 'present']),
|
||||
organization=dict(required=True),
|
||||
server=dict(),
|
||||
reverse=dict(),
|
||||
region=dict(required=True, choices=SCALEWAY_LOCATION.keys()),
|
||||
id=dict()
|
||||
))
|
||||
module = AnsibleModule(
|
||||
argument_spec=argument_spec,
|
||||
supports_check_mode=True,
|
||||
)
|
||||
|
||||
core(module)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
107
plugins/modules/cloud/scaleway/scaleway_ip_facts.py
Normal file
107
plugins/modules/cloud/scaleway/scaleway_ip_facts.py
Normal file
|
@ -0,0 +1,107 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# (c) 2018, Yanis Guenane <yanis+ansible@guenane.org>
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
||||
'status': ['deprecated'],
|
||||
'supported_by': 'community'}
|
||||
|
||||
DOCUMENTATION = r'''
|
||||
---
|
||||
module: scaleway_ip_facts
|
||||
deprecated:
|
||||
removed_in: '2.13'
|
||||
why: Deprecated in favour of C(_info) module.
|
||||
alternative: Use M(scaleway_ip_info) instead.
|
||||
short_description: Gather facts about the Scaleway ips available.
|
||||
description:
|
||||
- Gather facts about the Scaleway ips available.
|
||||
author:
|
||||
- "Yanis Guenane (@Spredzy)"
|
||||
- "Remy Leone (@sieben)"
|
||||
extends_documentation_fragment:
|
||||
- community.general.scaleway
|
||||
|
||||
options:
|
||||
region:
|
||||
description:
|
||||
- Scaleway region to use (for example par1).
|
||||
required: true
|
||||
choices:
|
||||
- ams1
|
||||
- EMEA-NL-EVS
|
||||
- par1
|
||||
- EMEA-FR-PAR1
|
||||
'''
|
||||
|
||||
EXAMPLES = r'''
|
||||
- name: Gather Scaleway ips facts
|
||||
scaleway_ip_facts:
|
||||
region: par1
|
||||
'''
|
||||
|
||||
RETURN = r'''
|
||||
---
|
||||
scaleway_ip_facts:
|
||||
description: Response from Scaleway API
|
||||
returned: success
|
||||
type: complex
|
||||
sample:
|
||||
"scaleway_ip_facts": [
|
||||
{
|
||||
"address": "163.172.170.243",
|
||||
"id": "ea081794-a581-8899-8451-386ddaf0a451",
|
||||
"organization": "3f709602-5e6c-4619-b80c-e324324324af",
|
||||
"reverse": null,
|
||||
"server": {
|
||||
"id": "12f19bc7-109c-4517-954c-e6b3d0311363",
|
||||
"name": "scw-e0d158"
|
||||
}
|
||||
}
|
||||
]
|
||||
'''
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible_collections.community.general.plugins.module_utils.scaleway import (
|
||||
Scaleway,
|
||||
ScalewayException,
|
||||
scaleway_argument_spec,
|
||||
SCALEWAY_LOCATION,
|
||||
)
|
||||
|
||||
|
||||
class ScalewayIpFacts(Scaleway):
|
||||
|
||||
def __init__(self, module):
|
||||
super(ScalewayIpFacts, self).__init__(module)
|
||||
self.name = 'ips'
|
||||
|
||||
region = module.params["region"]
|
||||
self.module.params['api_url'] = SCALEWAY_LOCATION[region]["api_endpoint"]
|
||||
|
||||
|
||||
def main():
|
||||
argument_spec = scaleway_argument_spec()
|
||||
argument_spec.update(dict(
|
||||
region=dict(required=True, choices=SCALEWAY_LOCATION.keys()),
|
||||
))
|
||||
module = AnsibleModule(
|
||||
argument_spec=argument_spec,
|
||||
supports_check_mode=True,
|
||||
)
|
||||
|
||||
try:
|
||||
module.exit_json(
|
||||
ansible_facts={'scaleway_ip_facts': ScalewayIpFacts(module).get_resources()}
|
||||
)
|
||||
except ScalewayException as exc:
|
||||
module.fail_json(msg=exc.message)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
107
plugins/modules/cloud/scaleway/scaleway_ip_info.py
Normal file
107
plugins/modules/cloud/scaleway/scaleway_ip_info.py
Normal file
|
@ -0,0 +1,107 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# (c) 2018, Yanis Guenane <yanis+ansible@guenane.org>
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
||||
'status': ['preview'],
|
||||
'supported_by': 'community'}
|
||||
|
||||
DOCUMENTATION = r'''
|
||||
---
|
||||
module: scaleway_ip_info
|
||||
short_description: Gather information about the Scaleway ips available.
|
||||
description:
|
||||
- Gather information about the Scaleway ips available.
|
||||
author:
|
||||
- "Yanis Guenane (@Spredzy)"
|
||||
- "Remy Leone (@sieben)"
|
||||
extends_documentation_fragment:
|
||||
- community.general.scaleway
|
||||
|
||||
options:
|
||||
region:
|
||||
description:
|
||||
- Scaleway region to use (for example C(par1)).
|
||||
required: true
|
||||
choices:
|
||||
- ams1
|
||||
- EMEA-NL-EVS
|
||||
- par1
|
||||
- EMEA-FR-PAR1
|
||||
'''
|
||||
|
||||
EXAMPLES = r'''
|
||||
- name: Gather Scaleway ips information
|
||||
scaleway_ip_info:
|
||||
region: par1
|
||||
register: result
|
||||
|
||||
- debug:
|
||||
msg: "{{ result.scaleway_ip_info }}"
|
||||
'''
|
||||
|
||||
RETURN = r'''
|
||||
---
|
||||
scaleway_ip_info:
|
||||
description: Response from Scaleway API
|
||||
returned: success
|
||||
type: complex
|
||||
sample:
|
||||
"scaleway_ip_info": [
|
||||
{
|
||||
"address": "163.172.170.243",
|
||||
"id": "ea081794-a581-8899-8451-386ddaf0a451",
|
||||
"organization": "3f709602-5e6c-4619-b80c-e324324324af",
|
||||
"reverse": null,
|
||||
"server": {
|
||||
"id": "12f19bc7-109c-4517-954c-e6b3d0311363",
|
||||
"name": "scw-e0d158"
|
||||
}
|
||||
}
|
||||
]
|
||||
'''
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible_collections.community.general.plugins.module_utils.scaleway import (
|
||||
Scaleway,
|
||||
ScalewayException,
|
||||
scaleway_argument_spec,
|
||||
SCALEWAY_LOCATION,
|
||||
)
|
||||
|
||||
|
||||
class ScalewayIpInfo(Scaleway):
|
||||
|
||||
def __init__(self, module):
|
||||
super(ScalewayIpInfo, self).__init__(module)
|
||||
self.name = 'ips'
|
||||
|
||||
region = module.params["region"]
|
||||
self.module.params['api_url'] = SCALEWAY_LOCATION[region]["api_endpoint"]
|
||||
|
||||
|
||||
def main():
|
||||
argument_spec = scaleway_argument_spec()
|
||||
argument_spec.update(dict(
|
||||
region=dict(required=True, choices=SCALEWAY_LOCATION.keys()),
|
||||
))
|
||||
module = AnsibleModule(
|
||||
argument_spec=argument_spec,
|
||||
supports_check_mode=True,
|
||||
)
|
||||
|
||||
try:
|
||||
module.exit_json(
|
||||
scaleway_ip_info=ScalewayIpInfo(module).get_resources()
|
||||
)
|
||||
except ScalewayException as exc:
|
||||
module.fail_json(msg=exc.message)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
353
plugins/modules/cloud/scaleway/scaleway_lb.py
Normal file
353
plugins/modules/cloud/scaleway/scaleway_lb.py
Normal file
|
@ -0,0 +1,353 @@
|
|||
#!/usr/bin/python
|
||||
#
|
||||
# Scaleway Load-balancer management module
|
||||
#
|
||||
# Copyright (C) 2018 Online SAS.
|
||||
# https://www.scaleway.com
|
||||
#
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
ANSIBLE_METADATA = {
|
||||
'metadata_version': '1.1',
|
||||
'status': ['preview'],
|
||||
'supported_by': 'community'
|
||||
}
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: scaleway_lb
|
||||
short_description: Scaleway load-balancer management module
|
||||
author: Remy Leone (@sieben)
|
||||
description:
|
||||
- "This module manages load-balancers on Scaleway."
|
||||
extends_documentation_fragment:
|
||||
- community.general.scaleway
|
||||
|
||||
|
||||
options:
|
||||
|
||||
name:
|
||||
description:
|
||||
- Name of the load-balancer
|
||||
required: true
|
||||
|
||||
description:
|
||||
description:
|
||||
- Description of the load-balancer
|
||||
required: true
|
||||
|
||||
organization_id:
|
||||
description:
|
||||
- Organization identifier
|
||||
required: true
|
||||
|
||||
state:
|
||||
description:
|
||||
- Indicate desired state of the instance.
|
||||
default: present
|
||||
choices:
|
||||
- present
|
||||
- absent
|
||||
|
||||
region:
|
||||
description:
|
||||
- Scaleway zone
|
||||
required: true
|
||||
choices:
|
||||
- nl-ams
|
||||
- fr-par
|
||||
|
||||
tags:
|
||||
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: 'no'
|
||||
|
||||
wait_timeout:
|
||||
description:
|
||||
- Time to wait for the load-balancer to reach the expected state
|
||||
required: false
|
||||
default: 300
|
||||
|
||||
wait_sleep_time:
|
||||
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
|
||||
scaleway_lb:
|
||||
name: foobar
|
||||
state: present
|
||||
organization_id: 951df375-e094-4d26-97c1-ba548eeb9c42
|
||||
region: fr-par
|
||||
tags:
|
||||
- hello
|
||||
|
||||
- name: Delete a load-balancer
|
||||
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=state_strategy.keys(), default='present'),
|
||||
tags=dict(type="list", 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()
|
108
plugins/modules/cloud/scaleway/scaleway_organization_facts.py
Normal file
108
plugins/modules/cloud/scaleway/scaleway_organization_facts.py
Normal file
|
@ -0,0 +1,108 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# (c) 2018, Yanis Guenane <yanis+ansible@guenane.org>
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
||||
'status': ['deprecated'],
|
||||
'supported_by': 'community'}
|
||||
|
||||
DOCUMENTATION = r'''
|
||||
---
|
||||
module: scaleway_organization_facts
|
||||
deprecated:
|
||||
removed_in: '2.13'
|
||||
why: Deprecated in favour of C(_info) module.
|
||||
alternative: Use M(scaleway_organization_info) instead.
|
||||
short_description: Gather facts about the Scaleway organizations available.
|
||||
description:
|
||||
- Gather facts about the Scaleway organizations available.
|
||||
author:
|
||||
- "Yanis Guenane (@Spredzy)"
|
||||
- "Remy Leone (@sieben)"
|
||||
options:
|
||||
api_url:
|
||||
description:
|
||||
- Scaleway API URL
|
||||
default: 'https://account.scaleway.com'
|
||||
aliases: ['base_url']
|
||||
extends_documentation_fragment:
|
||||
- community.general.scaleway
|
||||
|
||||
'''
|
||||
|
||||
EXAMPLES = r'''
|
||||
- name: Gather Scaleway organizations facts
|
||||
scaleway_organization_facts:
|
||||
'''
|
||||
|
||||
RETURN = r'''
|
||||
---
|
||||
scaleway_organization_facts:
|
||||
description: Response from Scaleway API
|
||||
returned: success
|
||||
type: complex
|
||||
sample:
|
||||
"scaleway_organization_facts": [
|
||||
{
|
||||
"address_city_name": "Paris",
|
||||
"address_country_code": "FR",
|
||||
"address_line1": "42 Rue de l'univers",
|
||||
"address_line2": null,
|
||||
"address_postal_code": "75042",
|
||||
"address_subdivision_code": "FR-75",
|
||||
"creation_date": "2018-08-06T13:43:28.508575+00:00",
|
||||
"currency": "EUR",
|
||||
"customer_class": "individual",
|
||||
"id": "3f709602-5e6c-4619-b80c-e8432ferewtr",
|
||||
"locale": "fr_FR",
|
||||
"modification_date": "2018-08-06T14:56:41.401685+00:00",
|
||||
"name": "James Bond",
|
||||
"support_id": "694324",
|
||||
"support_level": "basic",
|
||||
"support_pin": "9324",
|
||||
"users": [],
|
||||
"vat_number": null,
|
||||
"warnings": []
|
||||
}
|
||||
]
|
||||
'''
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule, env_fallback
|
||||
from ansible_collections.community.general.plugins.module_utils.scaleway import (
|
||||
Scaleway, ScalewayException, scaleway_argument_spec
|
||||
)
|
||||
|
||||
|
||||
class ScalewayOrganizationFacts(Scaleway):
|
||||
|
||||
def __init__(self, module):
|
||||
super(ScalewayOrganizationFacts, self).__init__(module)
|
||||
self.name = 'organizations'
|
||||
|
||||
|
||||
def main():
|
||||
argument_spec = scaleway_argument_spec()
|
||||
argument_spec.update(dict(
|
||||
api_url=dict(fallback=(env_fallback, ['SCW_API_URL']), default='https://account.scaleway.com', aliases=['base_url']),
|
||||
))
|
||||
|
||||
module = AnsibleModule(
|
||||
argument_spec=argument_spec,
|
||||
supports_check_mode=True,
|
||||
)
|
||||
|
||||
try:
|
||||
module.exit_json(
|
||||
ansible_facts={'scaleway_organization_facts': ScalewayOrganizationFacts(module).get_resources()}
|
||||
)
|
||||
except ScalewayException as exc:
|
||||
module.fail_json(msg=exc.message)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
108
plugins/modules/cloud/scaleway/scaleway_organization_info.py
Normal file
108
plugins/modules/cloud/scaleway/scaleway_organization_info.py
Normal file
|
@ -0,0 +1,108 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# (c) 2018, Yanis Guenane <yanis+ansible@guenane.org>
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
||||
'status': ['preview'],
|
||||
'supported_by': 'community'}
|
||||
|
||||
DOCUMENTATION = r'''
|
||||
---
|
||||
module: scaleway_organization_info
|
||||
short_description: Gather information about the Scaleway organizations available.
|
||||
description:
|
||||
- Gather information about the Scaleway organizations available.
|
||||
author:
|
||||
- "Yanis Guenane (@Spredzy)"
|
||||
- "Remy Leone (@sieben)"
|
||||
options:
|
||||
api_url:
|
||||
description:
|
||||
- Scaleway API URL
|
||||
default: 'https://account.scaleway.com'
|
||||
aliases: ['base_url']
|
||||
extends_documentation_fragment:
|
||||
- community.general.scaleway
|
||||
|
||||
'''
|
||||
|
||||
EXAMPLES = r'''
|
||||
- name: Gather Scaleway organizations information
|
||||
scaleway_organization_info:
|
||||
register: result
|
||||
|
||||
- debug:
|
||||
msg: "{{ result.scaleway_organization_info }}"
|
||||
'''
|
||||
|
||||
RETURN = r'''
|
||||
---
|
||||
scaleway_organization_info:
|
||||
description: Response from Scaleway API
|
||||
returned: success
|
||||
type: complex
|
||||
sample:
|
||||
"scaleway_organization_info": [
|
||||
{
|
||||
"address_city_name": "Paris",
|
||||
"address_country_code": "FR",
|
||||
"address_line1": "42 Rue de l'univers",
|
||||
"address_line2": null,
|
||||
"address_postal_code": "75042",
|
||||
"address_subdivision_code": "FR-75",
|
||||
"creation_date": "2018-08-06T13:43:28.508575+00:00",
|
||||
"currency": "EUR",
|
||||
"customer_class": "individual",
|
||||
"id": "3f709602-5e6c-4619-b80c-e8432ferewtr",
|
||||
"locale": "fr_FR",
|
||||
"modification_date": "2018-08-06T14:56:41.401685+00:00",
|
||||
"name": "James Bond",
|
||||
"support_id": "694324",
|
||||
"support_level": "basic",
|
||||
"support_pin": "9324",
|
||||
"users": [],
|
||||
"vat_number": null,
|
||||
"warnings": []
|
||||
}
|
||||
]
|
||||
'''
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule, env_fallback
|
||||
from ansible_collections.community.general.plugins.module_utils.scaleway import (
|
||||
Scaleway, ScalewayException, scaleway_argument_spec
|
||||
)
|
||||
|
||||
|
||||
class ScalewayOrganizationInfo(Scaleway):
|
||||
|
||||
def __init__(self, module):
|
||||
super(ScalewayOrganizationInfo, self).__init__(module)
|
||||
self.name = 'organizations'
|
||||
|
||||
|
||||
def main():
|
||||
argument_spec = scaleway_argument_spec()
|
||||
argument_spec.update(dict(
|
||||
api_url=dict(fallback=(env_fallback, ['SCW_API_URL']), default='https://account.scaleway.com', aliases=['base_url']),
|
||||
))
|
||||
|
||||
module = AnsibleModule(
|
||||
argument_spec=argument_spec,
|
||||
supports_check_mode=True,
|
||||
)
|
||||
|
||||
try:
|
||||
module.exit_json(
|
||||
scaleway_organization_info=ScalewayOrganizationInfo(module).get_resources()
|
||||
)
|
||||
except ScalewayException as exc:
|
||||
module.fail_json(msg=exc.message)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
240
plugins/modules/cloud/scaleway/scaleway_security_group.py
Normal file
240
plugins/modules/cloud/scaleway/scaleway_security_group.py
Normal file
|
@ -0,0 +1,240 @@
|
|||
#!/usr/bin/python
|
||||
#
|
||||
# Scaleway Security Group management module
|
||||
#
|
||||
# Copyright (C) 2018 Antoine Barbare (antoinebarbare@gmail.com).
|
||||
#
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
ANSIBLE_METADATA = {
|
||||
'metadata_version': '1.1',
|
||||
'status': ['preview'],
|
||||
'supported_by': 'community'
|
||||
}
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: scaleway_security_group
|
||||
short_description: Scaleway Security Group management module
|
||||
author: Antoine Barbare (@abarbare)
|
||||
description:
|
||||
- This module manages Security Group on Scaleway account
|
||||
U(https://developer.scaleway.com).
|
||||
extends_documentation_fragment:
|
||||
- community.general.scaleway
|
||||
|
||||
|
||||
options:
|
||||
state:
|
||||
description:
|
||||
- Indicate desired state of the Security Group.
|
||||
type: str
|
||||
choices: [ absent, present ]
|
||||
default: present
|
||||
|
||||
organization:
|
||||
description:
|
||||
- Organization identifier.
|
||||
type: str
|
||||
required: true
|
||||
|
||||
region:
|
||||
description:
|
||||
- Scaleway region to use (for example C(par1)).
|
||||
type: str
|
||||
required: true
|
||||
choices:
|
||||
- ams1
|
||||
- EMEA-NL-EVS
|
||||
- par1
|
||||
- EMEA-FR-PAR1
|
||||
|
||||
name:
|
||||
description:
|
||||
- Name of the Security Group.
|
||||
type: str
|
||||
required: true
|
||||
|
||||
description:
|
||||
description:
|
||||
- Description of the Security Group.
|
||||
type: str
|
||||
|
||||
stateful:
|
||||
description:
|
||||
- Create a stateful security group which allows established connections in and out.
|
||||
type: bool
|
||||
required: true
|
||||
|
||||
inbound_default_policy:
|
||||
description:
|
||||
- Default policy for incoming traffic.
|
||||
type: str
|
||||
choices: [ accept, drop ]
|
||||
|
||||
outbound_default_policy:
|
||||
description:
|
||||
- Default policy for outcoming traffic.
|
||||
type: str
|
||||
choices: [ accept, drop ]
|
||||
|
||||
organization_default:
|
||||
description:
|
||||
- Create security group to be the default one.
|
||||
type: bool
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
- name: Create a Security Group
|
||||
scaleway_security_group:
|
||||
state: present
|
||||
region: par1
|
||||
name: security_group
|
||||
description: "my security group description"
|
||||
organization: "43a3b6c8-916f-477b-b7ec-ff1898f5fdd9"
|
||||
stateful: false
|
||||
inbound_default_policy: accept
|
||||
outbound_default_policy: accept
|
||||
organization_default: false
|
||||
register: security_group_creation_task
|
||||
'''
|
||||
|
||||
RETURN = '''
|
||||
data:
|
||||
description: This is only present when C(state=present)
|
||||
returned: when C(state=present)
|
||||
type: dict
|
||||
sample: {
|
||||
"scaleway_security_group": {
|
||||
"description": "my security group description",
|
||||
"enable_default_security": true,
|
||||
"id": "0168fb1f-cc46-4f69-b4be-c95d2a19bcae",
|
||||
"inbound_default_policy": "accept",
|
||||
"name": "security_group",
|
||||
"organization": "43a3b6c8-916f-477b-b7ec-ff1898f5fdd9",
|
||||
"organization_default": false,
|
||||
"outbound_default_policy": "accept",
|
||||
"servers": [],
|
||||
"stateful": false
|
||||
}
|
||||
}
|
||||
'''
|
||||
|
||||
from ansible_collections.community.general.plugins.module_utils.scaleway import SCALEWAY_LOCATION, scaleway_argument_spec, Scaleway
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
from uuid import uuid4
|
||||
|
||||
|
||||
def payload_from_security_group(security_group):
|
||||
return dict(
|
||||
(k, v)
|
||||
for k, v in security_group.items()
|
||||
if k != 'id' and v is not None
|
||||
)
|
||||
|
||||
|
||||
def present_strategy(api, security_group):
|
||||
ret = {'changed': False}
|
||||
|
||||
response = api.get('security_groups')
|
||||
if not response.ok:
|
||||
api.module.fail_json(msg='Error getting security groups "%s": "%s" (%s)' % (response.info['msg'], response.json['message'], response.json))
|
||||
|
||||
security_group_lookup = dict((sg['name'], sg)
|
||||
for sg in response.json['security_groups'])
|
||||
|
||||
if security_group['name'] not in security_group_lookup.keys():
|
||||
ret['changed'] = True
|
||||
if api.module.check_mode:
|
||||
# Help user when check mode is enabled by defining id key
|
||||
ret['scaleway_security_group'] = {'id': str(uuid4())}
|
||||
return ret
|
||||
|
||||
# Create Security Group
|
||||
response = api.post('/security_groups',
|
||||
data=payload_from_security_group(security_group))
|
||||
|
||||
if not response.ok:
|
||||
msg = 'Error during security group creation: "%s": "%s" (%s)' % (response.info['msg'], response.json['message'], response.json)
|
||||
api.module.fail_json(msg=msg)
|
||||
ret['scaleway_security_group'] = response.json['security_group']
|
||||
|
||||
else:
|
||||
ret['scaleway_security_group'] = security_group_lookup[security_group['name']]
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
def absent_strategy(api, security_group):
|
||||
response = api.get('security_groups')
|
||||
ret = {'changed': False}
|
||||
|
||||
if not response.ok:
|
||||
api.module.fail_json(msg='Error getting security groups "%s": "%s" (%s)' % (response.info['msg'], response.json['message'], response.json))
|
||||
|
||||
security_group_lookup = dict((sg['name'], sg)
|
||||
for sg in response.json['security_groups'])
|
||||
if security_group['name'] not in security_group_lookup.keys():
|
||||
return ret
|
||||
|
||||
ret['changed'] = True
|
||||
if api.module.check_mode:
|
||||
return ret
|
||||
|
||||
response = api.delete('/security_groups/' + security_group_lookup[security_group['name']]['id'])
|
||||
if not response.ok:
|
||||
api.module.fail_json(msg='Error deleting security group "%s": "%s" (%s)' % (response.info['msg'], response.json['message'], response.json))
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
def core(module):
|
||||
security_group = {
|
||||
'organization': module.params['organization'],
|
||||
'name': module.params['name'],
|
||||
'description': module.params['description'],
|
||||
'stateful': module.params['stateful'],
|
||||
'inbound_default_policy': module.params['inbound_default_policy'],
|
||||
'outbound_default_policy': module.params['outbound_default_policy'],
|
||||
'organization_default': module.params['organization_default'],
|
||||
}
|
||||
|
||||
region = module.params['region']
|
||||
module.params['api_url'] = SCALEWAY_LOCATION[region]['api_endpoint']
|
||||
|
||||
api = Scaleway(module=module)
|
||||
if module.params['state'] == 'present':
|
||||
summary = present_strategy(api=api, security_group=security_group)
|
||||
else:
|
||||
summary = absent_strategy(api=api, security_group=security_group)
|
||||
module.exit_json(**summary)
|
||||
|
||||
|
||||
def main():
|
||||
argument_spec = scaleway_argument_spec()
|
||||
argument_spec.update(dict(
|
||||
state=dict(type='str', default='present', choices=['absent', 'present']),
|
||||
organization=dict(type='str', required=True),
|
||||
name=dict(type='str', required=True),
|
||||
description=dict(type='str'),
|
||||
region=dict(type='str', required=True, choices=SCALEWAY_LOCATION.keys()),
|
||||
stateful=dict(type='bool', required=True),
|
||||
inbound_default_policy=dict(type='str', choices=['accept', 'drop']),
|
||||
outbound_default_policy=dict(type='str', choices=['accept', 'drop']),
|
||||
organization_default=dict(type='bool'),
|
||||
))
|
||||
module = AnsibleModule(
|
||||
argument_spec=argument_spec,
|
||||
supports_check_mode=True,
|
||||
required_if=[['stateful', True, ['inbound_default_policy', 'outbound_default_policy']]]
|
||||
)
|
||||
|
||||
core(module)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
111
plugins/modules/cloud/scaleway/scaleway_security_group_facts.py
Normal file
111
plugins/modules/cloud/scaleway/scaleway_security_group_facts.py
Normal file
|
@ -0,0 +1,111 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# (c) 2018, Yanis Guenane <yanis+ansible@guenane.org>
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
||||
'status': ['deprecated'],
|
||||
'supported_by': 'community'}
|
||||
|
||||
DOCUMENTATION = r'''
|
||||
---
|
||||
module: scaleway_security_group_facts
|
||||
deprecated:
|
||||
removed_in: '2.13'
|
||||
why: Deprecated in favour of C(_info) module.
|
||||
alternative: Use M(scaleway_security_group_info) instead.
|
||||
short_description: Gather facts about the Scaleway security groups available.
|
||||
description:
|
||||
- Gather facts about the Scaleway security groups available.
|
||||
author:
|
||||
- "Yanis Guenane (@Spredzy)"
|
||||
- "Remy Leone (@sieben)"
|
||||
options:
|
||||
region:
|
||||
description:
|
||||
- Scaleway region to use (for example par1).
|
||||
required: true
|
||||
choices:
|
||||
- ams1
|
||||
- EMEA-NL-EVS
|
||||
- par1
|
||||
- EMEA-FR-PAR1
|
||||
extends_documentation_fragment:
|
||||
- community.general.scaleway
|
||||
|
||||
'''
|
||||
|
||||
EXAMPLES = r'''
|
||||
- name: Gather Scaleway security groups facts
|
||||
scaleway_security_group_facts:
|
||||
region: par1
|
||||
'''
|
||||
|
||||
RETURN = r'''
|
||||
---
|
||||
scaleway_security_group_facts:
|
||||
description: Response from Scaleway API
|
||||
returned: success
|
||||
type: complex
|
||||
sample:
|
||||
"scaleway_security_group_facts": [
|
||||
{
|
||||
"description": "test-ams",
|
||||
"enable_default_security": true,
|
||||
"id": "7fcde327-8bed-43a6-95c4-6dfbc56d8b51",
|
||||
"name": "test-ams",
|
||||
"organization": "3f709602-5e6c-4619-b80c-e841c89734af",
|
||||
"organization_default": false,
|
||||
"servers": [
|
||||
{
|
||||
"id": "12f19bc7-108c-4517-954c-e6b3d0311363",
|
||||
"name": "scw-e0d158"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
'''
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible_collections.community.general.plugins.module_utils.scaleway import (
|
||||
Scaleway,
|
||||
ScalewayException,
|
||||
scaleway_argument_spec,
|
||||
SCALEWAY_LOCATION,
|
||||
)
|
||||
|
||||
|
||||
class ScalewaySecurityGroupFacts(Scaleway):
|
||||
|
||||
def __init__(self, module):
|
||||
super(ScalewaySecurityGroupFacts, self).__init__(module)
|
||||
self.name = 'security_groups'
|
||||
|
||||
region = module.params["region"]
|
||||
self.module.params['api_url'] = SCALEWAY_LOCATION[region]["api_endpoint"]
|
||||
|
||||
|
||||
def main():
|
||||
argument_spec = scaleway_argument_spec()
|
||||
argument_spec.update(dict(
|
||||
region=dict(required=True, choices=SCALEWAY_LOCATION.keys()),
|
||||
))
|
||||
module = AnsibleModule(
|
||||
argument_spec=argument_spec,
|
||||
supports_check_mode=True,
|
||||
)
|
||||
|
||||
try:
|
||||
module.exit_json(
|
||||
ansible_facts={'scaleway_security_group_facts': ScalewaySecurityGroupFacts(module).get_resources()}
|
||||
)
|
||||
except ScalewayException as exc:
|
||||
module.fail_json(msg=exc.message)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
111
plugins/modules/cloud/scaleway/scaleway_security_group_info.py
Normal file
111
plugins/modules/cloud/scaleway/scaleway_security_group_info.py
Normal file
|
@ -0,0 +1,111 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# (c) 2018, Yanis Guenane <yanis+ansible@guenane.org>
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
||||
'status': ['preview'],
|
||||
'supported_by': 'community'}
|
||||
|
||||
DOCUMENTATION = r'''
|
||||
---
|
||||
module: scaleway_security_group_info
|
||||
short_description: Gather information about the Scaleway security groups available.
|
||||
description:
|
||||
- Gather information about the Scaleway security groups available.
|
||||
author:
|
||||
- "Yanis Guenane (@Spredzy)"
|
||||
- "Remy Leone (@sieben)"
|
||||
options:
|
||||
region:
|
||||
description:
|
||||
- Scaleway region to use (for example C(par1)).
|
||||
required: true
|
||||
choices:
|
||||
- ams1
|
||||
- EMEA-NL-EVS
|
||||
- par1
|
||||
- EMEA-FR-PAR1
|
||||
extends_documentation_fragment:
|
||||
- community.general.scaleway
|
||||
|
||||
'''
|
||||
|
||||
EXAMPLES = r'''
|
||||
- name: Gather Scaleway security groups information
|
||||
scaleway_security_group_info:
|
||||
region: par1
|
||||
register: result
|
||||
|
||||
- debug:
|
||||
msg: "{{ result.scaleway_security_group_info }}"
|
||||
'''
|
||||
|
||||
RETURN = r'''
|
||||
---
|
||||
scaleway_security_group_info:
|
||||
description: Response from Scaleway API
|
||||
returned: success
|
||||
type: complex
|
||||
sample:
|
||||
"scaleway_security_group_info": [
|
||||
{
|
||||
"description": "test-ams",
|
||||
"enable_default_security": true,
|
||||
"id": "7fcde327-8bed-43a6-95c4-6dfbc56d8b51",
|
||||
"name": "test-ams",
|
||||
"organization": "3f709602-5e6c-4619-b80c-e841c89734af",
|
||||
"organization_default": false,
|
||||
"servers": [
|
||||
{
|
||||
"id": "12f19bc7-108c-4517-954c-e6b3d0311363",
|
||||
"name": "scw-e0d158"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
'''
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible_collections.community.general.plugins.module_utils.scaleway import (
|
||||
Scaleway,
|
||||
ScalewayException,
|
||||
scaleway_argument_spec,
|
||||
SCALEWAY_LOCATION,
|
||||
)
|
||||
|
||||
|
||||
class ScalewaySecurityGroupInfo(Scaleway):
|
||||
|
||||
def __init__(self, module):
|
||||
super(ScalewaySecurityGroupInfo, self).__init__(module)
|
||||
self.name = 'security_groups'
|
||||
|
||||
region = module.params["region"]
|
||||
self.module.params['api_url'] = SCALEWAY_LOCATION[region]["api_endpoint"]
|
||||
|
||||
|
||||
def main():
|
||||
argument_spec = scaleway_argument_spec()
|
||||
argument_spec.update(dict(
|
||||
region=dict(required=True, choices=SCALEWAY_LOCATION.keys()),
|
||||
))
|
||||
module = AnsibleModule(
|
||||
argument_spec=argument_spec,
|
||||
supports_check_mode=True,
|
||||
)
|
||||
|
||||
try:
|
||||
module.exit_json(
|
||||
scaleway_security_group_info=ScalewaySecurityGroupInfo(module).get_resources()
|
||||
)
|
||||
except ScalewayException as exc:
|
||||
module.fail_json(msg=exc.message)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
258
plugins/modules/cloud/scaleway/scaleway_security_group_rule.py
Normal file
258
plugins/modules/cloud/scaleway/scaleway_security_group_rule.py
Normal file
|
@ -0,0 +1,258 @@
|
|||
#!/usr/bin/python
|
||||
#
|
||||
# Scaleway Security Group Rule management module
|
||||
#
|
||||
# Copyright (C) 2018 Antoine Barbare (antoinebarbare@gmail.com).
|
||||
#
|
||||
# GNU General Public License v3.0+ (see COPYING or
|
||||
# https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
ANSIBLE_METADATA = {
|
||||
'metadata_version': '1.1',
|
||||
'status': ['preview'],
|
||||
'supported_by': 'community'
|
||||
}
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: scaleway_security_group_rule
|
||||
short_description: Scaleway Security Group Rule management module
|
||||
author: Antoine Barbare (@abarbare)
|
||||
description:
|
||||
- This module manages Security Group Rule on Scaleway account
|
||||
U(https://developer.scaleway.com)
|
||||
extends_documentation_fragment:
|
||||
- community.general.scaleway
|
||||
|
||||
|
||||
options:
|
||||
state:
|
||||
description:
|
||||
- Indicate desired state of the Security Group Rule.
|
||||
default: present
|
||||
choices:
|
||||
- present
|
||||
- absent
|
||||
|
||||
region:
|
||||
description:
|
||||
- Scaleway region to use (for example C(par1)).
|
||||
required: true
|
||||
choices:
|
||||
- ams1
|
||||
- EMEA-NL-EVS
|
||||
- par1
|
||||
- EMEA-FR-PAR1
|
||||
|
||||
protocol:
|
||||
description:
|
||||
- Network protocol to use
|
||||
choices:
|
||||
- TCP
|
||||
- UDP
|
||||
- ICMP
|
||||
required: true
|
||||
|
||||
port:
|
||||
description:
|
||||
- Port related to the rule, null value for all the ports
|
||||
required: true
|
||||
type: int
|
||||
|
||||
ip_range:
|
||||
description:
|
||||
- IPV4 CIDR notation to apply to the rule
|
||||
default: 0.0.0.0/0
|
||||
|
||||
direction:
|
||||
description:
|
||||
- Rule direction
|
||||
choices:
|
||||
- inbound
|
||||
- outbound
|
||||
required: true
|
||||
|
||||
action:
|
||||
description:
|
||||
- Rule action
|
||||
choices:
|
||||
- accept
|
||||
- drop
|
||||
required: true
|
||||
|
||||
security_group:
|
||||
description:
|
||||
- Security Group unique identifier
|
||||
required: true
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
- name: Create a Security Group Rule
|
||||
scaleway_security_group_rule:
|
||||
state: present
|
||||
region: par1
|
||||
protocol: TCP
|
||||
port: 80
|
||||
ip_range: 0.0.0.0/0
|
||||
direction: inbound
|
||||
action: accept
|
||||
security_group: b57210ee-1281-4820-a6db-329f78596ecb
|
||||
register: security_group_rule_creation_task
|
||||
'''
|
||||
|
||||
RETURN = '''
|
||||
data:
|
||||
description: This is only present when C(state=present)
|
||||
returned: when C(state=present)
|
||||
type: dict
|
||||
sample: {
|
||||
"scaleway_security_group_rule": {
|
||||
"direction": "inbound",
|
||||
"protocol": "TCP",
|
||||
"ip_range": "0.0.0.0/0",
|
||||
"dest_port_from": 80,
|
||||
"action": "accept",
|
||||
"position": 2,
|
||||
"dest_port_to": null,
|
||||
"editable": null,
|
||||
"id": "10cb0b9a-80f6-4830-abd7-a31cd828b5e9"
|
||||
}
|
||||
}
|
||||
'''
|
||||
|
||||
from ansible_collections.community.general.plugins.module_utils.scaleway import SCALEWAY_LOCATION, scaleway_argument_spec, Scaleway, payload_from_object
|
||||
from ansible_collections.ansible.netcommon.plugins.module_utils.compat.ipaddress import ip_network
|
||||
from ansible.module_utils._text import to_text
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
|
||||
|
||||
def get_sgr_from_api(security_group_rules, security_group_rule):
|
||||
""" Check if a security_group_rule specs are present in security_group_rules
|
||||
Return None if no rules match the specs
|
||||
Return the rule if found
|
||||
"""
|
||||
for sgr in security_group_rules:
|
||||
if (sgr['ip_range'] == security_group_rule['ip_range'] and sgr['dest_port_from'] == security_group_rule['dest_port_from'] and
|
||||
sgr['direction'] == security_group_rule['direction'] and sgr['action'] == security_group_rule['action'] and
|
||||
sgr['protocol'] == security_group_rule['protocol']):
|
||||
return sgr
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def present_strategy(api, security_group_id, security_group_rule):
|
||||
ret = {'changed': False}
|
||||
|
||||
response = api.get('security_groups/%s/rules' % security_group_id)
|
||||
if not response.ok:
|
||||
api.module.fail_json(
|
||||
msg='Error getting security group rules "%s": "%s" (%s)' %
|
||||
(response.info['msg'], response.json['message'], response.json))
|
||||
|
||||
existing_rule = get_sgr_from_api(
|
||||
response.json['rules'], security_group_rule)
|
||||
|
||||
if not existing_rule:
|
||||
ret['changed'] = True
|
||||
if api.module.check_mode:
|
||||
return ret
|
||||
|
||||
# Create Security Group Rule
|
||||
response = api.post('/security_groups/%s/rules' % security_group_id,
|
||||
data=payload_from_object(security_group_rule))
|
||||
|
||||
if not response.ok:
|
||||
api.module.fail_json(
|
||||
msg='Error during security group rule creation: "%s": "%s" (%s)' %
|
||||
(response.info['msg'], response.json['message'], response.json))
|
||||
ret['scaleway_security_group_rule'] = response.json['rule']
|
||||
|
||||
else:
|
||||
ret['scaleway_security_group_rule'] = existing_rule
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
def absent_strategy(api, security_group_id, security_group_rule):
|
||||
ret = {'changed': False}
|
||||
|
||||
response = api.get('security_groups/%s/rules' % security_group_id)
|
||||
if not response.ok:
|
||||
api.module.fail_json(
|
||||
msg='Error getting security group rules "%s": "%s" (%s)' %
|
||||
(response.info['msg'], response.json['message'], response.json))
|
||||
|
||||
existing_rule = get_sgr_from_api(
|
||||
response.json['rules'], security_group_rule)
|
||||
|
||||
if not existing_rule:
|
||||
return ret
|
||||
|
||||
ret['changed'] = True
|
||||
if api.module.check_mode:
|
||||
return ret
|
||||
|
||||
response = api.delete(
|
||||
'/security_groups/%s/rules/%s' %
|
||||
(security_group_id, existing_rule['id']))
|
||||
if not response.ok:
|
||||
api.module.fail_json(
|
||||
msg='Error deleting security group rule "%s": "%s" (%s)' %
|
||||
(response.info['msg'], response.json['message'], response.json))
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
def core(module):
|
||||
api = Scaleway(module=module)
|
||||
|
||||
security_group_rule = {
|
||||
'protocol': module.params['protocol'],
|
||||
'dest_port_from': module.params['port'],
|
||||
'ip_range': module.params['ip_range'],
|
||||
'direction': module.params['direction'],
|
||||
'action': module.params['action'],
|
||||
}
|
||||
|
||||
region = module.params['region']
|
||||
module.params['api_url'] = SCALEWAY_LOCATION[region]['api_endpoint']
|
||||
|
||||
if module.params['state'] == 'present':
|
||||
summary = present_strategy(
|
||||
api=api,
|
||||
security_group_id=module.params['security_group'],
|
||||
security_group_rule=security_group_rule)
|
||||
else:
|
||||
summary = absent_strategy(
|
||||
api=api,
|
||||
security_group_id=module.params['security_group'],
|
||||
security_group_rule=security_group_rule)
|
||||
module.exit_json(**summary)
|
||||
|
||||
|
||||
def main():
|
||||
argument_spec = scaleway_argument_spec()
|
||||
argument_spec.update(
|
||||
state=dict(type='str', default='present', choices=['absent', 'present']),
|
||||
region=dict(type='str', required=True, choices=SCALEWAY_LOCATION.keys()),
|
||||
protocol=dict(type='str', required=True, choices=['TCP', 'UDP', 'ICMP']),
|
||||
port=dict(type='int', required=True),
|
||||
ip_range=dict(type='str', default='0.0.0.0/0'),
|
||||
direction=dict(type='str', required=True, choices=['inbound', 'outbound']),
|
||||
action=dict(type='str', required=True, choices=['accept', 'drop']),
|
||||
security_group=dict(type='str', required=True),
|
||||
)
|
||||
module = AnsibleModule(
|
||||
argument_spec=argument_spec,
|
||||
supports_check_mode=True,
|
||||
)
|
||||
|
||||
core(module)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
194
plugins/modules/cloud/scaleway/scaleway_server_facts.py
Normal file
194
plugins/modules/cloud/scaleway/scaleway_server_facts.py
Normal file
|
@ -0,0 +1,194 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# (c) 2018, Yanis Guenane <yanis+ansible@guenane.org>
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
||||
'status': ['deprecated'],
|
||||
'supported_by': 'community'}
|
||||
|
||||
DOCUMENTATION = r'''
|
||||
---
|
||||
module: scaleway_server_facts
|
||||
deprecated:
|
||||
removed_in: '2.13'
|
||||
why: Deprecated in favour of C(_info) module.
|
||||
alternative: Use M(scaleway_server_info) instead.
|
||||
short_description: Gather facts about the Scaleway servers available.
|
||||
description:
|
||||
- Gather facts about the Scaleway servers available.
|
||||
author:
|
||||
- "Yanis Guenane (@Spredzy)"
|
||||
- "Remy Leone (@sieben)"
|
||||
extends_documentation_fragment:
|
||||
- community.general.scaleway
|
||||
|
||||
options:
|
||||
region:
|
||||
description:
|
||||
- Scaleway region to use (for example par1).
|
||||
required: true
|
||||
choices:
|
||||
- ams1
|
||||
- EMEA-NL-EVS
|
||||
- par1
|
||||
- EMEA-FR-PAR1
|
||||
'''
|
||||
|
||||
EXAMPLES = r'''
|
||||
- name: Gather Scaleway servers facts
|
||||
scaleway_server_facts:
|
||||
region: par1
|
||||
'''
|
||||
|
||||
RETURN = r'''
|
||||
---
|
||||
scaleway_server_facts:
|
||||
description: Response from Scaleway API
|
||||
returned: success
|
||||
type: complex
|
||||
sample:
|
||||
"scaleway_server_facts": [
|
||||
{
|
||||
"arch": "x86_64",
|
||||
"boot_type": "local",
|
||||
"bootscript": {
|
||||
"architecture": "x86_64",
|
||||
"bootcmdargs": "LINUX_COMMON scaleway boot=local nbd.max_part=16",
|
||||
"default": true,
|
||||
"dtb": "",
|
||||
"id": "b1e68c26-a19c-4eac-9222-498b22bd7ad9",
|
||||
"initrd": "http://169.254.42.24/initrd/initrd-Linux-x86_64-v3.14.5.gz",
|
||||
"kernel": "http://169.254.42.24/kernel/x86_64-mainline-lts-4.4-4.4.127-rev1/vmlinuz-4.4.127",
|
||||
"organization": "11111111-1111-4111-8111-111111111111",
|
||||
"public": true,
|
||||
"title": "x86_64 mainline 4.4.127 rev1"
|
||||
},
|
||||
"commercial_type": "START1-XS",
|
||||
"creation_date": "2018-08-14T21:36:56.271545+00:00",
|
||||
"dynamic_ip_required": false,
|
||||
"enable_ipv6": false,
|
||||
"extra_networks": [],
|
||||
"hostname": "scw-e0d256",
|
||||
"id": "12f19bc7-108c-4517-954c-e6b3d0311363",
|
||||
"image": {
|
||||
"arch": "x86_64",
|
||||
"creation_date": "2018-04-26T12:42:21.619844+00:00",
|
||||
"default_bootscript": {
|
||||
"architecture": "x86_64",
|
||||
"bootcmdargs": "LINUX_COMMON scaleway boot=local nbd.max_part=16",
|
||||
"default": true,
|
||||
"dtb": "",
|
||||
"id": "b1e68c26-a19c-4eac-9222-498b22bd7ad9",
|
||||
"initrd": "http://169.254.42.24/initrd/initrd-Linux-x86_64-v3.14.5.gz",
|
||||
"kernel": "http://169.254.42.24/kernel/x86_64-mainline-lts-4.4-4.4.127-rev1/vmlinuz-4.4.127",
|
||||
"organization": "11111111-1111-4111-8111-111111111111",
|
||||
"public": true,
|
||||
"title": "x86_64 mainline 4.4.127 rev1"
|
||||
},
|
||||
"extra_volumes": [],
|
||||
"from_server": null,
|
||||
"id": "67375eb1-f14d-4f02-bb42-6119cecbde51",
|
||||
"modification_date": "2018-04-26T12:49:07.573004+00:00",
|
||||
"name": "Ubuntu Xenial",
|
||||
"organization": "51b656e3-4865-41e8-adbc-0c45bdd780db",
|
||||
"public": true,
|
||||
"root_volume": {
|
||||
"id": "020b8d61-3867-4a0e-84a4-445c5393e05d",
|
||||
"name": "snapshot-87fc282d-f252-4262-adad-86979d9074cf-2018-04-26_12:42",
|
||||
"size": 25000000000,
|
||||
"volume_type": "l_ssd"
|
||||
},
|
||||
"state": "available"
|
||||
},
|
||||
"ipv6": null,
|
||||
"location": {
|
||||
"cluster_id": "5",
|
||||
"hypervisor_id": "412",
|
||||
"node_id": "2",
|
||||
"platform_id": "13",
|
||||
"zone_id": "par1"
|
||||
},
|
||||
"maintenances": [],
|
||||
"modification_date": "2018-08-14T21:37:28.630882+00:00",
|
||||
"name": "scw-e0d256",
|
||||
"organization": "3f709602-5e6c-4619-b80c-e841c89734af",
|
||||
"private_ip": "10.14.222.131",
|
||||
"protected": false,
|
||||
"public_ip": {
|
||||
"address": "163.172.170.197",
|
||||
"dynamic": false,
|
||||
"id": "ea081794-a581-4495-8451-386ddaf0a451"
|
||||
},
|
||||
"security_group": {
|
||||
"id": "a37379d2-d8b0-4668-9cfb-1233fc436f7e",
|
||||
"name": "Default security group"
|
||||
},
|
||||
"state": "running",
|
||||
"state_detail": "booted",
|
||||
"tags": [],
|
||||
"volumes": {
|
||||
"0": {
|
||||
"creation_date": "2018-08-14T21:36:56.271545+00:00",
|
||||
"export_uri": "device://dev/vda",
|
||||
"id": "68386fae-4f55-4fbf-aabb-953036a85872",
|
||||
"modification_date": "2018-08-14T21:36:56.271545+00:00",
|
||||
"name": "snapshot-87fc282d-f252-4262-adad-86979d9074cf-2018-04-26_12:42",
|
||||
"organization": "3f709602-5e6c-4619-b80c-e841c89734af",
|
||||
"server": {
|
||||
"id": "12f19bc7-108c-4517-954c-e6b3d0311363",
|
||||
"name": "scw-e0d256"
|
||||
},
|
||||
"size": 25000000000,
|
||||
"state": "available",
|
||||
"volume_type": "l_ssd"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
'''
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible_collections.community.general.plugins.module_utils.scaleway import (
|
||||
Scaleway,
|
||||
ScalewayException,
|
||||
scaleway_argument_spec,
|
||||
SCALEWAY_LOCATION,
|
||||
)
|
||||
|
||||
|
||||
class ScalewayServerFacts(Scaleway):
|
||||
|
||||
def __init__(self, module):
|
||||
super(ScalewayServerFacts, self).__init__(module)
|
||||
self.name = 'servers'
|
||||
|
||||
region = module.params["region"]
|
||||
self.module.params['api_url'] = SCALEWAY_LOCATION[region]["api_endpoint"]
|
||||
|
||||
|
||||
def main():
|
||||
argument_spec = scaleway_argument_spec()
|
||||
argument_spec.update(dict(
|
||||
region=dict(required=True, choices=SCALEWAY_LOCATION.keys()),
|
||||
))
|
||||
|
||||
module = AnsibleModule(
|
||||
argument_spec=argument_spec,
|
||||
supports_check_mode=True,
|
||||
)
|
||||
|
||||
try:
|
||||
module.exit_json(
|
||||
ansible_facts={'scaleway_server_facts': ScalewayServerFacts(module).get_resources()}
|
||||
)
|
||||
except ScalewayException as exc:
|
||||
module.fail_json(msg=exc.message)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
194
plugins/modules/cloud/scaleway/scaleway_server_info.py
Normal file
194
plugins/modules/cloud/scaleway/scaleway_server_info.py
Normal file
|
@ -0,0 +1,194 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# (c) 2018, Yanis Guenane <yanis+ansible@guenane.org>
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
||||
'status': ['preview'],
|
||||
'supported_by': 'community'}
|
||||
|
||||
DOCUMENTATION = r'''
|
||||
---
|
||||
module: scaleway_server_info
|
||||
short_description: Gather information about the Scaleway servers available.
|
||||
description:
|
||||
- Gather information about the Scaleway servers available.
|
||||
author:
|
||||
- "Yanis Guenane (@Spredzy)"
|
||||
- "Remy Leone (@sieben)"
|
||||
extends_documentation_fragment:
|
||||
- community.general.scaleway
|
||||
|
||||
options:
|
||||
region:
|
||||
description:
|
||||
- Scaleway region to use (for example C(par1)).
|
||||
required: true
|
||||
choices:
|
||||
- ams1
|
||||
- EMEA-NL-EVS
|
||||
- par1
|
||||
- EMEA-FR-PAR1
|
||||
'''
|
||||
|
||||
EXAMPLES = r'''
|
||||
- name: Gather Scaleway servers information
|
||||
scaleway_server_info:
|
||||
region: par1
|
||||
register: result
|
||||
|
||||
- debug:
|
||||
msg: "{{ result.scaleway_server_info }}"
|
||||
'''
|
||||
|
||||
RETURN = r'''
|
||||
---
|
||||
scaleway_server_info:
|
||||
description: Response from Scaleway API
|
||||
returned: success
|
||||
type: complex
|
||||
sample:
|
||||
"scaleway_server_info": [
|
||||
{
|
||||
"arch": "x86_64",
|
||||
"boot_type": "local",
|
||||
"bootscript": {
|
||||
"architecture": "x86_64",
|
||||
"bootcmdargs": "LINUX_COMMON scaleway boot=local nbd.max_part=16",
|
||||
"default": true,
|
||||
"dtb": "",
|
||||
"id": "b1e68c26-a19c-4eac-9222-498b22bd7ad9",
|
||||
"initrd": "http://169.254.42.24/initrd/initrd-Linux-x86_64-v3.14.5.gz",
|
||||
"kernel": "http://169.254.42.24/kernel/x86_64-mainline-lts-4.4-4.4.127-rev1/vmlinuz-4.4.127",
|
||||
"organization": "11111111-1111-4111-8111-111111111111",
|
||||
"public": true,
|
||||
"title": "x86_64 mainline 4.4.127 rev1"
|
||||
},
|
||||
"commercial_type": "START1-XS",
|
||||
"creation_date": "2018-08-14T21:36:56.271545+00:00",
|
||||
"dynamic_ip_required": false,
|
||||
"enable_ipv6": false,
|
||||
"extra_networks": [],
|
||||
"hostname": "scw-e0d256",
|
||||
"id": "12f19bc7-108c-4517-954c-e6b3d0311363",
|
||||
"image": {
|
||||
"arch": "x86_64",
|
||||
"creation_date": "2018-04-26T12:42:21.619844+00:00",
|
||||
"default_bootscript": {
|
||||
"architecture": "x86_64",
|
||||
"bootcmdargs": "LINUX_COMMON scaleway boot=local nbd.max_part=16",
|
||||
"default": true,
|
||||
"dtb": "",
|
||||
"id": "b1e68c26-a19c-4eac-9222-498b22bd7ad9",
|
||||
"initrd": "http://169.254.42.24/initrd/initrd-Linux-x86_64-v3.14.5.gz",
|
||||
"kernel": "http://169.254.42.24/kernel/x86_64-mainline-lts-4.4-4.4.127-rev1/vmlinuz-4.4.127",
|
||||
"organization": "11111111-1111-4111-8111-111111111111",
|
||||
"public": true,
|
||||
"title": "x86_64 mainline 4.4.127 rev1"
|
||||
},
|
||||
"extra_volumes": [],
|
||||
"from_server": null,
|
||||
"id": "67375eb1-f14d-4f02-bb42-6119cecbde51",
|
||||
"modification_date": "2018-04-26T12:49:07.573004+00:00",
|
||||
"name": "Ubuntu Xenial",
|
||||
"organization": "51b656e3-4865-41e8-adbc-0c45bdd780db",
|
||||
"public": true,
|
||||
"root_volume": {
|
||||
"id": "020b8d61-3867-4a0e-84a4-445c5393e05d",
|
||||
"name": "snapshot-87fc282d-f252-4262-adad-86979d9074cf-2018-04-26_12:42",
|
||||
"size": 25000000000,
|
||||
"volume_type": "l_ssd"
|
||||
},
|
||||
"state": "available"
|
||||
},
|
||||
"ipv6": null,
|
||||
"location": {
|
||||
"cluster_id": "5",
|
||||
"hypervisor_id": "412",
|
||||
"node_id": "2",
|
||||
"platform_id": "13",
|
||||
"zone_id": "par1"
|
||||
},
|
||||
"maintenances": [],
|
||||
"modification_date": "2018-08-14T21:37:28.630882+00:00",
|
||||
"name": "scw-e0d256",
|
||||
"organization": "3f709602-5e6c-4619-b80c-e841c89734af",
|
||||
"private_ip": "10.14.222.131",
|
||||
"protected": false,
|
||||
"public_ip": {
|
||||
"address": "163.172.170.197",
|
||||
"dynamic": false,
|
||||
"id": "ea081794-a581-4495-8451-386ddaf0a451"
|
||||
},
|
||||
"security_group": {
|
||||
"id": "a37379d2-d8b0-4668-9cfb-1233fc436f7e",
|
||||
"name": "Default security group"
|
||||
},
|
||||
"state": "running",
|
||||
"state_detail": "booted",
|
||||
"tags": [],
|
||||
"volumes": {
|
||||
"0": {
|
||||
"creation_date": "2018-08-14T21:36:56.271545+00:00",
|
||||
"export_uri": "device://dev/vda",
|
||||
"id": "68386fae-4f55-4fbf-aabb-953036a85872",
|
||||
"modification_date": "2018-08-14T21:36:56.271545+00:00",
|
||||
"name": "snapshot-87fc282d-f252-4262-adad-86979d9074cf-2018-04-26_12:42",
|
||||
"organization": "3f709602-5e6c-4619-b80c-e841c89734af",
|
||||
"server": {
|
||||
"id": "12f19bc7-108c-4517-954c-e6b3d0311363",
|
||||
"name": "scw-e0d256"
|
||||
},
|
||||
"size": 25000000000,
|
||||
"state": "available",
|
||||
"volume_type": "l_ssd"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
'''
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible_collections.community.general.plugins.module_utils.scaleway import (
|
||||
Scaleway,
|
||||
ScalewayException,
|
||||
scaleway_argument_spec,
|
||||
SCALEWAY_LOCATION,
|
||||
)
|
||||
|
||||
|
||||
class ScalewayServerInfo(Scaleway):
|
||||
|
||||
def __init__(self, module):
|
||||
super(ScalewayServerInfo, self).__init__(module)
|
||||
self.name = 'servers'
|
||||
|
||||
region = module.params["region"]
|
||||
self.module.params['api_url'] = SCALEWAY_LOCATION[region]["api_endpoint"]
|
||||
|
||||
|
||||
def main():
|
||||
argument_spec = scaleway_argument_spec()
|
||||
argument_spec.update(dict(
|
||||
region=dict(required=True, choices=SCALEWAY_LOCATION.keys()),
|
||||
))
|
||||
|
||||
module = AnsibleModule(
|
||||
argument_spec=argument_spec,
|
||||
supports_check_mode=True,
|
||||
)
|
||||
|
||||
try:
|
||||
module.exit_json(
|
||||
scaleway_server_info=ScalewayServerInfo(module).get_resources()
|
||||
)
|
||||
except ScalewayException as exc:
|
||||
module.fail_json(msg=exc.message)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
112
plugins/modules/cloud/scaleway/scaleway_snapshot_facts.py
Normal file
112
plugins/modules/cloud/scaleway/scaleway_snapshot_facts.py
Normal file
|
@ -0,0 +1,112 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# (c) 2018, Yanis Guenane <yanis+ansible@guenane.org>
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
||||
'status': ['deprecated'],
|
||||
'supported_by': 'community'}
|
||||
|
||||
DOCUMENTATION = r'''
|
||||
---
|
||||
module: scaleway_snapshot_facts
|
||||
deprecated:
|
||||
removed_in: '2.13'
|
||||
why: Deprecated in favour of C(_info) module.
|
||||
alternative: Use M(scaleway_snapshot_info) instead.
|
||||
short_description: Gather facts about the Scaleway snapshots available.
|
||||
description:
|
||||
- Gather facts about the Scaleway snapshot available.
|
||||
author:
|
||||
- "Yanis Guenane (@Spredzy)"
|
||||
- "Remy Leone (@sieben)"
|
||||
extends_documentation_fragment:
|
||||
- community.general.scaleway
|
||||
|
||||
options:
|
||||
region:
|
||||
description:
|
||||
- Scaleway region to use (for example par1).
|
||||
required: true
|
||||
choices:
|
||||
- ams1
|
||||
- EMEA-NL-EVS
|
||||
- par1
|
||||
- EMEA-FR-PAR1
|
||||
'''
|
||||
|
||||
EXAMPLES = r'''
|
||||
- name: Gather Scaleway snapshots facts
|
||||
scaleway_snapshot_facts:
|
||||
region: par1
|
||||
'''
|
||||
|
||||
RETURN = r'''
|
||||
---
|
||||
scaleway_snapshot_facts:
|
||||
description: Response from Scaleway API
|
||||
returned: success
|
||||
type: complex
|
||||
sample:
|
||||
"scaleway_snapshot_facts": [
|
||||
{
|
||||
"base_volume": {
|
||||
"id": "68386fae-4f55-4fbf-aabb-953036a85872",
|
||||
"name": "snapshot-87fc282d-f252-4262-adad-86979d9074cf-2018-04-26_12:42"
|
||||
},
|
||||
"creation_date": "2018-08-14T22:34:35.299461+00:00",
|
||||
"id": "b61b4b03-a2e9-4da5-b5ea-e462ac0662d2",
|
||||
"modification_date": "2018-08-14T22:34:54.520560+00:00",
|
||||
"name": "snapshot-87fc282d-f252-4262-adad-86979d9074cf-2018-04-26_12:42 snapshot",
|
||||
"organization": "3f709602-5e6c-4619-b80c-e841c89734af",
|
||||
"size": 25000000000,
|
||||
"state": "available",
|
||||
"volume_type": "l_ssd"
|
||||
}
|
||||
]
|
||||
'''
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible_collections.community.general.plugins.module_utils.scaleway import (
|
||||
Scaleway,
|
||||
ScalewayException,
|
||||
scaleway_argument_spec,
|
||||
SCALEWAY_LOCATION
|
||||
)
|
||||
|
||||
|
||||
class ScalewaySnapshotFacts(Scaleway):
|
||||
|
||||
def __init__(self, module):
|
||||
super(ScalewaySnapshotFacts, self).__init__(module)
|
||||
self.name = 'snapshots'
|
||||
|
||||
region = module.params["region"]
|
||||
self.module.params['api_url'] = SCALEWAY_LOCATION[region]["api_endpoint"]
|
||||
|
||||
|
||||
def main():
|
||||
argument_spec = scaleway_argument_spec()
|
||||
argument_spec.update(dict(
|
||||
region=dict(required=True, choices=SCALEWAY_LOCATION.keys()),
|
||||
))
|
||||
|
||||
module = AnsibleModule(
|
||||
argument_spec=argument_spec,
|
||||
supports_check_mode=True,
|
||||
)
|
||||
|
||||
try:
|
||||
module.exit_json(
|
||||
ansible_facts={'scaleway_snapshot_facts': ScalewaySnapshotFacts(module).get_resources()}
|
||||
)
|
||||
except ScalewayException as exc:
|
||||
module.fail_json(msg=exc.message)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
112
plugins/modules/cloud/scaleway/scaleway_snapshot_info.py
Normal file
112
plugins/modules/cloud/scaleway/scaleway_snapshot_info.py
Normal file
|
@ -0,0 +1,112 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# (c) 2018, Yanis Guenane <yanis+ansible@guenane.org>
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
||||
'status': ['preview'],
|
||||
'supported_by': 'community'}
|
||||
|
||||
DOCUMENTATION = r'''
|
||||
---
|
||||
module: scaleway_snapshot_info
|
||||
short_description: Gather information about the Scaleway snapshots available.
|
||||
description:
|
||||
- Gather information about the Scaleway snapshot available.
|
||||
author:
|
||||
- "Yanis Guenane (@Spredzy)"
|
||||
- "Remy Leone (@sieben)"
|
||||
extends_documentation_fragment:
|
||||
- community.general.scaleway
|
||||
|
||||
options:
|
||||
region:
|
||||
description:
|
||||
- Scaleway region to use (for example C(par1)).
|
||||
required: true
|
||||
choices:
|
||||
- ams1
|
||||
- EMEA-NL-EVS
|
||||
- par1
|
||||
- EMEA-FR-PAR1
|
||||
'''
|
||||
|
||||
EXAMPLES = r'''
|
||||
- name: Gather Scaleway snapshots information
|
||||
scaleway_snapshot_info:
|
||||
region: par1
|
||||
register: result
|
||||
|
||||
- debug:
|
||||
msg: "{{ result.scaleway_snapshot_info }}"
|
||||
'''
|
||||
|
||||
RETURN = r'''
|
||||
---
|
||||
scaleway_snapshot_info:
|
||||
description: Response from Scaleway API
|
||||
returned: success
|
||||
type: complex
|
||||
sample:
|
||||
"scaleway_snapshot_info": [
|
||||
{
|
||||
"base_volume": {
|
||||
"id": "68386fae-4f55-4fbf-aabb-953036a85872",
|
||||
"name": "snapshot-87fc282d-f252-4262-adad-86979d9074cf-2018-04-26_12:42"
|
||||
},
|
||||
"creation_date": "2018-08-14T22:34:35.299461+00:00",
|
||||
"id": "b61b4b03-a2e9-4da5-b5ea-e462ac0662d2",
|
||||
"modification_date": "2018-08-14T22:34:54.520560+00:00",
|
||||
"name": "snapshot-87fc282d-f252-4262-adad-86979d9074cf-2018-04-26_12:42 snapshot",
|
||||
"organization": "3f709602-5e6c-4619-b80c-e841c89734af",
|
||||
"size": 25000000000,
|
||||
"state": "available",
|
||||
"volume_type": "l_ssd"
|
||||
}
|
||||
]
|
||||
'''
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible_collections.community.general.plugins.module_utils.scaleway import (
|
||||
Scaleway,
|
||||
ScalewayException,
|
||||
scaleway_argument_spec,
|
||||
SCALEWAY_LOCATION
|
||||
)
|
||||
|
||||
|
||||
class ScalewaySnapshotInfo(Scaleway):
|
||||
|
||||
def __init__(self, module):
|
||||
super(ScalewaySnapshotInfo, self).__init__(module)
|
||||
self.name = 'snapshots'
|
||||
|
||||
region = module.params["region"]
|
||||
self.module.params['api_url'] = SCALEWAY_LOCATION[region]["api_endpoint"]
|
||||
|
||||
|
||||
def main():
|
||||
argument_spec = scaleway_argument_spec()
|
||||
argument_spec.update(dict(
|
||||
region=dict(required=True, choices=SCALEWAY_LOCATION.keys()),
|
||||
))
|
||||
|
||||
module = AnsibleModule(
|
||||
argument_spec=argument_spec,
|
||||
supports_check_mode=True,
|
||||
)
|
||||
|
||||
try:
|
||||
module.exit_json(
|
||||
scaleway_snapshot_info=ScalewaySnapshotInfo(module).get_resources()
|
||||
)
|
||||
except ScalewayException as exc:
|
||||
module.fail_json(msg=exc.message)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
175
plugins/modules/cloud/scaleway/scaleway_sshkey.py
Normal file
175
plugins/modules/cloud/scaleway/scaleway_sshkey.py
Normal file
|
@ -0,0 +1,175 @@
|
|||
#!/usr/bin/python
|
||||
#
|
||||
# Scaleway SSH keys management module
|
||||
#
|
||||
# Copyright (C) 2018 Online SAS.
|
||||
# https://www.scaleway.com
|
||||
#
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
ANSIBLE_METADATA = {
|
||||
'metadata_version': '1.1',
|
||||
'status': ['preview'],
|
||||
'supported_by': 'community'
|
||||
}
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: scaleway_sshkey
|
||||
short_description: Scaleway SSH keys management module
|
||||
author: Remy Leone (@sieben)
|
||||
description:
|
||||
- This module manages SSH keys on Scaleway account
|
||||
U(https://developer.scaleway.com)
|
||||
extends_documentation_fragment:
|
||||
- community.general.scaleway
|
||||
|
||||
|
||||
options:
|
||||
state:
|
||||
description:
|
||||
- Indicate desired state of the SSH key.
|
||||
default: present
|
||||
choices:
|
||||
- present
|
||||
- absent
|
||||
ssh_pub_key:
|
||||
description:
|
||||
- The public SSH key as a string to add.
|
||||
required: true
|
||||
api_url:
|
||||
description:
|
||||
- Scaleway API URL
|
||||
default: 'https://account.scaleway.com'
|
||||
aliases: ['base_url']
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
- name: "Add SSH key"
|
||||
scaleway_sshkey:
|
||||
ssh_pub_key: "ssh-rsa AAAA..."
|
||||
state: "present"
|
||||
|
||||
- name: "Delete SSH key"
|
||||
scaleway_sshkey:
|
||||
ssh_pub_key: "ssh-rsa AAAA..."
|
||||
state: "absent"
|
||||
|
||||
- name: "Add SSH key with explicit token"
|
||||
scaleway_sshkey:
|
||||
ssh_pub_key: "ssh-rsa AAAA..."
|
||||
state: "present"
|
||||
oauth_token: "6ecd2c9b-6f4f-44d4-a187-61a92078d08c"
|
||||
'''
|
||||
|
||||
RETURN = '''
|
||||
data:
|
||||
description: This is only present when C(state=present)
|
||||
returned: when C(state=present)
|
||||
type: dict
|
||||
sample: {
|
||||
"ssh_public_keys": [
|
||||
{"key": "ssh-rsa AAAA...."}
|
||||
]
|
||||
}
|
||||
'''
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule, env_fallback
|
||||
from ansible_collections.community.general.plugins.module_utils.scaleway import scaleway_argument_spec, Scaleway
|
||||
|
||||
|
||||
def extract_present_sshkeys(raw_organization_dict):
|
||||
ssh_key_list = raw_organization_dict["organizations"][0]["users"][0]["ssh_public_keys"]
|
||||
ssh_key_lookup = [ssh_key["key"] for ssh_key in ssh_key_list]
|
||||
return ssh_key_lookup
|
||||
|
||||
|
||||
def extract_user_id(raw_organization_dict):
|
||||
return raw_organization_dict["organizations"][0]["users"][0]["id"]
|
||||
|
||||
|
||||
def sshkey_user_patch(ssh_lookup):
|
||||
ssh_list = {"ssh_public_keys": [{"key": key}
|
||||
for key in ssh_lookup]}
|
||||
return ssh_list
|
||||
|
||||
|
||||
def core(module):
|
||||
ssh_pub_key = module.params['ssh_pub_key']
|
||||
state = module.params["state"]
|
||||
account_api = Scaleway(module)
|
||||
response = account_api.get('organizations')
|
||||
|
||||
status_code = response.status_code
|
||||
organization_json = response.json
|
||||
|
||||
if not response.ok:
|
||||
module.fail_json(msg='Error getting ssh key [{0}: {1}]'.format(
|
||||
status_code, response.json['message']))
|
||||
|
||||
user_id = extract_user_id(organization_json)
|
||||
present_sshkeys = []
|
||||
try:
|
||||
present_sshkeys = extract_present_sshkeys(organization_json)
|
||||
except (KeyError, IndexError) as e:
|
||||
module.fail_json(changed=False, data="Error while extracting present SSH keys from API")
|
||||
|
||||
if state in ('present',):
|
||||
if ssh_pub_key in present_sshkeys:
|
||||
module.exit_json(changed=False)
|
||||
|
||||
# If key not found create it!
|
||||
if module.check_mode:
|
||||
module.exit_json(changed=True)
|
||||
|
||||
present_sshkeys.append(ssh_pub_key)
|
||||
payload = sshkey_user_patch(present_sshkeys)
|
||||
|
||||
response = account_api.patch('/users/%s' % user_id, data=payload)
|
||||
|
||||
if response.ok:
|
||||
module.exit_json(changed=True, data=response.json)
|
||||
|
||||
module.fail_json(msg='Error creating ssh key [{0}: {1}]'.format(
|
||||
response.status_code, response.json))
|
||||
|
||||
elif state in ('absent',):
|
||||
if ssh_pub_key not in present_sshkeys:
|
||||
module.exit_json(changed=False)
|
||||
|
||||
if module.check_mode:
|
||||
module.exit_json(changed=True)
|
||||
|
||||
present_sshkeys.remove(ssh_pub_key)
|
||||
payload = sshkey_user_patch(present_sshkeys)
|
||||
|
||||
response = account_api.patch('/users/%s' % user_id, data=payload)
|
||||
|
||||
if response.ok:
|
||||
module.exit_json(changed=True, data=response.json)
|
||||
|
||||
module.fail_json(msg='Error deleting ssh key [{0}: {1}]'.format(
|
||||
response.status_code, response.json))
|
||||
|
||||
|
||||
def main():
|
||||
argument_spec = scaleway_argument_spec()
|
||||
argument_spec.update(dict(
|
||||
state=dict(default='present', choices=['absent', 'present']),
|
||||
ssh_pub_key=dict(required=True),
|
||||
api_url=dict(fallback=(env_fallback, ['SCW_API_URL']), default='https://account.scaleway.com', aliases=['base_url']),
|
||||
))
|
||||
module = AnsibleModule(
|
||||
argument_spec=argument_spec,
|
||||
supports_check_mode=True,
|
||||
)
|
||||
|
||||
core(module)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
171
plugins/modules/cloud/scaleway/scaleway_user_data.py
Normal file
171
plugins/modules/cloud/scaleway/scaleway_user_data.py
Normal file
|
@ -0,0 +1,171 @@
|
|||
#!/usr/bin/python
|
||||
#
|
||||
# Scaleway user data management module
|
||||
#
|
||||
# Copyright (C) 2018 Online SAS.
|
||||
# https://www.scaleway.com
|
||||
#
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
ANSIBLE_METADATA = {
|
||||
'metadata_version': '1.1',
|
||||
'status': ['preview'],
|
||||
'supported_by': 'community'
|
||||
}
|
||||
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: scaleway_user_data
|
||||
short_description: Scaleway user_data management module
|
||||
author: Remy Leone (@sieben)
|
||||
description:
|
||||
- "This module manages user_data on compute instances on Scaleway."
|
||||
- "It can be used to configure cloud-init for instance"
|
||||
extends_documentation_fragment:
|
||||
- community.general.scaleway
|
||||
|
||||
|
||||
options:
|
||||
|
||||
server_id:
|
||||
description:
|
||||
- Scaleway Compute instance ID of the server
|
||||
required: true
|
||||
|
||||
user_data:
|
||||
description:
|
||||
- User defined data. Typically used with `cloud-init`.
|
||||
- Pass your cloud-init script here as a string
|
||||
required: false
|
||||
|
||||
region:
|
||||
description:
|
||||
- Scaleway compute zone
|
||||
required: true
|
||||
choices:
|
||||
- ams1
|
||||
- EMEA-NL-EVS
|
||||
- par1
|
||||
- EMEA-FR-PAR1
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
- name: Update the cloud-init
|
||||
scaleway_user_data:
|
||||
server_id: '5a33b4ab-57dd-4eb6-8b0a-d95eb63492ce'
|
||||
region: ams1
|
||||
user_data:
|
||||
cloud-init: 'final_message: "Hello World!"'
|
||||
'''
|
||||
|
||||
RETURN = '''
|
||||
'''
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible_collections.community.general.plugins.module_utils.scaleway import SCALEWAY_LOCATION, scaleway_argument_spec, Scaleway
|
||||
|
||||
|
||||
def patch_user_data(compute_api, server_id, key, value):
|
||||
compute_api.module.debug("Starting patching user_data attributes")
|
||||
|
||||
path = "servers/%s/user_data/%s" % (server_id, key)
|
||||
response = compute_api.patch(path=path, data=value, headers={"Content-type": "text/plain"})
|
||||
if not response.ok:
|
||||
msg = 'Error during user_data patching: %s %s' % (response.status_code, response.body)
|
||||
compute_api.module.fail_json(msg=msg)
|
||||
|
||||
return response
|
||||
|
||||
|
||||
def delete_user_data(compute_api, server_id, key):
|
||||
compute_api.module.debug("Starting deleting user_data attributes: %s" % key)
|
||||
|
||||
response = compute_api.delete(path="servers/%s/user_data/%s" % (server_id, key))
|
||||
|
||||
if not response.ok:
|
||||
msg = 'Error during user_data deleting: (%s) %s' % response.status_code, response.body
|
||||
compute_api.module.fail_json(msg=msg)
|
||||
|
||||
return response
|
||||
|
||||
|
||||
def get_user_data(compute_api, server_id, key):
|
||||
compute_api.module.debug("Starting patching user_data attributes")
|
||||
|
||||
path = "servers/%s/user_data/%s" % (server_id, key)
|
||||
response = compute_api.get(path=path)
|
||||
if not response.ok:
|
||||
msg = 'Error during user_data patching: %s %s' % (response.status_code, response.body)
|
||||
compute_api.module.fail_json(msg=msg)
|
||||
|
||||
return response.json
|
||||
|
||||
|
||||
def core(module):
|
||||
region = module.params["region"]
|
||||
server_id = module.params["server_id"]
|
||||
user_data = module.params["user_data"]
|
||||
changed = False
|
||||
|
||||
module.params['api_url'] = SCALEWAY_LOCATION[region]["api_endpoint"]
|
||||
compute_api = Scaleway(module=module)
|
||||
|
||||
user_data_list = compute_api.get(path="servers/%s/user_data" % server_id)
|
||||
if not user_data_list.ok:
|
||||
msg = 'Error during user_data fetching: %s %s' % user_data_list.status_code, user_data_list.body
|
||||
compute_api.module.fail_json(msg=msg)
|
||||
|
||||
present_user_data_keys = user_data_list.json["user_data"]
|
||||
present_user_data = dict(
|
||||
(key, get_user_data(compute_api=compute_api, server_id=server_id, key=key))
|
||||
for key in present_user_data_keys
|
||||
)
|
||||
|
||||
if present_user_data == user_data:
|
||||
module.exit_json(changed=changed, msg=user_data_list.json)
|
||||
|
||||
# First we remove keys that are not defined in the wished user_data
|
||||
for key in present_user_data:
|
||||
if key not in user_data:
|
||||
|
||||
changed = True
|
||||
if compute_api.module.check_mode:
|
||||
module.exit_json(changed=changed, msg={"status": "User-data of %s would be patched." % server_id})
|
||||
|
||||
delete_user_data(compute_api=compute_api, server_id=server_id, key=key)
|
||||
|
||||
# Then we patch keys that are different
|
||||
for key, value in user_data.items():
|
||||
if key not in present_user_data or user_data[key] != present_user_data[key]:
|
||||
|
||||
changed = True
|
||||
if compute_api.module.check_mode:
|
||||
module.exit_json(changed=changed, msg={"status": "User-data of %s would be patched." % server_id})
|
||||
|
||||
patch_user_data(compute_api=compute_api, server_id=server_id, key=key, value=value)
|
||||
|
||||
module.exit_json(changed=changed, msg=user_data)
|
||||
|
||||
|
||||
def main():
|
||||
argument_spec = scaleway_argument_spec()
|
||||
argument_spec.update(dict(
|
||||
region=dict(required=True, choices=SCALEWAY_LOCATION.keys()),
|
||||
user_data=dict(type="dict"),
|
||||
server_id=dict(required=True),
|
||||
))
|
||||
module = AnsibleModule(
|
||||
argument_spec=argument_spec,
|
||||
supports_check_mode=True,
|
||||
)
|
||||
|
||||
core(module)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
173
plugins/modules/cloud/scaleway/scaleway_volume.py
Normal file
173
plugins/modules/cloud/scaleway/scaleway_volume.py
Normal file
|
@ -0,0 +1,173 @@
|
|||
#!/usr/bin/python
|
||||
#
|
||||
# Scaleway volumes management module
|
||||
#
|
||||
# Copyright (C) 2018 Henryk Konsek Consulting (hekonsek@gmail.com).
|
||||
#
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
ANSIBLE_METADATA = {
|
||||
'metadata_version': '1.1',
|
||||
'status': ['preview'],
|
||||
'supported_by': 'community'
|
||||
}
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: scaleway_volume
|
||||
short_description: Scaleway volumes management module
|
||||
author: Henryk Konsek (@hekonsek)
|
||||
description:
|
||||
- This module manages volumes on Scaleway account
|
||||
U(https://developer.scaleway.com)
|
||||
extends_documentation_fragment:
|
||||
- community.general.scaleway
|
||||
|
||||
|
||||
options:
|
||||
state:
|
||||
description:
|
||||
- Indicate desired state of the volume.
|
||||
default: present
|
||||
choices:
|
||||
- present
|
||||
- absent
|
||||
region:
|
||||
description:
|
||||
- Scaleway region to use (for example par1).
|
||||
required: true
|
||||
choices:
|
||||
- ams1
|
||||
- EMEA-NL-EVS
|
||||
- par1
|
||||
- EMEA-FR-PAR1
|
||||
name:
|
||||
description:
|
||||
- Name used to identify the volume.
|
||||
required: true
|
||||
organization:
|
||||
description:
|
||||
- ScaleWay organization ID to which volume belongs.
|
||||
size:
|
||||
description:
|
||||
- Size of the volume in bytes.
|
||||
volume_type:
|
||||
description:
|
||||
- Type of the volume (for example 'l_ssd').
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
- name: Create 10GB volume
|
||||
scaleway_volume:
|
||||
name: my-volume
|
||||
state: present
|
||||
region: par1
|
||||
organization: "{{ scw_org }}"
|
||||
"size": 10000000000
|
||||
volume_type: l_ssd
|
||||
register: server_creation_check_task
|
||||
|
||||
- name: Make sure volume deleted
|
||||
scaleway_volume:
|
||||
name: my-volume
|
||||
state: absent
|
||||
region: par1
|
||||
|
||||
'''
|
||||
|
||||
RETURN = '''
|
||||
data:
|
||||
description: This is only present when C(state=present)
|
||||
returned: when C(state=present)
|
||||
type: dict
|
||||
sample: {
|
||||
"volume": {
|
||||
"export_uri": null,
|
||||
"id": "c675f420-cfeb-48ff-ba2a-9d2a4dbe3fcd",
|
||||
"name": "volume-0-3",
|
||||
"organization": "000a115d-2852-4b0a-9ce8-47f1134ba95a",
|
||||
"server": null,
|
||||
"size": 10000000000,
|
||||
"volume_type": "l_ssd"
|
||||
}
|
||||
}
|
||||
'''
|
||||
|
||||
from ansible_collections.community.general.plugins.module_utils.scaleway import SCALEWAY_LOCATION, scaleway_argument_spec, Scaleway
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
|
||||
|
||||
def core(module):
|
||||
state = module.params['state']
|
||||
name = module.params['name']
|
||||
organization = module.params['organization']
|
||||
size = module.params['size']
|
||||
volume_type = module.params['volume_type']
|
||||
|
||||
account_api = Scaleway(module)
|
||||
response = account_api.get('volumes')
|
||||
status_code = response.status_code
|
||||
volumes_json = response.json
|
||||
|
||||
if not response.ok:
|
||||
module.fail_json(msg='Error getting volume [{0}: {1}]'.format(
|
||||
status_code, response.json['message']))
|
||||
|
||||
volumeByName = None
|
||||
for volume in volumes_json['volumes']:
|
||||
if volume['organization'] == organization and volume['name'] == name:
|
||||
volumeByName = volume
|
||||
|
||||
if state in ('present',):
|
||||
if volumeByName is not None:
|
||||
module.exit_json(changed=False)
|
||||
|
||||
payload = {'name': name, 'organization': organization, 'size': size, 'volume_type': volume_type}
|
||||
|
||||
response = account_api.post('/volumes', payload)
|
||||
|
||||
if response.ok:
|
||||
module.exit_json(changed=True, data=response.json)
|
||||
|
||||
module.fail_json(msg='Error creating volume [{0}: {1}]'.format(
|
||||
response.status_code, response.json))
|
||||
|
||||
elif state in ('absent',):
|
||||
if volumeByName is None:
|
||||
module.exit_json(changed=False)
|
||||
|
||||
if module.check_mode:
|
||||
module.exit_json(changed=True)
|
||||
|
||||
response = account_api.delete('/volumes/' + volumeByName['id'])
|
||||
if response.status_code == 204:
|
||||
module.exit_json(changed=True, data=response.json)
|
||||
|
||||
module.fail_json(msg='Error deleting volume [{0}: {1}]'.format(
|
||||
response.status_code, response.json))
|
||||
|
||||
|
||||
def main():
|
||||
argument_spec = scaleway_argument_spec()
|
||||
argument_spec.update(dict(
|
||||
state=dict(default='present', choices=['absent', 'present']),
|
||||
name=dict(required=True),
|
||||
size=dict(type='int'),
|
||||
organization=dict(),
|
||||
volume_type=dict(),
|
||||
region=dict(required=True, choices=SCALEWAY_LOCATION.keys()),
|
||||
))
|
||||
module = AnsibleModule(
|
||||
argument_spec=argument_spec,
|
||||
supports_check_mode=True,
|
||||
)
|
||||
|
||||
core(module)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
107
plugins/modules/cloud/scaleway/scaleway_volume_facts.py
Normal file
107
plugins/modules/cloud/scaleway/scaleway_volume_facts.py
Normal file
|
@ -0,0 +1,107 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# (c) 2018, Yanis Guenane <yanis+ansible@guenane.org>
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
||||
'status': ['deprecated'],
|
||||
'supported_by': 'community'}
|
||||
|
||||
DOCUMENTATION = r'''
|
||||
---
|
||||
module: scaleway_volume_facts
|
||||
deprecated:
|
||||
removed_in: '2.13'
|
||||
why: Deprecated in favour of C(_info) module.
|
||||
alternative: Use M(scaleway_volume_info) instead.
|
||||
short_description: Gather facts about the Scaleway volumes available.
|
||||
description:
|
||||
- Gather facts about the Scaleway volumes available.
|
||||
author:
|
||||
- "Yanis Guenane (@Spredzy)"
|
||||
- "Remy Leone (@sieben)"
|
||||
extends_documentation_fragment:
|
||||
- community.general.scaleway
|
||||
|
||||
options:
|
||||
region:
|
||||
description:
|
||||
- Scaleway region to use (for example par1).
|
||||
required: true
|
||||
choices:
|
||||
- ams1
|
||||
- EMEA-NL-EVS
|
||||
- par1
|
||||
- EMEA-FR-PAR1
|
||||
'''
|
||||
|
||||
EXAMPLES = r'''
|
||||
- name: Gather Scaleway volumes facts
|
||||
scaleway_volume_facts:
|
||||
region: par1
|
||||
'''
|
||||
|
||||
RETURN = r'''
|
||||
---
|
||||
scaleway_volume_facts:
|
||||
description: Response from Scaleway API
|
||||
returned: success
|
||||
type: complex
|
||||
sample:
|
||||
"scaleway_volume_facts": [
|
||||
{
|
||||
"creation_date": "2018-08-14T20:56:24.949660+00:00",
|
||||
"export_uri": null,
|
||||
"id": "b8d51a06-daeb-4fef-9539-a8aea016c1ba",
|
||||
"modification_date": "2018-08-14T20:56:24.949660+00:00",
|
||||
"name": "test-volume",
|
||||
"organization": "3f709602-5e6c-4619-b80c-e841c89734af",
|
||||
"server": null,
|
||||
"size": 50000000000,
|
||||
"state": "available",
|
||||
"volume_type": "l_ssd"
|
||||
}
|
||||
]
|
||||
'''
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible_collections.community.general.plugins.module_utils.scaleway import (
|
||||
Scaleway, ScalewayException, scaleway_argument_spec,
|
||||
SCALEWAY_LOCATION)
|
||||
|
||||
|
||||
class ScalewayVolumeFacts(Scaleway):
|
||||
|
||||
def __init__(self, module):
|
||||
super(ScalewayVolumeFacts, self).__init__(module)
|
||||
self.name = 'volumes'
|
||||
|
||||
region = module.params["region"]
|
||||
self.module.params['api_url'] = SCALEWAY_LOCATION[region]["api_endpoint"]
|
||||
|
||||
|
||||
def main():
|
||||
argument_spec = scaleway_argument_spec()
|
||||
argument_spec.update(dict(
|
||||
region=dict(required=True, choices=SCALEWAY_LOCATION.keys()),
|
||||
))
|
||||
|
||||
module = AnsibleModule(
|
||||
argument_spec=argument_spec,
|
||||
supports_check_mode=True,
|
||||
)
|
||||
|
||||
try:
|
||||
module.exit_json(
|
||||
ansible_facts={'scaleway_volume_facts': ScalewayVolumeFacts(module).get_resources()}
|
||||
)
|
||||
except ScalewayException as exc:
|
||||
module.fail_json(msg=exc.message)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
107
plugins/modules/cloud/scaleway/scaleway_volume_info.py
Normal file
107
plugins/modules/cloud/scaleway/scaleway_volume_info.py
Normal file
|
@ -0,0 +1,107 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# (c) 2018, Yanis Guenane <yanis+ansible@guenane.org>
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
||||
'status': ['preview'],
|
||||
'supported_by': 'community'}
|
||||
|
||||
DOCUMENTATION = r'''
|
||||
---
|
||||
module: scaleway_volume_info
|
||||
short_description: Gather information about the Scaleway volumes available.
|
||||
description:
|
||||
- Gather information about the Scaleway volumes available.
|
||||
author:
|
||||
- "Yanis Guenane (@Spredzy)"
|
||||
- "Remy Leone (@sieben)"
|
||||
extends_documentation_fragment:
|
||||
- community.general.scaleway
|
||||
|
||||
options:
|
||||
region:
|
||||
description:
|
||||
- Scaleway region to use (for example C(par1)).
|
||||
required: true
|
||||
choices:
|
||||
- ams1
|
||||
- EMEA-NL-EVS
|
||||
- par1
|
||||
- EMEA-FR-PAR1
|
||||
'''
|
||||
|
||||
EXAMPLES = r'''
|
||||
- name: Gather Scaleway volumes information
|
||||
scaleway_volume_info:
|
||||
region: par1
|
||||
register: result
|
||||
|
||||
- debug:
|
||||
msg: "{{ result.scaleway_volume_info }}"
|
||||
'''
|
||||
|
||||
RETURN = r'''
|
||||
---
|
||||
scaleway_volume_info:
|
||||
description: Response from Scaleway API
|
||||
returned: success
|
||||
type: complex
|
||||
sample:
|
||||
"scaleway_volume_info": [
|
||||
{
|
||||
"creation_date": "2018-08-14T20:56:24.949660+00:00",
|
||||
"export_uri": null,
|
||||
"id": "b8d51a06-daeb-4fef-9539-a8aea016c1ba",
|
||||
"modification_date": "2018-08-14T20:56:24.949660+00:00",
|
||||
"name": "test-volume",
|
||||
"organization": "3f709602-5e6c-4619-b80c-e841c89734af",
|
||||
"server": null,
|
||||
"size": 50000000000,
|
||||
"state": "available",
|
||||
"volume_type": "l_ssd"
|
||||
}
|
||||
]
|
||||
'''
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible_collections.community.general.plugins.module_utils.scaleway import (
|
||||
Scaleway, ScalewayException, scaleway_argument_spec,
|
||||
SCALEWAY_LOCATION)
|
||||
|
||||
|
||||
class ScalewayVolumeInfo(Scaleway):
|
||||
|
||||
def __init__(self, module):
|
||||
super(ScalewayVolumeInfo, self).__init__(module)
|
||||
self.name = 'volumes'
|
||||
|
||||
region = module.params["region"]
|
||||
self.module.params['api_url'] = SCALEWAY_LOCATION[region]["api_endpoint"]
|
||||
|
||||
|
||||
def main():
|
||||
argument_spec = scaleway_argument_spec()
|
||||
argument_spec.update(dict(
|
||||
region=dict(required=True, choices=SCALEWAY_LOCATION.keys()),
|
||||
))
|
||||
|
||||
module = AnsibleModule(
|
||||
argument_spec=argument_spec,
|
||||
supports_check_mode=True,
|
||||
)
|
||||
|
||||
try:
|
||||
module.exit_json(
|
||||
scaleway_volume_info=ScalewayVolumeInfo(module).get_resources()
|
||||
)
|
||||
except ScalewayException as exc:
|
||||
module.fail_json(msg=exc.message)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
Loading…
Add table
Add a link
Reference in a new issue