Scaleway modules upgrade

This commit is contained in:
Jack Ivanov 2019-08-16 12:01:34 +02:00
parent 5613003cbe
commit d7f8f9363f
2 changed files with 132 additions and 26 deletions

View file

@ -29,6 +29,15 @@ extends_documentation_fragment: 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
version_added: '2.8'
default: absent
enable_ipv6:
description:
- Enable public IPv6 connectivity on the instance
@ -106,6 +115,13 @@ options:
- 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
version_added: "2.8"
'''
EXAMPLES = '''
@ -121,6 +137,19 @@ EXAMPLES = '''
- 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
@ -141,7 +170,6 @@ from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.six.moves.urllib.parse import quote as urlquote
from ansible.module_utils.scaleway import SCALEWAY_LOCATION, scaleway_argument_spec, Scaleway
SCALEWAY_SERVER_STATES = (
'stopped',
'stopping',
@ -157,6 +185,17 @@ SCALEWAY_TRANSITIONS_STATES = (
)
def check_image_id(compute_api, image_id):
response = compute_api.get(path="images")
if response.ok and response.json:
image_ids = [image["id"] for image in response.json["images"]]
if image_id not in image_ids:
compute_api.module.fail_json(msg='Error in getting image %s on %s' % (image_id, compute_api.module.params.get('api_url')))
else:
compute_api.module.fail_json(msg="Error in getting images from: %s" % compute_api.module.params.get('api_url'))
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"])
@ -195,17 +234,51 @@ def wait_to_complete_state_transition(compute_api, server):
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
response = compute_api.post(path="servers",
data={"enable_ipv6": server["enable_ipv6"],
"boot_type": server["boot_type"],
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"]})
"organization": server["organization"]
}
if server["boot_type"]:
data["boot_type"] = server["boot_type"]
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)
@ -278,7 +351,7 @@ def present_strategy(compute_api, wished_server):
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)
target_server = server_change_attributes(compute_api=compute_api, target_server=target_server, wished_server=wished_server)
return changed, target_server
@ -300,7 +373,7 @@ def absent_strategy(compute_api, wished_server):
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":
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)
@ -341,7 +414,7 @@ def running_strategy(compute_api, wished_server):
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)
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"):
@ -385,7 +458,7 @@ def stop_strategy(compute_api, wished_server):
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)
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)
@ -432,7 +505,7 @@ def restart_strategy(compute_api, wished_server):
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)
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:
@ -471,8 +544,8 @@ state_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)
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)
@ -488,6 +561,7 @@ PATCH_MUTABLE_SERVER_ATTRIBUTES = (
"tags",
"name",
"dynamic_ip_required",
"security_group",
)
@ -499,29 +573,51 @@ def server_attributes_should_be_changed(compute_api, target_server, wished_serve
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])
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((x, wished_server[x])
for x in PATCH_MUTABLE_SERVER_ATTRIBUTES
if x in wished_server and x in target_server)
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 response
return target_server
def core(module):
@ -534,12 +630,19 @@ def core(module):
"enable_ipv6": module.params["enable_ipv6"],
"boot_type": module.params["boot_type"],
"tags": module.params["tags"],
"organization": module.params["organization"]
"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)
@ -552,13 +655,15 @@ def main():
region=dict(required=True, choices=SCALEWAY_LOCATION.keys()),
commercial_type=dict(required=True),
enable_ipv6=dict(default=False, type="bool"),
boot_type=dict(default="bootscript"),
boot_type=dict(choices=['bootscript', 'local']),
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,

View file

@ -24,6 +24,7 @@
scaleway_compute:
name: "{{ algo_server_name }}"
enable_ipv6: true
public_ip: dynamic
boot_type: local
state: running
image: "{{ images[0] }}"