diff --git a/lib/ansible/module_utils/scaleway.py b/lib/ansible/module_utils/scaleway.py new file mode 100644 index 00000000000..d15c9efc56d --- /dev/null +++ b/lib/ansible/module_utils/scaleway.py @@ -0,0 +1,78 @@ +import json + +from ansible.module_utils.urls import fetch_url + + +class Response(object): + + def __init__(self, resp, info): + self.body = None + if resp: + self.body = resp.read() + self.info = info + + @property + def json(self): + if not self.body: + if "body" in self.info: + return json.loads(self.info["body"]) + return None + try: + return json.loads(self.body) + except ValueError: + return None + + @property + def status_code(self): + return self.info["status"] + + @property + def ok(self): + return self.status_code in (200, 201, 202, 204) + + +class ScalewayAPI(object): + + def __init__(self, module, headers, base_url): + self.module = module + self.headers = headers + self.base_url = base_url + + def _url_builder(self, path): + if path[0] == '/': + path = path[1:] + return '%s/%s' % (self.base_url, path) + + def send(self, method, path, data=None, headers=None): + url = self._url_builder(path) + data = self.module.jsonify(data) + timeout = self.module.params['timeout'] + + if headers is not None: + self.headers.update(headers) + + resp, info = fetch_url(self.module, url, data=data, headers=self.headers, method=method, timeout=timeout) + + # Exceptions in fetch_url may result in a status -1, the ensures a proper error to the user in all cases + if info['status'] == -1: + self.module.fail_json(msg=info['msg']) + + return Response(resp, info) + + def get(self, path, data=None, headers=None): + return self.send('GET', path, data, headers) + + def put(self, path, data=None, headers=None): + return self.send('PUT', path, data, headers) + + def post(self, path, data=None, headers=None): + return self.send('POST', path, data, headers) + + def delete(self, path, data=None, headers=None): + return self.send('DELETE', path, data, headers) + + def patch(self, path, data=None, headers=None): + return self.send("PATCH", path, data, headers) + + def update(self, path, data=None, headers=None): + return self.send("UPDATE", path, data, headers) diff --git a/lib/ansible/modules/cloud/scaleway/scaleway_compute.py b/lib/ansible/modules/cloud/scaleway/scaleway_compute.py new file mode 100644 index 00000000000..a9090849206 --- /dev/null +++ b/lib/ansible/modules/cloud/scaleway/scaleway_compute.py @@ -0,0 +1,631 @@ +#!/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 +version_added: "2.6" +author: Remy Leone (@sieben) +description: + - "This module manages compute instances on Scaleway." +options: + + 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: [] + + oauth_token: + description: + - Scaleway OAuth token. + required: true + + 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 + choices: + - ARM64-2GB + - ARM64-4GB + - ARM64-8GB + - ARM64-16GB + - ARM64-32GB + - ARM64-64GB + - ARM64-128GB + - C1 + - C2S + - C2M + - C2L + - VC1S + - VC1M + - VC1L + - X64-15GB + - X64-30GB + - X64-60GB + - X64-120GB + + timeout: + description: + - Timeout for API calls + required: false + default: 30 + + 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 +''' + +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: 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.basic import env_fallback +from ansible.module_utils.six.moves.urllib.parse import quote as urlquote +from ansible.module_utils.scaleway import ScalewayAPI + +SCALEWAY_COMMERCIAL_TYPES = [ + + # Virtual ARM64 compute instance + 'ARM64-2GB', + 'ARM64-4GB', + 'ARM64-8GB', + 'ARM64-16GB', + 'ARM64-32GB', + 'ARM64-64GB', + 'ARM64-128GB', + + # Baremetal + 'C1', # ARM64 (4 cores) - 2GB + 'C2S', # X86-64 (4 cores) - 8GB + 'C2M', # X86-64 (8 cores) - 16GB + 'C2L', # x86-64 (8 cores) - 32 GB + + # Virtual X86-64 compute instance + 'VC1S', # Starter X86-64 (2 cores) - 2GB + 'VC1M', # Starter X86-64 (4 cores) - 4GB + 'VC1L', # Starter X86-64 (6 cores) - 8GB + 'X64-15GB', + 'X64-30GB', + 'X64-60GB', + 'X64-120GB', +] + +SCALEWAY_LOCATION = { + 'par1': {'name': 'Paris 1', 'country': 'FR', "api_endpoint": 'https://cp-par1.scaleway.com'}, + 'EMEA-FR-PAR1': {'name': 'Paris 1', 'country': 'FR', "api_endpoint": 'https://cp-par1.scaleway.com'}, + 'ams1': {'name': 'Amsterdam 1', 'country': 'NL', "api_endpoint": 'https://cp-ams1.scaleway.com'}, + 'EMEA-NL-EVS': {'name': 'Amsterdam 1', 'country': 'NL', "api_endpoint": 'https://cp-ams1.scaleway.com'}, +} + +SCALEWAY_SERVER_STATES = ( + 'stopped', + 'stopping', + 'starting', + 'running', + 'locked' +) + +SCALEWAY_TRANSITIONS_STATES = ( + "stopping", + "starting", + "pending" +) + + +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 create_server(compute_api, server): + compute_api.module.debug("Starting a create_server") + target_server = None + response = compute_api.post(path="servers", + data={"enable_ipv6": server["enable_ipv6"], + "tags": server["tags"], + "commercial_type": server["commercial_type"], + "image": server["image"], + "name": server["name"], + "organization": server["organization"]}) + + 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"]} + + 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 not 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"]} + + 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"]} + + 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"]} + + 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 + url = 'servers?name=%s&per_page=%d' % (urlquote(wished_server["name"]), per_page) + response = compute_api.get(url) + + 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", +) + + +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: + return any([target_server[x] != wished_server[x] + for x in PATCH_MUTABLE_SERVER_ATTRIBUTES + if x in target_server and x in wished_server]) + 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((x, wished_server[x]) + for x in PATCH_MUTABLE_SERVER_ATTRIBUTES + if x in wished_server and x in target_server) + 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) + + wait_to_complete_state_transition(compute_api=compute_api, server=target_server) + + return response + + +def core(module): + api_token = module.params['oauth_token'] + 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"] + } + + compute_api = ScalewayAPI(module=module, + headers={'X-Auth-Token': api_token, + 'Content-type': 'application/json'}, + base_url=SCALEWAY_LOCATION[region]["api_endpoint"]) + + changed, summary = state_strategy[wished_server["state"]](compute_api=compute_api, wished_server=wished_server) + module.exit_json(changed=changed, msg=summary) + + +def main(): + module = AnsibleModule( + argument_spec=dict( + oauth_token=dict( + no_log=True, + # Support environment variable for Scaleway OAuth Token + fallback=(env_fallback, ['SCW_TOKEN', 'SCW_API_KEY', 'SCW_OAUTH_TOKEN']), + required=True, + ), + image=dict(required=True), + name=dict(), + region=dict(required=True, choices=SCALEWAY_LOCATION.keys()), + commercial_type=dict(required=True, choices=SCALEWAY_COMMERCIAL_TYPES), + enable_ipv6=dict(default=False, type="bool"), + state=dict(choices=state_strategy.keys(), default='present'), + tags=dict(type="list", default=[]), + organization=dict(required=True), + timeout=dict(type="int", default=30), + wait=dict(type="bool", default=False), + wait_timeout=dict(type="int", default=300), + wait_sleep_time=dict(type="int", default=3), + ), + supports_check_mode=True, + ) + + core(module) + + +if __name__ == '__main__': + main() diff --git a/lib/ansible/modules/cloud/scaleway/scaleway_sshkey.py b/lib/ansible/modules/cloud/scaleway/scaleway_sshkey.py index 2a4cf8f63a1..c8070fd0b43 100644 --- a/lib/ansible/modules/cloud/scaleway/scaleway_sshkey.py +++ b/lib/ansible/modules/cloud/scaleway/scaleway_sshkey.py @@ -83,82 +83,9 @@ data: } ''' -import json - from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.basic import env_fallback -from ansible.module_utils.urls import fetch_url - - -class Response(object): - - def __init__(self, resp, info): - self.body = None - if resp: - self.body = resp.read() - self.info = info - - @property - def json(self): - if not self.body: - if "body" in self.info: - return json.loads(self.info["body"]) - return None - try: - return json.loads(self.body) - except ValueError: - return None - - @property - def status_code(self): - return self.info["status"] - - -class AccountAPI(object): - - def __init__(self, module, headers, base_url): - self.module = module - self.headers = headers - self.base_url = base_url - - def _url_builder(self, path): - if path[0] == '/': - path = path[1:] - return '%s/%s' % (self.base_url, path) - - def send(self, method, path, data=None, headers=None): - url = self._url_builder(path) - data = self.module.jsonify(data) - timeout = self.module.params['timeout'] - - if headers is not None: - self.headers.update(headers) - - resp, info = fetch_url(self.module, url, data=data, headers=self.headers, method=method, timeout=timeout) - - # Exceptions in fetch_url may result in a status -1, the ensures a proper error to the user in all cases - if info['status'] == -1: - self.module.fail_json(msg=info['msg']) - - return Response(resp, info) - - def get(self, path, data=None, headers=None): - return self.send('GET', path, data, headers) - - def put(self, path, data=None, headers=None): - return self.send('PUT', path, data, headers) - - def post(self, path, data=None, headers=None): - return self.send('POST', path, data, headers) - - def delete(self, path, data=None, headers=None): - return self.send('DELETE', path, data, headers) - - def patch(self, path, data=None, headers=None): - return self.send("PATCH", path, data, headers) - - def update(self, path, data=None, headers=None): - return self.send("UPDATE", path, data, headers) +from ansible.module_utils.scaleway import ScalewayAPI def extract_present_sshkeys(raw_organization_dict): @@ -181,16 +108,16 @@ def core(module): api_token = module.params['oauth_token'] ssh_pub_key = module.params['ssh_pub_key'] state = module.params["state"] - account_api = AccountAPI(module, - headers={'X-Auth-Token': api_token, - 'Content-type': 'application/json'}, - base_url=module.params["base_url"]) + account_api = ScalewayAPI(module, + headers={'X-Auth-Token': api_token, + 'Content-type': 'application/json'}, + base_url=module.params["base_url"]) response = account_api.get('organizations') status_code = response.status_code organization_json = response.json - if status_code not in (200, 404): + if not response.ok: module.fail_json(msg='Error getting ssh key [{0}: {1}]'.format( status_code, response.json['message'])) @@ -214,7 +141,7 @@ def core(module): response = account_api.patch('/users/%s' % user_id, data=payload) - if response.status_code in (200, 201): + if response.ok: module.exit_json(changed=True, data=response.json) module.fail_json(msg='Error creating ssh key [{0}: {1}]'.format( @@ -232,7 +159,7 @@ def core(module): response = account_api.patch('/users/%s' % user_id, data=payload) - if response.status_code in (200, 201, 204): + if response.ok: module.exit_json(changed=True, data=response.json) module.fail_json(msg='Error deleting ssh key [{0}: {1}]'.format( diff --git a/test/legacy/scaleway_compute.yml b/test/legacy/scaleway_compute.yml new file mode 100644 index 00000000000..b3697dd099d --- /dev/null +++ b/test/legacy/scaleway_compute.yml @@ -0,0 +1,396 @@ +# SCW_API_KEY='XXX' ansible-playbook ./test/legacy/scaleway_compute.yml + +- name: Test compute instance lifecyle on a Scaleway account + hosts: localhost + gather_facts: no + environment: + SCW_API_KEY: "{{ lookup('env', 'SCW_API_KEY') }}" + + tasks: + + - name: Create a server (Check) + check_mode: yes + scaleway_compute: + name: foobar + state: present + image: 89ee4018-f8c3-4dc4-a6b5-bca14f985ebe + organization: 951df375-e094-4d26-97c1-ba548eeb9c42 + region: ams1 + commercial_type: VC1S + + register: server_creation_check_task + + - debug: var=server_creation_check_task + + - assert: + that: + - server_creation_check_task is success + - server_creation_check_task is changed + + - 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 + wait: true + + register: server_creation_task + + - debug: var=server_creation_task + + - assert: + that: + - server_creation_task is success + - server_creation_task is changed + + - name: Create a server (Confirmation) + scaleway_compute: + name: foobar + state: present + image: 89ee4018-f8c3-4dc4-a6b5-bca14f985ebe + organization: 951df375-e094-4d26-97c1-ba548eeb9c42 + region: ams1 + commercial_type: VC1S + wait: true + + register: server_creation_confirmation_task + + - debug: var=server_creation_confirmation_task + + - assert: + that: + - server_creation_confirmation_task is success + - server_creation_confirmation_task is not changed + + - name: Patch server tags (Check) + check_mode: yes + 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 + register: server_patching_check_task + + - debug: var=server_patching_check_task + + - assert: + that: + - server_patching_check_task is success + - server_patching_check_task is changed + + - name: Patch server tags + scaleway_compute: + name: foobar + state: present + image: 89ee4018-f8c3-4dc4-a6b5-bca14f985ebe + organization: 951df375-e094-4d26-97c1-ba548eeb9c42 + region: ams1 + commercial_type: VC1S + wait: true + tags: + - test + - www + register: server_patching_task + + - debug: var=server_patching_task + + - assert: + that: + - server_patching_task is success + - server_patching_task is changed + + - name: Patch server tags (Confirmation) + scaleway_compute: + name: foobar + state: present + image: 89ee4018-f8c3-4dc4-a6b5-bca14f985ebe + organization: 951df375-e094-4d26-97c1-ba548eeb9c42 + region: ams1 + commercial_type: VC1S + wait: true + tags: + - test + - www + register: server_patching_confirmation_task + + - debug: var=server_patching_confirmation_task + + - assert: + that: + - server_patching_confirmation_task is success + - server_patching_confirmation_task is not changed + + - name: Run it (Check mode) + check_mode: yes + scaleway_compute: + name: foobar + state: running + image: 89ee4018-f8c3-4dc4-a6b5-bca14f985ebe + organization: 951df375-e094-4d26-97c1-ba548eeb9c42 + region: ams1 + commercial_type: VC1S + tags: + - test + - www + register: server_run_check_task + + - debug: var=server_run_check_task + + - assert: + that: + - server_run_check_task is success + - server_run_check_task is changed + + - name: Run it + scaleway_compute: + name: foobar + state: running + image: 89ee4018-f8c3-4dc4-a6b5-bca14f985ebe + organization: 951df375-e094-4d26-97c1-ba548eeb9c42 + region: ams1 + commercial_type: VC1S + wait: true + tags: + - test + - www + register: server_run_task + + - debug: var=server_run_task + + - assert: + that: + - server_run_task is success + - server_run_task is changed + + - name: Run it + scaleway_compute: + name: foobar + state: running + image: 89ee4018-f8c3-4dc4-a6b5-bca14f985ebe + organization: 951df375-e094-4d26-97c1-ba548eeb9c42 + region: ams1 + commercial_type: VC1S + wait: true + tags: + - test + - www + register: server_run_confirmation_task + + - debug: var=server_run_confirmation_task + + - assert: + that: + - server_run_confirmation_task is success + - server_run_confirmation_task is not changed + + - name: Reboot it (Check mode) + check_mode: yes + scaleway_compute: + name: foobar + state: restarted + image: 89ee4018-f8c3-4dc4-a6b5-bca14f985ebe + organization: 951df375-e094-4d26-97c1-ba548eeb9c42 + region: ams1 + commercial_type: VC1S + tags: + - test + - www + register: server_reboot_check_task + + - debug: var=server_reboot_check_task + + - assert: + that: + - server_reboot_check_task is success + - server_reboot_check_task is changed + + - name: Reboot it + scaleway_compute: + name: foobar + state: restarted + image: 89ee4018-f8c3-4dc4-a6b5-bca14f985ebe + organization: 951df375-e094-4d26-97c1-ba548eeb9c42 + region: ams1 + commercial_type: VC1S + wait: true + tags: + - test + - www + register: server_reboot_task + + - debug: var=server_reboot_task + + - assert: + that: + - server_reboot_task is success + - server_reboot_task is changed + + - name: Stop it (Check mode) + check_mode: yes + scaleway_compute: + name: foobar + state: stopped + image: 89ee4018-f8c3-4dc4-a6b5-bca14f985ebe + organization: 951df375-e094-4d26-97c1-ba548eeb9c42 + region: ams1 + commercial_type: VC1S + tags: + - test + - www + register: server_stop_check_task + + - debug: var=server_stop_check_task + + - assert: + that: + - server_stop_check_task is success + - server_stop_check_task is changed + + - name: Stop it + scaleway_compute: + name: foobar + state: stopped + image: 89ee4018-f8c3-4dc4-a6b5-bca14f985ebe + organization: 951df375-e094-4d26-97c1-ba548eeb9c42 + region: ams1 + commercial_type: VC1S + wait: true + tags: + - test + - www + register: server_stop_task + + - debug: var=server_stop_task + + - assert: + that: + - server_stop_task is success + - server_stop_task is changed + + - name: Stop it (Confirmation) + scaleway_compute: + name: foobar + state: stopped + image: 89ee4018-f8c3-4dc4-a6b5-bca14f985ebe + organization: 951df375-e094-4d26-97c1-ba548eeb9c42 + region: ams1 + commercial_type: VC1S + wait: true + tags: + - test + - www + register: server_stop_confirmation_task + + - debug: var=server_stop_confirmation_task + + - assert: + that: + - server_stop_confirmation_task is success + - server_stop_confirmation_task is not changed + + - name: Destroy it (Check mode) + check_mode: yes + scaleway_compute: + name: foobar + state: absent + image: 89ee4018-f8c3-4dc4-a6b5-bca14f985ebe + organization: 951df375-e094-4d26-97c1-ba548eeb9c42 + region: ams1 + commercial_type: VC1S + tags: + - test + - www + register: server_destroy_check_task + + - debug: var=server_destroy_check_task + + - assert: + that: + - server_destroy_check_task is success + - server_destroy_check_task is changed + + - name: Destroy it + scaleway_compute: + name: foobar + state: absent + image: 89ee4018-f8c3-4dc4-a6b5-bca14f985ebe + organization: 951df375-e094-4d26-97c1-ba548eeb9c42 + region: ams1 + commercial_type: VC1S + wait: true + tags: + - test + - www + register: server_destroy_task + + - debug: var=server_destroy_task + + - assert: + that: + - server_destroy_task is success + - server_destroy_task is changed + + - name: Destroy it (Confirmation) + scaleway_compute: + name: foobar + state: absent + image: 89ee4018-f8c3-4dc4-a6b5-bca14f985ebe + organization: 951df375-e094-4d26-97c1-ba548eeb9c42 + region: ams1 + commercial_type: VC1S + wait: true + tags: + - test + - www + register: server_destroy_confirmation_task + + - debug: var=server_destroy_confirmation_task + + - assert: + that: + - server_destroy_confirmation_task is success + - server_destroy_confirmation_task is not changed + + - name: Testing for unauthorized organization + ignore_errors: yes + scaleway_compute: + name: foobar + state: present + image: 89ee4018-f8c3-4dc4-a6b5-bca14f985ebe + organization: this-organization-does-not-exists + region: ams1 + commercial_type: VC1S + register: unauthorized_organization_task + + - debug: var=unauthorized_organization_task + + - assert: + that: + - unauthorized_organization_task is not success + - unauthorized_organization_task is not changed + + - name: Testing for unexisting image + ignore_errors: yes + scaleway_compute: + name: foobar + state: present + image: this-image-does-not-exists + organization: 951df375-e094-4d26-97c1-ba548eeb9c42 + region: ams1 + commercial_type: VC1S + register: unexisting_image_check + + - debug: var=unexisting_image_check + + - assert: + that: + - unexisting_image_check is not success + - unexisting_image_check is not changed