Initial commit

This commit is contained in:
Ansible Core Team 2020-03-09 09:11:07 +00:00
commit aebc1b03fd
4861 changed files with 812621 additions and 0 deletions

View 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()

View 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()

View 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()

View 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()

View 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()

View 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()

View 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()

View 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()

View 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()

View 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()

View 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()

View 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()

View 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()

View 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()

View 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()

View 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()

View 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()

View 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()

View 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()

View 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()

View 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()

View 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()