diff --git a/lib/ansible/module_utils/scaleway.py b/lib/ansible/module_utils/scaleway.py index d15c9efc56d..762ceed8062 100644 --- a/lib/ansible/module_utils/scaleway.py +++ b/lib/ansible/module_utils/scaleway.py @@ -76,3 +76,12 @@ class ScalewayAPI(object): def update(self, path, data=None, headers=None): return self.send("UPDATE", path, data, headers) + + +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'} +} diff --git a/lib/ansible/modules/cloud/scaleway/scaleway_compute.py b/lib/ansible/modules/cloud/scaleway/scaleway_compute.py index a9090849206..09ac2fb2633 100644 --- a/lib/ansible/modules/cloud/scaleway/scaleway_compute.py +++ b/lib/ansible/modules/cloud/scaleway/scaleway_compute.py @@ -160,7 +160,7 @@ 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 +from ansible.module_utils.scaleway import ScalewayAPI, SCALEWAY_LOCATION SCALEWAY_COMMERCIAL_TYPES = [ @@ -189,13 +189,6 @@ SCALEWAY_COMMERCIAL_TYPES = [ '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', diff --git a/lib/ansible/plugins/inventory/scaleway.py b/lib/ansible/plugins/inventory/scaleway.py new file mode 100644 index 00000000000..82f6ca0ed48 --- /dev/null +++ b/lib/ansible/plugins/inventory/scaleway.py @@ -0,0 +1,151 @@ +# Copyright (c) 2017 Ansible Project +# 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 + +DOCUMENTATION = ''' + name: scaleway + plugin_type: inventory + authors: + - Remy Leone + short_description: Scaleway inventory source + description: + - Get inventory hosts from Scaleway + options: + regions: + description: Filter results on a specific Scaleway region + type: list + default: + - ams1 + - par1 + tags: + description: Filter results on a specific tag + type: list + oauth_token: + description: Scaleway OAuth token. + env: + # in order of precedence + - name: SCW_TOKEN + - name: SCW_API_KEY + - name: SCW_OAUTH_TOKEN +''' + +EXAMPLES = ''' +# scaleway_inventory.yml file in YAML format +# Example command line: ansible-inventory --list -i scaleway_inventory.yml + +plugin: scaleway +regions: + - ams1 + - par1 +tags: + - foobar +''' + +import json +import os + +from ansible.errors import AnsibleError +from ansible.plugins.inventory import BaseInventoryPlugin +from ansible.module_utils.scaleway import SCALEWAY_LOCATION +from ansible.module_utils.urls import open_url + + +def _fetch_information(token, url): + try: + response = open_url(url, + headers={'X-Auth-Token': token, + 'Content-type': 'application/json'}) + except Exception: + raise AnsibleError("Error while fetching %s" % url) + + try: + raw_json = json.loads(response.read()) + except ValueError: + raise AnsibleError("Incorrect JSON payload") + + try: + return raw_json["servers"] + except KeyError: + raise AnsibleError("Incorrect format from the Scaleway API response") + + +def _build_server_url(api_endpoint): + return "/".join([api_endpoint, "servers"]) + + +class InventoryModule(BaseInventoryPlugin): + NAME = 'scaleway' + + def __init__(self): + super(InventoryModule, self).__init__() + + self.token = self.get_option("oauth_token") + self.config_data = None + + def verify_file(self, path): + return "scaleway" in path + + def _fill_host_variables(self, server_id, server_info): + targeted_attributes = ( + "arch", + "commercial_type", + "organization", + "state", + "hostname", + "state" + ) + for attribute in targeted_attributes: + self.inventory.set_variable(server_id, attribute, server_info[attribute]) + + self.inventory.set_variable(server_id, "tags", server_info["tags"]) + self.inventory.set_variable(server_id, "ipv4", server_info["public_ip"]["address"]) + + def _get_zones(self): + config_zones = self.get_option("regions") + return set(SCALEWAY_LOCATION.keys()).intersection(config_zones) + + def _get_tags(self): + return self.get_option("tags") + + def match_groups(self, server_info): + server_zone = server_info["location"]["zone_id"] + server_tags = server_info["tags"] + + # If no filtering is defined, all tags are valid groups + if self._get_tags() is None: + return set(server_tags).union((server_zone,)) + + matching_tags = set(server_tags).intersection(self._get_tags()) + + if not matching_tags: + return set() + else: + return matching_tags.union((server_zone,)) + + def do_zone_inventory(self, zone): + self.inventory.add_group(zone) + zone_info = SCALEWAY_LOCATION[zone] + + url = _build_server_url(zone_info["api_endpoint"]) + all_servers = _fetch_information(url=url, token=self.token) + + for server_info in all_servers: + + groups = self.match_groups(server_info) + print(groups) + server_id = server_info["id"] + + for group in groups: + self.inventory.add_group(group=group) + self.inventory.add_host(group=group, host=server_id) + self._fill_host_variables(server_id=server_id, server_info=server_info) + + def parse(self, inventory, loader, path, cache=True): + super(InventoryModule, self).parse(inventory, loader, path) + self.config_data = self._read_config_data(path=path) + + for zone in self._get_zones(): + self.do_zone_inventory(zone=zone)