From c1b5b51366a5355f014967ac39fd5dd0bda69373 Mon Sep 17 00:00:00 2001 From: Felix Fontein Date: Tue, 7 Jul 2020 16:41:16 +0200 Subject: [PATCH] Remove DigitalOcean modules (moved to community.digitalocean) (#622) * Remove DigitalOcean modules. * Remove inventory scripts. --- .github/BOTMETA.yml | 28 - changelogs/fragments/digital-ocean.yml | 2 + meta/runtime.yml | 179 +++++- plugins/doc_fragments/digital_ocean.py | 33 -- plugins/module_utils/digital_ocean.py | 131 ----- .../cloud/digital_ocean/digital_ocean.py | 475 --------------- .../digital_ocean_account_facts.py | 1 - .../digital_ocean_account_info.py | 81 --- .../digital_ocean_block_storage.py | 283 --------- .../digital_ocean_certificate.py | 169 ------ .../digital_ocean_certificate_facts.py | 1 - .../digital_ocean_certificate_info.py | 113 ---- .../digital_ocean/digital_ocean_domain.py | 214 ------- .../digital_ocean_domain_facts.py | 1 - .../digital_ocean_domain_info.py | 138 ----- .../digital_ocean/digital_ocean_droplet.py | 351 ------------ .../digital_ocean_firewall_facts.py | 1 - .../digital_ocean_firewall_info.py | 131 ----- .../digital_ocean_floating_ip.py | 311 ---------- .../digital_ocean_floating_ip_facts.py | 1 - .../digital_ocean_floating_ip_info.py | 119 ---- .../digital_ocean_image_facts.py | 1 - .../digital_ocean/digital_ocean_image_info.py | 148 ----- .../digital_ocean_load_balancer_facts.py | 1 - .../digital_ocean_load_balancer_info.py | 115 ---- .../digital_ocean_region_facts.py | 1 - .../digital_ocean_region_info.py | 115 ---- .../digital_ocean/digital_ocean_size_facts.py | 1 - .../digital_ocean/digital_ocean_size_info.py | 113 ---- .../digital_ocean_snapshot_facts.py | 1 - .../digital_ocean_snapshot_info.py | 160 ------ .../digital_ocean/digital_ocean_sshkey.py | 257 --------- .../digital_ocean_sshkey_facts.py | 101 ---- .../digital_ocean_sshkey_info.py | 92 --- .../cloud/digital_ocean/digital_ocean_tag.py | 205 ------- .../digital_ocean/digital_ocean_tag_facts.py | 1 - .../digital_ocean/digital_ocean_tag_info.py | 115 ---- .../digital_ocean_volume_facts.py | 1 - .../digital_ocean_volume_info.py | 140 ----- plugins/modules/digital_ocean.py | 1 - .../modules/digital_ocean_account_facts.py | 1 - plugins/modules/digital_ocean_account_info.py | 1 - .../modules/digital_ocean_block_storage.py | 1 - plugins/modules/digital_ocean_certificate.py | 1 - .../digital_ocean_certificate_facts.py | 1 - .../modules/digital_ocean_certificate_info.py | 1 - plugins/modules/digital_ocean_domain.py | 1 - plugins/modules/digital_ocean_domain_facts.py | 1 - plugins/modules/digital_ocean_domain_info.py | 1 - plugins/modules/digital_ocean_droplet.py | 1 - .../modules/digital_ocean_firewall_facts.py | 1 - .../modules/digital_ocean_firewall_info.py | 1 - plugins/modules/digital_ocean_floating_ip.py | 1 - .../digital_ocean_floating_ip_facts.py | 1 - .../modules/digital_ocean_floating_ip_info.py | 1 - plugins/modules/digital_ocean_image_facts.py | 1 - plugins/modules/digital_ocean_image_info.py | 1 - .../digital_ocean_load_balancer_facts.py | 1 - .../digital_ocean_load_balancer_info.py | 1 - plugins/modules/digital_ocean_region_facts.py | 1 - plugins/modules/digital_ocean_region_info.py | 1 - plugins/modules/digital_ocean_size_facts.py | 1 - plugins/modules/digital_ocean_size_info.py | 1 - .../modules/digital_ocean_snapshot_facts.py | 1 - .../modules/digital_ocean_snapshot_info.py | 1 - plugins/modules/digital_ocean_sshkey.py | 1 - plugins/modules/digital_ocean_sshkey_facts.py | 1 - plugins/modules/digital_ocean_sshkey_info.py | 1 - plugins/modules/digital_ocean_tag.py | 1 - plugins/modules/digital_ocean_tag_facts.py | 1 - plugins/modules/digital_ocean_tag_info.py | 1 - plugins/modules/digital_ocean_volume_facts.py | 1 - plugins/modules/digital_ocean_volume_info.py | 1 - scripts/inventory/digital_ocean.ini | 34 -- scripts/inventory/digital_ocean.py | 541 ------------------ .../targets/digital_ocean_floating_ip/aliases | 1 - .../digital_ocean_floating_ip/tasks/main.yml | 42 -- .../targets/digital_ocean_sshkey/aliases | 1 - .../digital_ocean_sshkey/tasks/main.yml | 29 - .../targets/digital_ocean_tag/aliases | 2 - .../targets/digital_ocean_tag/tasks/main.yml | 51 -- tests/sanity/ignore-2.10.txt | 34 -- tests/sanity/ignore-2.11.txt | 34 -- tests/sanity/ignore-2.9.txt | 31 - 84 files changed, 154 insertions(+), 5011 deletions(-) create mode 100644 changelogs/fragments/digital-ocean.yml delete mode 100644 plugins/doc_fragments/digital_ocean.py delete mode 100644 plugins/module_utils/digital_ocean.py delete mode 100644 plugins/modules/cloud/digital_ocean/digital_ocean.py delete mode 120000 plugins/modules/cloud/digital_ocean/digital_ocean_account_facts.py delete mode 100644 plugins/modules/cloud/digital_ocean/digital_ocean_account_info.py delete mode 100644 plugins/modules/cloud/digital_ocean/digital_ocean_block_storage.py delete mode 100644 plugins/modules/cloud/digital_ocean/digital_ocean_certificate.py delete mode 120000 plugins/modules/cloud/digital_ocean/digital_ocean_certificate_facts.py delete mode 100644 plugins/modules/cloud/digital_ocean/digital_ocean_certificate_info.py delete mode 100644 plugins/modules/cloud/digital_ocean/digital_ocean_domain.py delete mode 120000 plugins/modules/cloud/digital_ocean/digital_ocean_domain_facts.py delete mode 100644 plugins/modules/cloud/digital_ocean/digital_ocean_domain_info.py delete mode 100644 plugins/modules/cloud/digital_ocean/digital_ocean_droplet.py delete mode 120000 plugins/modules/cloud/digital_ocean/digital_ocean_firewall_facts.py delete mode 100644 plugins/modules/cloud/digital_ocean/digital_ocean_firewall_info.py delete mode 100644 plugins/modules/cloud/digital_ocean/digital_ocean_floating_ip.py delete mode 120000 plugins/modules/cloud/digital_ocean/digital_ocean_floating_ip_facts.py delete mode 100644 plugins/modules/cloud/digital_ocean/digital_ocean_floating_ip_info.py delete mode 120000 plugins/modules/cloud/digital_ocean/digital_ocean_image_facts.py delete mode 100644 plugins/modules/cloud/digital_ocean/digital_ocean_image_info.py delete mode 120000 plugins/modules/cloud/digital_ocean/digital_ocean_load_balancer_facts.py delete mode 100644 plugins/modules/cloud/digital_ocean/digital_ocean_load_balancer_info.py delete mode 120000 plugins/modules/cloud/digital_ocean/digital_ocean_region_facts.py delete mode 100644 plugins/modules/cloud/digital_ocean/digital_ocean_region_info.py delete mode 120000 plugins/modules/cloud/digital_ocean/digital_ocean_size_facts.py delete mode 100644 plugins/modules/cloud/digital_ocean/digital_ocean_size_info.py delete mode 120000 plugins/modules/cloud/digital_ocean/digital_ocean_snapshot_facts.py delete mode 100644 plugins/modules/cloud/digital_ocean/digital_ocean_snapshot_info.py delete mode 100644 plugins/modules/cloud/digital_ocean/digital_ocean_sshkey.py delete mode 100644 plugins/modules/cloud/digital_ocean/digital_ocean_sshkey_facts.py delete mode 100644 plugins/modules/cloud/digital_ocean/digital_ocean_sshkey_info.py delete mode 100644 plugins/modules/cloud/digital_ocean/digital_ocean_tag.py delete mode 120000 plugins/modules/cloud/digital_ocean/digital_ocean_tag_facts.py delete mode 100644 plugins/modules/cloud/digital_ocean/digital_ocean_tag_info.py delete mode 120000 plugins/modules/cloud/digital_ocean/digital_ocean_volume_facts.py delete mode 100644 plugins/modules/cloud/digital_ocean/digital_ocean_volume_info.py delete mode 120000 plugins/modules/digital_ocean.py delete mode 120000 plugins/modules/digital_ocean_account_facts.py delete mode 120000 plugins/modules/digital_ocean_account_info.py delete mode 120000 plugins/modules/digital_ocean_block_storage.py delete mode 120000 plugins/modules/digital_ocean_certificate.py delete mode 120000 plugins/modules/digital_ocean_certificate_facts.py delete mode 120000 plugins/modules/digital_ocean_certificate_info.py delete mode 120000 plugins/modules/digital_ocean_domain.py delete mode 120000 plugins/modules/digital_ocean_domain_facts.py delete mode 120000 plugins/modules/digital_ocean_domain_info.py delete mode 120000 plugins/modules/digital_ocean_droplet.py delete mode 120000 plugins/modules/digital_ocean_firewall_facts.py delete mode 120000 plugins/modules/digital_ocean_firewall_info.py delete mode 120000 plugins/modules/digital_ocean_floating_ip.py delete mode 120000 plugins/modules/digital_ocean_floating_ip_facts.py delete mode 120000 plugins/modules/digital_ocean_floating_ip_info.py delete mode 120000 plugins/modules/digital_ocean_image_facts.py delete mode 120000 plugins/modules/digital_ocean_image_info.py delete mode 120000 plugins/modules/digital_ocean_load_balancer_facts.py delete mode 120000 plugins/modules/digital_ocean_load_balancer_info.py delete mode 120000 plugins/modules/digital_ocean_region_facts.py delete mode 120000 plugins/modules/digital_ocean_region_info.py delete mode 120000 plugins/modules/digital_ocean_size_facts.py delete mode 120000 plugins/modules/digital_ocean_size_info.py delete mode 120000 plugins/modules/digital_ocean_snapshot_facts.py delete mode 120000 plugins/modules/digital_ocean_snapshot_info.py delete mode 120000 plugins/modules/digital_ocean_sshkey.py delete mode 120000 plugins/modules/digital_ocean_sshkey_facts.py delete mode 120000 plugins/modules/digital_ocean_sshkey_info.py delete mode 120000 plugins/modules/digital_ocean_tag.py delete mode 120000 plugins/modules/digital_ocean_tag_facts.py delete mode 120000 plugins/modules/digital_ocean_tag_info.py delete mode 120000 plugins/modules/digital_ocean_volume_facts.py delete mode 120000 plugins/modules/digital_ocean_volume_info.py delete mode 100644 scripts/inventory/digital_ocean.ini delete mode 100644 scripts/inventory/digital_ocean.py delete mode 100644 tests/integration/targets/digital_ocean_floating_ip/aliases delete mode 100644 tests/integration/targets/digital_ocean_floating_ip/tasks/main.yml delete mode 100644 tests/integration/targets/digital_ocean_sshkey/aliases delete mode 100644 tests/integration/targets/digital_ocean_sshkey/tasks/main.yml delete mode 100644 tests/integration/targets/digital_ocean_tag/aliases delete mode 100644 tests/integration/targets/digital_ocean_tag/tasks/main.yml diff --git a/.github/BOTMETA.yml b/.github/BOTMETA.yml index a91ccffb3d..4ec1cdc8e1 100644 --- a/.github/BOTMETA.yml +++ b/.github/BOTMETA.yml @@ -196,33 +196,6 @@ files: authors: krsacme $modules/cloud/centurylink/: authors: clc-runner - $modules/cloud/digital_ocean/digital_ocean.py: - authors: zbal - $modules/cloud/digital_ocean/: - authors: Akasurde - maintainers: $team_digital_ocean - keywords: - - digital ocean - - droplet - $modules/cloud/digital_ocean/digital_ocean_firewall_facts.py: - authors: BondAnthony - maintainers: mgregson - $modules/cloud/digital_ocean/digital_ocean_floating_ip_facts.py: - authors: pmarques - $modules/cloud/digital_ocean/digital_ocean_sshkey_facts.py: - authors: pmarques - $modules/cloud/digital_ocean/digital_ocean_block_storage.py: - authors: harneksidhu - $modules/cloud/digital_ocean/digital_ocean_domain.py: - authors: mgregson - maintainers: BondAnthony - $modules/cloud/digital_ocean/digital_ocean_droplet.py: - authors: gurch101 - $modules/cloud/digital_ocean/digital_ocean_firewall_info.py: - authors: BondAnthony - maintainers: mgregson - $modules/cloud/digital_ocean/digital_ocean_tag.py: - authors: kontrafiktion $modules/cloud/dimensiondata/dimensiondata_network.py: authors: aimonb maintainers: tintoy @@ -1355,7 +1328,6 @@ macros: team_aix: MorrisA bcoca d-little flynn1973 gforster kairoaraujo marvin-sinister mator molekuul ramooncamacho wtcross team_bsd: JoergFiedler MacLemon bcoca dch jasperla mekanix opoplawski overhacked tuxillo team_cyberark_conjur: jvanderhoof ryanprior - team_digital_ocean: BondAnthony mgregson team_docker: DBendit WojciechowskiPiotr akshay196 danihodovic dariko felixfontein jwitko kassiansun tbouvet team_e_spirit: MatrixCrawler getjack team_extreme: LindsayHill bigmstone ujwalkomarla diff --git a/changelogs/fragments/digital-ocean.yml b/changelogs/fragments/digital-ocean.yml new file mode 100644 index 0000000000..a8870cbc1a --- /dev/null +++ b/changelogs/fragments/digital-ocean.yml @@ -0,0 +1,2 @@ +removed_features: +- "digital_ocean_* - all DigitalOcean modules have been moved to the ``community.digitalocean`` collection. A redirection is active, which will be removed in version 2.0.0 (https://github.com/ansible-collections/community.general/pull/622)." \ No newline at end of file diff --git a/meta/runtime.yml b/meta/runtime.yml index c2c81a2861..1ff5ba7fc6 100644 --- a/meta/runtime.yml +++ b/meta/runtime.yml @@ -71,59 +71,173 @@ plugin_routing: digital_ocean: deprecation: removal_version: 2.0.0 - warning_text: see plugin documentation for details + warning_text: The digital_ocean module has been moved to the community.digitalocean collection. + redirect: community.digitalocean.digital_ocean digital_ocean_account_facts: deprecation: - removal_version: 3.0.0 - warning_text: see plugin documentation for details + removal_version: 2.0.0 + warning_text: The digital_ocean_account_facts module has been moved to the community.digitalocean collection. + redirect: community.digitalocean.digital_ocean_account_facts + digital_ocean_account_info: + deprecation: + removal_version: 2.0.0 + warning_text: The digital_ocean_account_info module has been moved to the community.digitalocean collection. + redirect: community.digitalocean.digital_ocean_account_info + digital_ocean_block_storage: + deprecation: + removal_version: 2.0.0 + warning_text: The digital_ocean_block_storage module has been moved to the community.digitalocean collection. + redirect: community.digitalocean.digital_ocean_block_storage + digital_ocean_certificate: + deprecation: + removal_version: 2.0.0 + warning_text: The digital_ocean_certificate module has been moved to the community.digitalocean collection. + redirect: community.digitalocean.digital_ocean_certificate digital_ocean_certificate_facts: deprecation: - removal_version: 3.0.0 - warning_text: see plugin documentation for details + removal_version: 2.0.0 + warning_text: The digital_ocean_certificate_facts module has been moved to the community.digitalocean collection. + redirect: community.digitalocean.digital_ocean_certificate_facts + digital_ocean_certificate_info: + deprecation: + removal_version: 2.0.0 + warning_text: The digital_ocean_certificate_info module has been moved to the community.digitalocean collection. + redirect: community.digitalocean.digital_ocean_certificate_info + digital_ocean_domain: + deprecation: + removal_version: 2.0.0 + warning_text: The digital_ocean_domain module has been moved to the community.digitalocean collection. + redirect: community.digitalocean.digital_ocean_domain digital_ocean_domain_facts: deprecation: - removal_version: 3.0.0 - warning_text: see plugin documentation for details + removal_version: 2.0.0 + warning_text: The digital_ocean_domain_facts module has been moved to the community.digitalocean collection. + redirect: community.digitalocean.digital_ocean_domain_facts + digital_ocean_domain_info: + deprecation: + removal_version: 2.0.0 + warning_text: The digital_ocean_domain_info module has been moved to the community.digitalocean collection. + redirect: community.digitalocean.digital_ocean_domain_info + digital_ocean_droplet: + deprecation: + removal_version: 2.0.0 + warning_text: The digital_ocean_droplet module has been moved to the community.digitalocean collection. + redirect: community.digitalocean.digital_ocean_droplet digital_ocean_firewall_facts: deprecation: - removal_version: 3.0.0 - warning_text: see plugin documentation for details + removal_version: 2.0.0 + warning_text: The digital_ocean_firewall_facts module has been moved to the community.digitalocean collection. + redirect: community.digitalocean.digital_ocean_firewall_facts + digital_ocean_firewall_info: + deprecation: + removal_version: 2.0.0 + warning_text: The digital_ocean_firewall_info module has been moved to the community.digitalocean collection. + redirect: community.digitalocean.digital_ocean_firewall_info + digital_ocean_floating_ip: + deprecation: + removal_version: 2.0.0 + warning_text: The digital_ocean_floating_ip module has been moved to the community.digitalocean collection. + redirect: community.digitalocean.digital_ocean_floating_ip digital_ocean_floating_ip_facts: deprecation: - removal_version: 3.0.0 - warning_text: see plugin documentation for details + removal_version: 2.0.0 + warning_text: The digital_ocean_floating_ip_facts module has been moved to the community.digitalocean collection. + redirect: community.digitalocean.digital_ocean_floating_ip_facts + digital_ocean_floating_ip_info: + deprecation: + removal_version: 2.0.0 + warning_text: The digital_ocean_floating_ip_info module has been moved to the community.digitalocean collection. + redirect: community.digitalocean.digital_ocean_floating_ip_info digital_ocean_image_facts: deprecation: - removal_version: 3.0.0 - warning_text: see plugin documentation for details + removal_version: 2.0.0 + warning_text: The digital_ocean_image_facts module has been moved to the community.digitalocean collection. + redirect: community.digitalocean.digital_ocean_image_facts + digital_ocean_image_info: + deprecation: + removal_version: 2.0.0 + warning_text: The digital_ocean_image_info module has been moved to the community.digitalocean collection. + redirect: community.digitalocean.digital_ocean_image_info digital_ocean_load_balancer_facts: deprecation: - removal_version: 3.0.0 - warning_text: see plugin documentation for details + removal_version: 2.0.0 + warning_text: The digital_ocean_load_balancer_facts module has been moved to the community.digitalocean collection. + redirect: community.digitalocean.digital_ocean_load_balancer_facts + digital_ocean_load_balancer_info: + deprecation: + removal_version: 2.0.0 + warning_text: The digital_ocean_load_balancer_info module has been moved to the community.digitalocean collection. + redirect: community.digitalocean.digital_ocean_load_balancer_info digital_ocean_region_facts: deprecation: - removal_version: 3.0.0 - warning_text: see plugin documentation for details + removal_version: 2.0.0 + warning_text: The digital_ocean_region_facts module has been moved to the community.digitalocean collection. + redirect: community.digitalocean.digital_ocean_region_facts + digital_ocean_region_info: + deprecation: + removal_version: 2.0.0 + warning_text: The digital_ocean_region_info module has been moved to the community.digitalocean collection. + redirect: community.digitalocean.digital_ocean_region_info digital_ocean_size_facts: deprecation: - removal_version: 3.0.0 - warning_text: see plugin documentation for details + removal_version: 2.0.0 + warning_text: The digital_ocean_size_facts module has been moved to the community.digitalocean collection. + redirect: community.digitalocean.digital_ocean_size_facts + digital_ocean_size_info: + deprecation: + removal_version: 2.0.0 + warning_text: The digital_ocean_size_info module has been moved to the community.digitalocean collection. + redirect: community.digitalocean.digital_ocean_size_info digital_ocean_snapshot_facts: deprecation: - removal_version: 3.0.0 - warning_text: see plugin documentation for details + removal_version: 2.0.0 + warning_text: The digital_ocean_snapshot_facts module has been moved to the community.digitalocean collection. + redirect: community.digitalocean.digital_ocean_snapshot_facts + digital_ocean_snapshot_info: + deprecation: + removal_version: 2.0.0 + warning_text: The digital_ocean_snapshot_info module has been moved to the community.digitalocean collection. + redirect: community.digitalocean.digital_ocean_snapshot_info + digital_ocean_sshkey: + deprecation: + removal_version: 2.0.0 + warning_text: The digital_ocean_sshkey module has been moved to the community.digitalocean collection. + redirect: community.digitalocean.digital_ocean_sshkey digital_ocean_sshkey_facts: deprecation: - removal_version: 3.0.0 - warning_text: see plugin documentation for details + removal_version: 2.0.0 + warning_text: The digital_ocean_sshkey_facts module has been moved to the community.digitalocean collection. + redirect: community.digitalocean.digital_ocean_sshkey_facts + digital_ocean_sshkey_info: + deprecation: + removal_version: 2.0.0 + warning_text: The digital_ocean_sshkey_info module has been moved to the community.digitalocean collection. + redirect: community.digitalocean.digital_ocean_sshkey_info + digital_ocean_tag: + deprecation: + removal_version: 2.0.0 + warning_text: The digital_ocean_tag module has been moved to the community.digitalocean collection. + redirect: community.digitalocean.digital_ocean_tag digital_ocean_tag_facts: deprecation: - removal_version: 3.0.0 - warning_text: see plugin documentation for details + removal_version: 2.0.0 + warning_text: The digital_ocean_tag_facts module has been moved to the community.digitalocean collection. + redirect: community.digitalocean.digital_ocean_tag_facts + digital_ocean_tag_info: + deprecation: + removal_version: 2.0.0 + warning_text: The digital_ocean_tag_info module has been moved to the community.digitalocean collection. + redirect: community.digitalocean.digital_ocean_tag_info digital_ocean_volume_facts: deprecation: - removal_version: 3.0.0 - warning_text: see plugin documentation for details + removal_version: 2.0.0 + warning_text: The digital_ocean_volume_facts module has been moved to the community.digitalocean collection. + redirect: community.digitalocean.digital_ocean_volume_facts + digital_ocean_volume_info: + deprecation: + removal_version: 2.0.0 + warning_text: The digital_ocean_volume_info module has been moved to the community.digitalocean collection. + redirect: community.digitalocean.digital_ocean_volume_info docker_image_facts: deprecation: removal_version: 2.0.0 @@ -508,8 +622,19 @@ plugin_routing: removal_version: 1.0.0 warning_text: The logicmonitor_facts module is no longer maintained and the API used has been disabled in 2017. doc_fragments: + digital_ocean: + deprecation: + removal_version: 2.0.0 + warning_text: The digital_ocean docs_fragment has been moved to the community.digitalocean collection. + redirect: community.digitalocean.digital_ocean proxysql: deprecation: removal_version: 2.0.0 warning_text: The proxysql docs_fragment has been moved to the community.proxysql collection. redirect: community.proxysql.proxysql + module_utils: + digital_ocean: + deprecation: + removal_version: 2.0.0 + warning_text: The digital_ocean module_utils has been moved to the community.digitalocean collection. + redirect: community.digitalocean.digital_ocean diff --git a/plugins/doc_fragments/digital_ocean.py b/plugins/doc_fragments/digital_ocean.py deleted file mode 100644 index 5759d17b51..0000000000 --- a/plugins/doc_fragments/digital_ocean.py +++ /dev/null @@ -1,33 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright: (c) 2018, Ansible Project -# Copyright: (c) 2018, Abhijeet Kasurde (akasurde@redhat.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 - - -class ModuleDocFragment(object): - # Parameters for DigitalOcean modules - DOCUMENTATION = r''' -options: - oauth_token: - description: - - DigitalOcean OAuth token. - - "There are several other environment variables which can be used to provide this value." - - "i.e., - 'DO_API_TOKEN', 'DO_API_KEY', 'DO_OAUTH_TOKEN' and 'OAUTH_TOKEN'" - type: str - aliases: [ api_token ] - timeout: - description: - - The timeout in seconds used for polling DigitalOcean's API. - type: int - default: 30 - validate_certs: - description: - - If set to C(no), the SSL certificates will not be validated. - - This should only set to C(no) used on personally controlled sites using self-signed certificates. - type: bool - default: yes -''' diff --git a/plugins/module_utils/digital_ocean.py b/plugins/module_utils/digital_ocean.py deleted file mode 100644 index 53c731eea1..0000000000 --- a/plugins/module_utils/digital_ocean.py +++ /dev/null @@ -1,131 +0,0 @@ -# This code is part of Ansible, but is an independent component. -# This particular file snippet, and this file snippet only, is BSD licensed. -# Modules you write using this snippet, which is embedded dynamically by Ansible -# still belong to the author of the module, and may assign their own license -# to the complete work. -# -# Copyright (c), Ansible Project 2017 -# Simplified BSD License (see licenses/simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause) - -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - -import json -import os -from ansible.module_utils.urls import fetch_url -from ansible.module_utils._text import to_text -from ansible.module_utils.basic import env_fallback - - -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(to_text(self.info["body"])) - return None - try: - return json.loads(to_text(self.body)) - except ValueError: - return None - - @property - def status_code(self): - return self.info["status"] - - -class DigitalOceanHelper: - - def __init__(self, module): - self.module = module - self.baseurl = 'https://api.digitalocean.com/v2' - self.timeout = module.params.get('timeout', 30) - self.oauth_token = module.params.get('oauth_token') - self.headers = {'Authorization': 'Bearer {0}'.format(self.oauth_token), - 'Content-type': 'application/json'} - - # Check if api_token is valid or not - response = self.get('account') - if response.status_code == 401: - self.module.fail_json(msg='Failed to login using API token, please verify validity of API token.') - - def _url_builder(self, path): - if path[0] == '/': - path = path[1:] - return '%s/%s' % (self.baseurl, path) - - def send(self, method, path, data=None): - url = self._url_builder(path) - data = self.module.jsonify(data) - - resp, info = fetch_url(self.module, url, data=data, headers=self.headers, method=method, timeout=self.timeout) - - return Response(resp, info) - - def get(self, path, data=None): - return self.send('GET', path, data) - - def put(self, path, data=None): - return self.send('PUT', path, data) - - def post(self, path, data=None): - return self.send('POST', path, data) - - def delete(self, path, data=None): - return self.send('DELETE', path, data) - - @staticmethod - def digital_ocean_argument_spec(): - return dict( - validate_certs=dict(type='bool', required=False, default=True), - oauth_token=dict( - no_log=True, - # Support environment variable for DigitalOcean OAuth Token - fallback=(env_fallback, ['DO_API_TOKEN', 'DO_API_KEY', 'DO_OAUTH_TOKEN', 'OAUTH_TOKEN']), - required=False, - aliases=['api_token'], - ), - timeout=dict(type='int', default=30), - ) - - def get_paginated_data(self, base_url=None, data_key_name=None, data_per_page=40, expected_status_code=200): - """ - Function to get all paginated data from given URL - Args: - base_url: Base URL to get data from - data_key_name: Name of data key value - data_per_page: Number results per page (Default: 40) - expected_status_code: Expected returned code from DigitalOcean (Default: 200) - Returns: List of data - - """ - page = 1 - has_next = True - ret_data = [] - status_code = None - response = None - while has_next or status_code != expected_status_code: - required_url = "{0}page={1}&per_page={2}".format(base_url, page, data_per_page) - response = self.get(required_url) - status_code = response.status_code - # stop if any error during pagination - if status_code != expected_status_code: - break - page += 1 - ret_data.extend(response.json[data_key_name]) - has_next = "pages" in response.json["links"] and "next" in response.json["links"]["pages"] - - if status_code != expected_status_code: - msg = "Failed to fetch %s from %s" % (data_key_name, base_url) - if response: - msg += " due to error : %s" % response.json['message'] - self.module.fail_json(msg=msg) - - return ret_data diff --git a/plugins/modules/cloud/digital_ocean/digital_ocean.py b/plugins/modules/cloud/digital_ocean/digital_ocean.py deleted file mode 100644 index dd555f599f..0000000000 --- a/plugins/modules/cloud/digital_ocean/digital_ocean.py +++ /dev/null @@ -1,475 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -# -# Copyright: 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 = ''' ---- -module: digital_ocean -short_description: Create/delete a droplet/SSH_key in DigitalOcean -deprecated: - removed_in: 2.0.0 # was Ansible 2.12 - why: Updated module to remove external dependency with increased functionality. - alternative: Use M(community.general.digital_ocean_droplet) instead. -description: - - Create/delete a droplet in DigitalOcean and optionally wait for it to be 'running', or deploy an SSH key. -author: "Vincent Viallet (@zbal)" -options: - command: - description: - - Which target you want to operate on. - default: droplet - choices: ['droplet', 'ssh'] - state: - description: - - Indicate desired state of the target. - default: present - choices: ['present', 'active', 'absent', 'deleted'] - api_token: - description: - - DigitalOcean api token. - id: - description: - - Numeric, the droplet id you want to operate on. - aliases: ['droplet_id'] - name: - description: - - String, this is the name of the droplet - must be formatted by hostname rules, or the name of a SSH key. - unique_name: - description: - - Bool, require unique hostnames. By default, DigitalOcean allows multiple hosts with the same name. Setting this to "yes" allows only one host - per name. Useful for idempotence. - type: bool - default: 'no' - size_id: - description: - - This is the slug of the size you would like the droplet created with. - image_id: - description: - - This is the slug of the image you would like the droplet created with. - region_id: - description: - - This is the slug of the region you would like your server to be created in. - ssh_key_ids: - description: - - Optional, array of SSH key (numeric) ID that you would like to be added to the server. - virtio: - description: - - "Bool, turn on virtio driver in droplet for improved network and storage I/O." - type: bool - default: 'yes' - private_networking: - description: - - "Bool, add an additional, private network interface to droplet for inter-droplet communication." - type: bool - default: 'no' - backups_enabled: - description: - - Optional, Boolean, enables backups for your droplet. - type: bool - default: 'no' - user_data: - description: - - opaque blob of data which is made available to the droplet - ipv6: - description: - - Optional, Boolean, enable IPv6 for your droplet. - type: bool - default: 'no' - wait: - description: - - Wait for the droplet to be in state 'running' before returning. If wait is "no" an ip_address may not be returned. - type: bool - default: 'yes' - wait_timeout: - description: - - How long before wait gives up, in seconds. - default: 300 - ssh_pub_key: - description: - - The public SSH key you want to add to your account. - -notes: - - Two environment variables can be used, DO_API_KEY and DO_API_TOKEN. They both refer to the v2 token. - - As of Ansible 1.9.5 and 2.0, Version 2 of the DigitalOcean API is used, this removes C(client_id) and C(api_key) options in favor of C(api_token). - - If you are running Ansible 1.9.4 or earlier you might not be able to use the included version of this module as the API version used has been retired. - Upgrade Ansible or, if unable to, try downloading the latest version of this module from github and putting it into a 'library' directory. -requirements: - - "python >= 2.6" - - dopy -''' - - -EXAMPLES = ''' -# Ensure a SSH key is present -# If a key matches this name, will return the ssh key id and changed = False -# If no existing key matches this name, a new key is created, the ssh key id is returned and changed = False - -- name: Ensure a SSH key is present - digital_ocean: - state: present - command: ssh - name: my_ssh_key - ssh_pub_key: 'ssh-rsa AAAA...' - api_token: XXX - -# Will return the droplet details including the droplet id (used for idempotence) -- name: Create a new Droplet - digital_ocean: - state: present - command: droplet - name: mydroplet - api_token: XXX - size_id: 2gb - region_id: ams2 - image_id: fedora-19-x64 - wait_timeout: 500 - register: my_droplet - -- debug: - msg: "ID is {{ my_droplet.droplet.id }}" - -- debug: - msg: "IP is {{ my_droplet.droplet.ip_address }}" - -# Ensure a droplet is present -# If droplet id already exist, will return the droplet details and changed = False -# If no droplet matches the id, a new droplet will be created and the droplet details (including the new id) are returned, changed = True. - -- name: Ensure a droplet is present - digital_ocean: - state: present - command: droplet - id: 123 - name: mydroplet - api_token: XXX - size_id: 2gb - region_id: ams2 - image_id: fedora-19-x64 - wait_timeout: 500 - -# Create a droplet with ssh key -# The ssh key id can be passed as argument at the creation of a droplet (see ssh_key_ids). -# Several keys can be added to ssh_key_ids as id1,id2,id3 -# The keys are used to connect as root to the droplet. - -- name: Create a droplet with ssh key - digital_ocean: - state: present - ssh_key_ids: 123,456 - name: mydroplet - api_token: XXX - size_id: 2gb - region_id: ams2 - image_id: fedora-19-x64 -''' - -import os -import time -import traceback - -from distutils.version import LooseVersion - -try: - # Imported as a dependency for dopy - import ansible.module_utils.six - HAS_SIX = True -except ImportError: - HAS_SIX = False - -HAS_DOPY = False -try: - import dopy - from dopy.manager import DoError, DoManager - if LooseVersion(dopy.__version__) >= LooseVersion('0.3.2'): - HAS_DOPY = True -except ImportError: - pass - -from ansible.module_utils.basic import AnsibleModule, env_fallback - - -class TimeoutError(Exception): - - def __init__(self, msg, id_): - super(TimeoutError, self).__init__(msg) - self.id = id_ - - -class JsonfyMixIn(object): - - def to_json(self): - return self.__dict__ - - -class Droplet(JsonfyMixIn): - manager = None - - def __init__(self, droplet_json): - self.status = 'new' - self.__dict__.update(droplet_json) - - def is_powered_on(self): - return self.status == 'active' - - def update_attr(self, attrs=None): - if attrs: - for k, v in attrs.items(): - setattr(self, k, v) - networks = attrs.get('networks', {}) - for network in networks.get('v6', []): - if network['type'] == 'public': - setattr(self, 'public_ipv6_address', network['ip_address']) - else: - setattr(self, 'private_ipv6_address', network['ip_address']) - else: - json = self.manager.show_droplet(self.id) - if json['ip_address']: - self.update_attr(json) - - def power_on(self): - if self.status != 'off': - raise AssertionError('Can only power on a closed one.') - json = self.manager.power_on_droplet(self.id) - self.update_attr(json) - - def ensure_powered_on(self, wait=True, wait_timeout=300): - if self.is_powered_on(): - return - if self.status == 'off': # powered off - self.power_on() - - if wait: - end_time = time.time() + wait_timeout - while time.time() < end_time: - time.sleep(min(20, end_time - time.time())) - self.update_attr() - if self.is_powered_on(): - if not self.ip_address: - raise TimeoutError('No ip is found.', self.id) - return - raise TimeoutError('Wait for droplet running timeout', self.id) - - def destroy(self): - return self.manager.destroy_droplet(self.id, scrub_data=True) - - @classmethod - def setup(cls, api_token): - cls.manager = DoManager(None, api_token, api_version=2) - - @classmethod - def add(cls, name, size_id, image_id, region_id, ssh_key_ids=None, virtio=True, private_networking=False, backups_enabled=False, user_data=None, - ipv6=False): - private_networking_lower = str(private_networking).lower() - backups_enabled_lower = str(backups_enabled).lower() - ipv6_lower = str(ipv6).lower() - json = cls.manager.new_droplet(name, size_id, image_id, region_id, - ssh_key_ids=ssh_key_ids, virtio=virtio, private_networking=private_networking_lower, - backups_enabled=backups_enabled_lower, user_data=user_data, ipv6=ipv6_lower) - droplet = cls(json) - return droplet - - @classmethod - def find(cls, id=None, name=None): - if not id and not name: - return False - - droplets = cls.list_all() - - # Check first by id. digital ocean requires that it be unique - for droplet in droplets: - if droplet.id == id: - return droplet - - # Failing that, check by hostname. - for droplet in droplets: - if droplet.name == name: - return droplet - - return False - - @classmethod - def list_all(cls): - json = cls.manager.all_active_droplets() - return list(map(cls, json)) - - -class SSH(JsonfyMixIn): - manager = None - - def __init__(self, ssh_key_json): - self.__dict__.update(ssh_key_json) - update_attr = __init__ - - def destroy(self): - self.manager.destroy_ssh_key(self.id) - return True - - @classmethod - def setup(cls, api_token): - cls.manager = DoManager(None, api_token, api_version=2) - - @classmethod - def find(cls, name): - if not name: - return False - keys = cls.list_all() - for key in keys: - if key.name == name: - return key - return False - - @classmethod - def list_all(cls): - json = cls.manager.all_ssh_keys() - return list(map(cls, json)) - - @classmethod - def add(cls, name, key_pub): - json = cls.manager.new_ssh_key(name, key_pub) - return cls(json) - - -def core(module): - def getkeyordie(k): - v = module.params[k] - if v is None: - module.fail_json(msg='Unable to load %s' % k) - return v - - api_token = module.params['api_token'] - changed = True - command = module.params['command'] - state = module.params['state'] - - if command == 'droplet': - Droplet.setup(api_token) - if state in ('active', 'present'): - - # First, try to find a droplet by id. - droplet = Droplet.find(id=module.params['id']) - - # If we couldn't find the droplet and the user is allowing unique - # hostnames, then check to see if a droplet with the specified - # hostname already exists. - if not droplet and module.params['unique_name']: - droplet = Droplet.find(name=getkeyordie('name')) - - # If both of those attempts failed, then create a new droplet. - if not droplet: - droplet = Droplet.add( - name=getkeyordie('name'), - size_id=getkeyordie('size_id'), - image_id=getkeyordie('image_id'), - region_id=getkeyordie('region_id'), - ssh_key_ids=module.params['ssh_key_ids'], - virtio=module.params['virtio'], - private_networking=module.params['private_networking'], - backups_enabled=module.params['backups_enabled'], - user_data=module.params.get('user_data'), - ipv6=module.params['ipv6'], - ) - - if droplet.is_powered_on(): - changed = False - - droplet.ensure_powered_on( - wait=getkeyordie('wait'), - wait_timeout=getkeyordie('wait_timeout') - ) - - module.exit_json(changed=changed, droplet=droplet.to_json()) - - elif state in ('absent', 'deleted'): - # First, try to find a droplet by id. - droplet = Droplet.find(module.params['id']) - - # If we couldn't find the droplet and the user is allowing unique - # hostnames, then check to see if a droplet with the specified - # hostname already exists. - if not droplet and module.params['unique_name']: - droplet = Droplet.find(name=getkeyordie('name')) - - if not droplet: - module.exit_json(changed=False, msg='The droplet is not found.') - - droplet.destroy() - module.exit_json(changed=True) - - elif command == 'ssh': - SSH.setup(api_token) - name = getkeyordie('name') - if state in ('active', 'present'): - key = SSH.find(name) - if key: - module.exit_json(changed=False, ssh_key=key.to_json()) - key = SSH.add(name, getkeyordie('ssh_pub_key')) - module.exit_json(changed=True, ssh_key=key.to_json()) - - elif state in ('absent', 'deleted'): - key = SSH.find(name) - if not key: - module.exit_json(changed=False, msg='SSH key with the name of %s is not found.' % name) - key.destroy() - module.exit_json(changed=True) - - -def main(): - module = AnsibleModule( - argument_spec=dict( - command=dict(choices=['droplet', 'ssh'], default='droplet'), - state=dict(choices=['active', 'present', 'absent', 'deleted'], default='present'), - api_token=dict( - aliases=['API_TOKEN'], - no_log=True, - fallback=(env_fallback, ['DO_API_TOKEN', 'DO_API_KEY']) - ), - name=dict(type='str'), - size_id=dict(), - image_id=dict(), - region_id=dict(), - ssh_key_ids=dict(type='list'), - virtio=dict(type='bool', default=True), - private_networking=dict(type='bool', default=False), - backups_enabled=dict(type='bool', default=False), - id=dict(aliases=['droplet_id'], type='int'), - unique_name=dict(type='bool', default=False), - user_data=dict(default=None), - ipv6=dict(type='bool', default=False), - wait=dict(type='bool', default=True), - wait_timeout=dict(default=300, type='int'), - ssh_pub_key=dict(type='str'), - ), - required_together=( - ['size_id', 'image_id', 'region_id'], - ), - mutually_exclusive=( - ['size_id', 'ssh_pub_key'], - ['image_id', 'ssh_pub_key'], - ['region_id', 'ssh_pub_key'], - ), - required_one_of=( - ['id', 'name'], - ), - ) - if not HAS_DOPY and not HAS_SIX: - module.fail_json(msg='dopy >= 0.3.2 is required for this module. dopy requires six but six is not installed. ' - 'Make sure both dopy and six are installed.') - if not HAS_DOPY: - module.fail_json(msg='dopy >= 0.3.2 required for this module') - - try: - core(module) - except TimeoutError as e: - module.fail_json(msg=str(e), id=e.id) - except (DoError, Exception) as e: - module.fail_json(msg=str(e), exception=traceback.format_exc()) - - -if __name__ == '__main__': - main() diff --git a/plugins/modules/cloud/digital_ocean/digital_ocean_account_facts.py b/plugins/modules/cloud/digital_ocean/digital_ocean_account_facts.py deleted file mode 120000 index 6eff816538..0000000000 --- a/plugins/modules/cloud/digital_ocean/digital_ocean_account_facts.py +++ /dev/null @@ -1 +0,0 @@ -digital_ocean_account_info.py \ No newline at end of file diff --git a/plugins/modules/cloud/digital_ocean/digital_ocean_account_info.py b/plugins/modules/cloud/digital_ocean/digital_ocean_account_info.py deleted file mode 100644 index 1fa7b70649..0000000000 --- a/plugins/modules/cloud/digital_ocean/digital_ocean_account_info.py +++ /dev/null @@ -1,81 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -# Copyright: (c) 2018, Ansible Project -# Copyright: (c) 2018, Abhijeet Kasurde -# 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 = ''' ---- -module: digital_ocean_account_info -short_description: Gather information about DigitalOcean User account -description: - - This module can be used to gather information about User account. - - This module was called C(digital_ocean_account_facts) before Ansible 2.9. The usage did not change. -author: "Abhijeet Kasurde (@Akasurde)" - -requirements: - - "python >= 2.6" - -extends_documentation_fragment: -- community.general.digital_ocean.documentation - -''' - - -EXAMPLES = ''' -- name: Gather information about user account - digital_ocean_account_info: - oauth_token: "{{ oauth_token }}" -''' - - -RETURN = ''' -data: - description: DigitalOcean account information - returned: success - type: dict - sample: { - "droplet_limit": 10, - "email": "testuser1@gmail.com", - "email_verified": true, - "floating_ip_limit": 3, - "status": "active", - "status_message": "", - "uuid": "aaaaaaaaaaaaaa" - } -''' - -from traceback import format_exc -from ansible.module_utils.basic import AnsibleModule -from ansible_collections.community.general.plugins.module_utils.digital_ocean import DigitalOceanHelper -from ansible.module_utils._text import to_native - - -def core(module): - rest = DigitalOceanHelper(module) - - response = rest.get("account") - if response.status_code != 200: - module.fail_json(msg="Failed to fetch 'account' information due to error : %s" % response.json['message']) - - module.exit_json(changed=False, data=response.json["account"]) - - -def main(): - argument_spec = DigitalOceanHelper.digital_ocean_argument_spec() - module = AnsibleModule(argument_spec=argument_spec) - if module._name in ('digital_ocean_account_facts', 'community.general.digital_ocean_account_facts'): - module.deprecate("The 'digital_ocean_account_facts' module has been renamed to 'digital_ocean_account_info'", - version='3.0.0', collection_name='community.general') # was Ansible 2.13 - try: - core(module) - except Exception as e: - module.fail_json(msg=to_native(e), exception=format_exc()) - - -if __name__ == '__main__': - main() diff --git a/plugins/modules/cloud/digital_ocean/digital_ocean_block_storage.py b/plugins/modules/cloud/digital_ocean/digital_ocean_block_storage.py deleted file mode 100644 index 88de216979..0000000000 --- a/plugins/modules/cloud/digital_ocean/digital_ocean_block_storage.py +++ /dev/null @@ -1,283 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -# Copyright: 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 = ''' ---- -module: digital_ocean_block_storage -short_description: Create/destroy or attach/detach Block Storage volumes in DigitalOcean -description: - - Create/destroy Block Storage volume in DigitalOcean, or attach/detach Block Storage volume to a droplet. -options: - command: - description: - - Which operation do you want to perform. - choices: ['create', 'attach'] - required: true - state: - description: - - Indicate desired state of the target. - choices: ['present', 'absent'] - required: true - block_size: - description: - - The size of the Block Storage volume in gigabytes. Required when command=create and state=present. If snapshot_id is included, this will be ignored. - volume_name: - description: - - The name of the Block Storage volume. - required: true - description: - description: - - Description of the Block Storage volume. - region: - description: - - The slug of the region where your Block Storage volume should be located in. If snapshot_id is included, this will be ignored. - required: true - snapshot_id: - description: - - The snapshot id you would like the Block Storage volume created with. If included, region and block_size will be ignored and changed to null. - droplet_id: - description: - - The droplet id you want to operate on. Required when command=attach. -extends_documentation_fragment: -- community.general.digital_ocean.documentation - -notes: - - Two environment variables can be used, DO_API_KEY and DO_API_TOKEN. - They both refer to the v2 token. - - If snapshot_id is used, region and block_size will be ignored and changed to null. - -author: - - "Harnek Sidhu (@harneksidhu)" -''' - -EXAMPLES = ''' -- name: Create new Block Storage - digital_ocean_block_storage: - state: present - command: create - api_token: - region: nyc1 - block_size: 10 - volume_name: nyc1-block-storage - -- name: Delete Block Storage - digital_ocean_block_storage: - state: absent - command: create - api_token: - region: nyc1 - volume_name: nyc1-block-storage - -- name: Attach Block Storage to a Droplet - digital_ocean_block_storage: - state: present - command: attach - api_token: - volume_name: nyc1-block-storage - region: nyc1 - droplet_id: - -- name: Detach Block Storage from a Droplet - digital_ocean_block_storage: - state: absent - command: attach - api_token: - volume_name: nyc1-block-storage - region: nyc1 - droplet_id: -''' - -RETURN = ''' -id: - description: Unique identifier of a Block Storage volume returned during creation. - returned: changed - type: str - sample: "69b25d9a-494c-12e6-a5af-001f53126b44" -''' - -import time -import traceback - -from ansible.module_utils.basic import AnsibleModule -from ansible_collections.community.general.plugins.module_utils.digital_ocean import DigitalOceanHelper - - -class DOBlockStorageException(Exception): - pass - - -class DOBlockStorage(object): - def __init__(self, module): - self.module = module - self.rest = DigitalOceanHelper(module) - - def get_key_or_fail(self, k): - v = self.module.params[k] - if v is None: - self.module.fail_json(msg='Unable to load %s' % k) - return v - - def poll_action_for_complete_status(self, action_id): - url = 'actions/{0}'.format(action_id) - end_time = time.time() + self.module.params['timeout'] - while time.time() < end_time: - time.sleep(2) - response = self.rest.get(url) - status = response.status_code - json = response.json - if status == 200: - if json['action']['status'] == 'completed': - return True - elif json['action']['status'] == 'errored': - raise DOBlockStorageException(json['message']) - raise DOBlockStorageException('Unable to reach api.digitalocean.com') - - def get_attached_droplet_ID(self, volume_name, region): - url = 'volumes?name={0}®ion={1}'.format(volume_name, region) - response = self.rest.get(url) - status = response.status_code - json = response.json - if status == 200: - volumes = json['volumes'] - if len(volumes) > 0: - droplet_ids = volumes[0]['droplet_ids'] - if len(droplet_ids) > 0: - return droplet_ids[0] - return None - else: - raise DOBlockStorageException(json['message']) - - def attach_detach_block_storage(self, method, volume_name, region, droplet_id): - data = { - 'type': method, - 'volume_name': volume_name, - 'region': region, - 'droplet_id': droplet_id - } - response = self.rest.post('volumes/actions', data=data) - status = response.status_code - json = response.json - if status == 202: - return self.poll_action_for_complete_status(json['action']['id']) - elif status == 200: - return True - elif status == 422: - return False - else: - raise DOBlockStorageException(json['message']) - - def create_block_storage(self): - volume_name = self.get_key_or_fail('volume_name') - snapshot_id = self.module.params['snapshot_id'] - if snapshot_id: - self.module.params['block_size'] = None - self.module.params['region'] = None - block_size = None - region = None - else: - block_size = self.get_key_or_fail('block_size') - region = self.get_key_or_fail('region') - description = self.module.params['description'] - data = { - 'size_gigabytes': block_size, - 'name': volume_name, - 'description': description, - 'region': region, - 'snapshot_id': snapshot_id, - } - response = self.rest.post("volumes", data=data) - status = response.status_code - json = response.json - if status == 201: - self.module.exit_json(changed=True, id=json['volume']['id']) - elif status == 409 and json['id'] == 'conflict': - self.module.exit_json(changed=False) - else: - raise DOBlockStorageException(json['message']) - - def delete_block_storage(self): - volume_name = self.get_key_or_fail('volume_name') - region = self.get_key_or_fail('region') - url = 'volumes?name={0}®ion={1}'.format(volume_name, region) - attached_droplet_id = self.get_attached_droplet_ID(volume_name, region) - if attached_droplet_id is not None: - self.attach_detach_block_storage('detach', volume_name, region, attached_droplet_id) - response = self.rest.delete(url) - status = response.status_code - json = response.json - if status == 204: - self.module.exit_json(changed=True) - elif status == 404: - self.module.exit_json(changed=False) - else: - raise DOBlockStorageException(json['message']) - - def attach_block_storage(self): - volume_name = self.get_key_or_fail('volume_name') - region = self.get_key_or_fail('region') - droplet_id = self.get_key_or_fail('droplet_id') - attached_droplet_id = self.get_attached_droplet_ID(volume_name, region) - if attached_droplet_id is not None: - if attached_droplet_id == droplet_id: - self.module.exit_json(changed=False) - else: - self.attach_detach_block_storage('detach', volume_name, region, attached_droplet_id) - changed_status = self.attach_detach_block_storage('attach', volume_name, region, droplet_id) - self.module.exit_json(changed=changed_status) - - def detach_block_storage(self): - volume_name = self.get_key_or_fail('volume_name') - region = self.get_key_or_fail('region') - droplet_id = self.get_key_or_fail('droplet_id') - changed_status = self.attach_detach_block_storage('detach', volume_name, region, droplet_id) - self.module.exit_json(changed=changed_status) - - -def handle_request(module): - block_storage = DOBlockStorage(module) - command = module.params['command'] - state = module.params['state'] - if command == 'create': - if state == 'present': - block_storage.create_block_storage() - elif state == 'absent': - block_storage.delete_block_storage() - elif command == 'attach': - if state == 'present': - block_storage.attach_block_storage() - elif state == 'absent': - block_storage.detach_block_storage() - - -def main(): - argument_spec = DigitalOceanHelper.digital_ocean_argument_spec() - argument_spec.update( - state=dict(choices=['present', 'absent'], required=True), - command=dict(choices=['create', 'attach'], required=True), - block_size=dict(type='int', required=False), - volume_name=dict(type='str', required=True), - description=dict(type='str'), - region=dict(type='str', required=False), - snapshot_id=dict(type='str', required=False), - droplet_id=dict(type='int') - ) - - module = AnsibleModule(argument_spec=argument_spec) - - try: - handle_request(module) - except DOBlockStorageException as e: - module.fail_json(msg=e.message, exception=traceback.format_exc()) - except KeyError as e: - module.fail_json(msg='Unable to load %s' % e.message, exception=traceback.format_exc()) - - -if __name__ == '__main__': - main() diff --git a/plugins/modules/cloud/digital_ocean/digital_ocean_certificate.py b/plugins/modules/cloud/digital_ocean/digital_ocean_certificate.py deleted file mode 100644 index 98cf32615b..0000000000 --- a/plugins/modules/cloud/digital_ocean/digital_ocean_certificate.py +++ /dev/null @@ -1,169 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -# Copyright (c) 2017, Abhijeet Kasurde -# -# 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 = ''' ---- -module: digital_ocean_certificate -short_description: Manage certificates in DigitalOcean. -description: - - Create, Retrieve and remove certificates DigitalOcean. -author: "Abhijeet Kasurde (@Akasurde)" -options: - name: - description: - - The name of the certificate. - required: true - private_key: - description: - - A PEM-formatted private key content of SSL Certificate. - leaf_certificate: - description: - - A PEM-formatted public SSL Certificate. - certificate_chain: - description: - - The full PEM-formatted trust chain between the certificate authority's certificate and your domain's SSL certificate. - state: - description: - - Whether the certificate should be present or absent. - default: present - choices: ['present', 'absent'] -extends_documentation_fragment: -- community.general.digital_ocean.documentation - -notes: - - Two environment variables can be used, DO_API_KEY, DO_OAUTH_TOKEN and DO_API_TOKEN. - They both refer to the v2 token. -''' - - -EXAMPLES = ''' -- name: Create a certificate - digital_ocean_certificate: - name: production - state: present - private_key: "-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkM8OI7pRpgyj1I\n-----END PRIVATE KEY-----" - leaf_certificate: "-----BEGIN CERTIFICATE-----\nMIIFDmg2Iaw==\n-----END CERTIFICATE-----" - oauth_token: b7d03a6947b217efb6f3ec3bd365652 - -- name: Create a certificate using file lookup plugin - digital_ocean_certificate: - name: production - state: present - private_key: "{{ lookup('file', 'test.key') }}" - leaf_certificate: "{{ lookup('file', 'test.cert') }}" - oauth_token: "{{ oauth_token }}" - -- name: Create a certificate with trust chain - digital_ocean_certificate: - name: production - state: present - private_key: "{{ lookup('file', 'test.key') }}" - leaf_certificate: "{{ lookup('file', 'test.cert') }}" - certificate_chain: "{{ lookup('file', 'chain.cert') }}" - oauth_token: "{{ oauth_token }}" - -- name: Remove a certificate - digital_ocean_certificate: - name: production - state: absent - oauth_token: "{{ oauth_token }}" - -''' - - -RETURN = ''' # ''' - -from ansible.module_utils.basic import AnsibleModule -from ansible_collections.community.general.plugins.module_utils.digital_ocean import DigitalOceanHelper -from ansible.module_utils._text import to_native - - -def core(module): - state = module.params['state'] - name = module.params['name'] - - rest = DigitalOceanHelper(module) - - results = dict(changed=False) - - response = rest.get('certificates') - status_code = response.status_code - resp_json = response.json - - if status_code != 200: - module.fail_json(msg="Failed to retrieve certificates for DigitalOcean") - - if state == 'present': - for cert in resp_json['certificates']: - if cert['name'] == name: - module.fail_json(msg="Certificate name %s already exists" % name) - - # Certificate does not exist, let us create it - cert_data = dict(name=name, - private_key=module.params['private_key'], - leaf_certificate=module.params['leaf_certificate']) - - if module.params['certificate_chain'] is not None: - cert_data.update(certificate_chain=module.params['certificate_chain']) - - response = rest.post("certificates", data=cert_data) - status_code = response.status_code - if status_code == 500: - module.fail_json(msg="Failed to upload certificates as the certificates are malformed.") - - resp_json = response.json - if status_code == 201: - results.update(changed=True, response=resp_json) - elif status_code == 422: - results.update(changed=False, response=resp_json) - - elif state == 'absent': - cert_id_del = None - for cert in resp_json['certificates']: - if cert['name'] == name: - cert_id_del = cert['id'] - - if cert_id_del is not None: - url = "certificates/{0}".format(cert_id_del) - response = rest.delete(url) - if response.status_code == 204: - results.update(changed=True) - else: - results.update(changed=False) - else: - module.fail_json(msg="Failed to find certificate %s" % name) - - module.exit_json(**results) - - -def main(): - argument_spec = DigitalOceanHelper.digital_ocean_argument_spec() - argument_spec.update( - name=dict(type='str'), - leaf_certificate=dict(type='str'), - private_key=dict(type='str', no_log=True), - state=dict(choices=['present', 'absent'], default='present'), - certificate_chain=dict(type='str') - ) - - module = AnsibleModule( - argument_spec=argument_spec, - required_if=[('state', 'present', ['name', 'leaf_certificate', 'private_key']), - ('state', 'absent', ['name']) - ], - ) - - try: - core(module) - except Exception as e: - module.fail_json(msg=to_native(e)) - - -if __name__ == '__main__': - main() diff --git a/plugins/modules/cloud/digital_ocean/digital_ocean_certificate_facts.py b/plugins/modules/cloud/digital_ocean/digital_ocean_certificate_facts.py deleted file mode 120000 index adbb7c1ccf..0000000000 --- a/plugins/modules/cloud/digital_ocean/digital_ocean_certificate_facts.py +++ /dev/null @@ -1 +0,0 @@ -digital_ocean_certificate_info.py \ No newline at end of file diff --git a/plugins/modules/cloud/digital_ocean/digital_ocean_certificate_info.py b/plugins/modules/cloud/digital_ocean/digital_ocean_certificate_info.py deleted file mode 100644 index 7baf5fb91f..0000000000 --- a/plugins/modules/cloud/digital_ocean/digital_ocean_certificate_info.py +++ /dev/null @@ -1,113 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -# Copyright: (c) 2018, Ansible Project -# Copyright: (c) 2018, Abhijeet Kasurde -# 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 = ''' ---- -module: digital_ocean_certificate_info -short_description: Gather information about DigitalOcean certificates -description: - - This module can be used to gather information about DigitalOcean provided certificates. - - This module was called C(digital_ocean_certificate_facts) before Ansible 2.9. The usage did not change. -author: "Abhijeet Kasurde (@Akasurde)" -options: - certificate_id: - description: - - Certificate ID that can be used to identify and reference a certificate. - required: false -requirements: - - "python >= 2.6" -extends_documentation_fragment: -- community.general.digital_ocean.documentation - -''' - - -EXAMPLES = ''' -- name: Gather information about all certificates - digital_ocean_certificate_info: - oauth_token: "{{ oauth_token }}" - -- name: Gather information about certificate with given id - digital_ocean_certificate_info: - oauth_token: "{{ oauth_token }}" - certificate_id: "892071a0-bb95-49bc-8021-3afd67a210bf" - -- name: Get not after information about certificate - digital_ocean_certificate_info: - register: resp_out -- set_fact: - not_after_date: "{{ item.not_after }}" - loop: "{{ resp_out.data|json_query(name) }}" - vars: - name: "[?name=='web-cert-01']" -- debug: var=not_after_date -''' - - -RETURN = ''' -data: - description: DigitalOcean certificate information - returned: success - type: list - sample: [ - { - "id": "892071a0-bb95-49bc-8021-3afd67a210bf", - "name": "web-cert-01", - "not_after": "2017-02-22T00:23:00Z", - "sha1_fingerprint": "dfcc9f57d86bf58e321c2c6c31c7a971be244ac7", - "created_at": "2017-02-08T16:02:37Z" - }, - ] -''' - -from traceback import format_exc -from ansible.module_utils.basic import AnsibleModule -from ansible_collections.community.general.plugins.module_utils.digital_ocean import DigitalOceanHelper -from ansible.module_utils._text import to_native - - -def core(module): - certificate_id = module.params.get('certificate_id', None) - rest = DigitalOceanHelper(module) - - base_url = 'certificates?' - if certificate_id is not None: - response = rest.get("%s/%s" % (base_url, certificate_id)) - status_code = response.status_code - - if status_code != 200: - module.fail_json(msg="Failed to retrieve certificates for DigitalOcean") - - resp_json = response.json - certificate = resp_json['certificate'] - else: - certificate = rest.get_paginated_data(base_url=base_url, data_key_name='certificates') - - module.exit_json(changed=False, data=certificate) - - -def main(): - argument_spec = DigitalOceanHelper.digital_ocean_argument_spec() - argument_spec.update( - certificate_id=dict(type='str', required=False), - ) - module = AnsibleModule(argument_spec=argument_spec) - if module._name in ('digital_ocean_certificate_facts', 'community.general.digital_ocean_certificate_facts'): - module.deprecate("The 'digital_ocean_certificate_facts' module has been renamed to 'digital_ocean_certificate_info'", - version='3.0.0', collection_name='community.general') # was Ansible 2.13 - - try: - core(module) - except Exception as e: - module.fail_json(msg=to_native(e), exception=format_exc()) - - -if __name__ == '__main__': - main() diff --git a/plugins/modules/cloud/digital_ocean/digital_ocean_domain.py b/plugins/modules/cloud/digital_ocean/digital_ocean_domain.py deleted file mode 100644 index 0dadfdd0ec..0000000000 --- a/plugins/modules/cloud/digital_ocean/digital_ocean_domain.py +++ /dev/null @@ -1,214 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -# -# Copyright: 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 = ''' ---- -module: digital_ocean_domain -short_description: Create/delete a DNS domain in DigitalOcean -description: - - Create/delete a DNS domain in DigitalOcean. -author: "Michael Gregson (@mgregson)" -options: - state: - description: - - Indicate desired state of the target. - default: present - choices: ['present', 'absent'] - id: - description: - - Numeric, the droplet id you want to operate on. - aliases: ['droplet_id'] - name: - description: - - String, this is the name of the droplet - must be formatted by hostname rules, or the name of a SSH key, or the name of a domain. - ip: - description: - - An 'A' record for '@' ($ORIGIN) will be created with the value 'ip'. 'ip' is an IP version 4 address. -extends_documentation_fragment: -- community.general.digital_ocean.documentation - -notes: - - Environment variables DO_OAUTH_TOKEN can be used for the oauth_token. - - As of Ansible 1.9.5 and 2.0, Version 2 of the DigitalOcean API is used, this removes C(client_id) and C(api_key) options in favor of C(oauth_token). - - If you are running Ansible 1.9.4 or earlier you might not be able to use the included version of this module as the API version used has been retired. - -requirements: - - "python >= 2.6" -''' - - -EXAMPLES = ''' -- name: Create a domain - digital_ocean_domain: - state: present - name: my.digitalocean.domain - ip: 127.0.0.1 - -# Create a droplet and corresponding domain -- name: Create a droplet - digital_ocean: - state: present - name: test_droplet - size_id: 1gb - region_id: sgp1 - image_id: ubuntu-14-04-x64 - register: test_droplet - -- name: Create a corresponding domain - digital_ocean_domain: - state: present - name: "{{ test_droplet.droplet.name }}.my.domain" - ip: "{{ test_droplet.droplet.ip_address }}" - -''' - -import traceback -from ansible.module_utils.basic import AnsibleModule -from ansible_collections.community.general.plugins.module_utils.digital_ocean import DigitalOceanHelper -from ansible.module_utils._text import to_native - - -class DoManager(DigitalOceanHelper, object): - def __init__(self, module): - super(DoManager, self).__init__(module) - self.domain_name = module.params.get('name', None) - self.domain_ip = module.params.get('ip', None) - self.domain_id = module.params.get('id', None) - - @staticmethod - def jsonify(response): - return response.status_code, response.json - - def all_domains(self): - resp = self.get('domains/') - return resp - - def find(self): - if self.domain_name is None and self.domain_id is None: - return False - - domains = self.all_domains() - status, json = self.jsonify(domains) - for domain in json['domains']: - if domain['name'] == self.domain_name: - return True - return False - - def add(self): - params = {'name': self.domain_name, 'ip_address': self.domain_ip} - resp = self.post('domains/', data=params) - status = resp.status_code - json = resp.json - if status == 201: - return json['domain'] - else: - return json - - def all_domain_records(self): - resp = self.get('domains/%s/records/' % self.domain_name) - return resp.json - - def domain_record(self): - resp = self.get('domains/%s' % self.domain_name) - status, json = self.jsonify(resp) - return json - - def destroy_domain(self): - resp = self.delete('domains/%s' % self.domain_name) - status, json = self.jsonify(resp) - if status == 204: - return True - else: - return json - - def edit_domain_record(self, record): - params = {'name': '@', - 'data': self.module.params.get('ip')} - resp = self.put('domains/%s/records/%s' % (self.domain_name, record['id']), data=params) - status, json = self.jsonify(resp) - - return json['domain_record'] - - def create_domain_record(self): - params = {'name': '@', - 'type': 'A', - 'data': self.module.params.get('ip')} - - resp = self.post('domains/%s/records' % (self.domain_name), data=params) - status, json = self.jsonify(resp) - - return json['domain_record'] - - -def core(module): - do_manager = DoManager(module) - state = module.params.get('state') - - domain = do_manager.find() - if state == 'present': - if not domain: - domain = do_manager.add() - if 'message' in domain: - module.fail_json(changed=False, msg=domain['message']) - else: - module.exit_json(changed=True, domain=domain) - else: - records = do_manager.all_domain_records() - at_record = None - for record in records['domain_records']: - if record['name'] == "@" and record['type'] == 'A': - at_record = record - - if not at_record: - do_manager.create_domain_record() - module.exit_json(changed=True, domain=do_manager.find()) - elif not at_record['data'] == module.params.get('ip'): - do_manager.edit_domain_record(at_record) - module.exit_json(changed=True, domain=do_manager.find()) - else: - module.exit_json(changed=False, domain=do_manager.domain_record()) - - elif state == 'absent': - if not domain: - module.exit_json(changed=False, msg="Domain not found") - else: - delete_event = do_manager.destroy_domain() - if not delete_event: - module.fail_json(changed=False, msg=delete_event['message']) - else: - module.exit_json(changed=True, event=None) - delete_event = do_manager.destroy_domain() - module.exit_json(changed=delete_event) - - -def main(): - argument_spec = DigitalOceanHelper.digital_ocean_argument_spec() - argument_spec.update( - state=dict(choices=['present', 'absent'], default='present'), - name=dict(type='str'), - id=dict(aliases=['droplet_id'], type='int'), - ip=dict(type='str') - ) - - module = AnsibleModule( - argument_spec=argument_spec, - required_one_of=( - ['id', 'name'], - ), - ) - - try: - core(module) - except Exception as e: - module.fail_json(msg=to_native(e), exception=traceback.format_exc()) - - -if __name__ == '__main__': - main() diff --git a/plugins/modules/cloud/digital_ocean/digital_ocean_domain_facts.py b/plugins/modules/cloud/digital_ocean/digital_ocean_domain_facts.py deleted file mode 120000 index f226660018..0000000000 --- a/plugins/modules/cloud/digital_ocean/digital_ocean_domain_facts.py +++ /dev/null @@ -1 +0,0 @@ -digital_ocean_domain_info.py \ No newline at end of file diff --git a/plugins/modules/cloud/digital_ocean/digital_ocean_domain_info.py b/plugins/modules/cloud/digital_ocean/digital_ocean_domain_info.py deleted file mode 100644 index 7bfbfbdd50..0000000000 --- a/plugins/modules/cloud/digital_ocean/digital_ocean_domain_info.py +++ /dev/null @@ -1,138 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -# Copyright: (c) 2018, Ansible Project -# Copyright: (c) 2018, Abhijeet Kasurde -# 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 = ''' ---- -module: digital_ocean_domain_info -short_description: Gather information about DigitalOcean Domains -description: - - This module can be used to gather information about DigitalOcean provided Domains. - - This module was called C(digital_ocean_domain_facts) before Ansible 2.9. The usage did not change. -author: "Abhijeet Kasurde (@Akasurde)" -options: - domain_name: - description: - - Name of the domain to gather information for. - required: false -requirements: - - "python >= 2.6" -extends_documentation_fragment: -- community.general.digital_ocean.documentation - -''' - - -EXAMPLES = ''' -- name: Gather information about all domains - digital_ocean_domain_info: - oauth_token: "{{ oauth_token }}" - -- name: Gather information about domain with given name - digital_ocean_domain_info: - oauth_token: "{{ oauth_token }}" - domain_name: "example.com" - -- name: Get ttl from domain - digital_ocean_domain_info: - register: resp_out -- set_fact: - domain_ttl: "{{ item.ttl }}" - loop: "{{ resp_out.data|json_query(name) }}" - vars: - name: "[?name=='example.com']" -- debug: var=domain_ttl -''' - - -RETURN = ''' -data: - description: DigitalOcean Domain information - returned: success - type: list - sample: [ - { - "domain_records": [ - { - "data": "ns1.digitalocean.com", - "flags": null, - "id": 37826823, - "name": "@", - "port": null, - "priority": null, - "tag": null, - "ttl": 1800, - "type": "NS", - "weight": null - }, - ], - "name": "myexample123.com", - "ttl": 1800, - "zone_file": "myexample123.com. IN SOA ns1.digitalocean.com. hostmaster.myexample123.com. 1520702984 10800 3600 604800 1800\n", - }, - ] -''' - -from traceback import format_exc -from ansible.module_utils.basic import AnsibleModule -from ansible_collections.community.general.plugins.module_utils.digital_ocean import DigitalOceanHelper -from ansible.module_utils._text import to_native - - -def core(module): - domain_name = module.params.get('domain_name', None) - rest = DigitalOceanHelper(module) - domain_results = [] - - if domain_name is not None: - response = rest.get("domains/%s" % domain_name) - status_code = response.status_code - - if status_code != 200: - module.fail_json(msg="Failed to retrieve domain for DigitalOcean") - - resp_json = response.json - domains = [resp_json['domain']] - else: - domains = rest.get_paginated_data(base_url="domains?", data_key_name='domains') - - for temp_domain in domains: - temp_domain_dict = { - "name": temp_domain['name'], - "ttl": temp_domain['ttl'], - "zone_file": temp_domain['zone_file'], - "domain_records": list(), - } - - base_url = "domains/%s/records?" % temp_domain['name'] - - temp_domain_dict["domain_records"] = rest.get_paginated_data(base_url=base_url, data_key_name='domain_records') - domain_results.append(temp_domain_dict) - - module.exit_json(changed=False, data=domain_results) - - -def main(): - argument_spec = DigitalOceanHelper.digital_ocean_argument_spec() - argument_spec.update( - domain_name=dict(type='str', required=False), - ) - module = AnsibleModule(argument_spec=argument_spec) - if module._name in ('digital_ocean_domain_facts', 'community.general.digital_ocean_domain_facts'): - module.deprecate("The 'digital_ocean_domain_facts' module has been renamed to 'digital_ocean_domain_info'", - version='3.0.0', collection_name='community.general') # was Ansible 2.13 - - try: - core(module) - except Exception as e: - module.fail_json(msg=to_native(e), exception=format_exc()) - - -if __name__ == '__main__': - main() diff --git a/plugins/modules/cloud/digital_ocean/digital_ocean_droplet.py b/plugins/modules/cloud/digital_ocean/digital_ocean_droplet.py deleted file mode 100644 index 227d5e0b42..0000000000 --- a/plugins/modules/cloud/digital_ocean/digital_ocean_droplet.py +++ /dev/null @@ -1,351 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -# -# Copyright: 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 = ''' ---- -module: digital_ocean_droplet -short_description: Create and delete a DigitalOcean droplet -description: - - Create and delete a droplet in DigitalOcean and optionally wait for it to be active. -author: "Gurchet Rai (@gurch101)" -options: - state: - description: - - Indicate desired state of the target. - default: present - choices: ['present', 'absent'] - id: - description: - - Numeric, the droplet id you want to operate on. - aliases: ['droplet_id'] - name: - description: - - String, this is the name of the droplet - must be formatted by hostname rules. - unique_name: - description: - - require unique hostnames. By default, DigitalOcean allows multiple hosts with the same name. Setting this to "yes" allows only one host - per name. Useful for idempotence. - default: False - type: bool - size: - description: - - This is the slug of the size you would like the droplet created with. - aliases: ['size_id'] - image: - description: - - This is the slug of the image you would like the droplet created with. - aliases: ['image_id'] - region: - description: - - This is the slug of the region you would like your server to be created in. - aliases: ['region_id'] - ssh_keys: - description: - - array of SSH key Fingerprint that you would like to be added to the server. - required: False - private_networking: - description: - - add an additional, private network interface to droplet for inter-droplet communication. - default: False - type: bool - vpc_uuid: - description: - - A string specifying the UUID of the VPC to which the Droplet will be assigned. If excluded, Droplet will be - assigned to the account's default VPC for the region. - type: str - version_added: 0.2.0 - user_data: - description: - - opaque blob of data which is made available to the droplet - required: False - ipv6: - description: - - enable IPv6 for your droplet. - required: False - default: False - type: bool - wait: - description: - - Wait for the droplet to be active before returning. If wait is "no" an ip_address may not be returned. - required: False - default: True - type: bool - wait_timeout: - description: - - How long before wait gives up, in seconds, when creating a droplet. - default: 120 - backups: - description: - - indicates whether automated backups should be enabled. - required: False - default: False - type: bool - monitoring: - description: - - indicates whether to install the DigitalOcean agent for monitoring. - required: False - default: False - type: bool - tags: - description: - - List, A list of tag names as strings to apply to the Droplet after it is created. Tag names can either be existing or new tags. - required: False - volumes: - description: - - List, A list including the unique string identifier for each Block Storage volume to be attached to the Droplet. - required: False - oauth_token: - description: - - DigitalOcean OAuth token. Can be specified in C(DO_API_KEY), C(DO_API_TOKEN), or C(DO_OAUTH_TOKEN) environment variables - aliases: ['API_TOKEN'] - required: True -requirements: - - "python >= 2.6" -''' - - -EXAMPLES = ''' -- name: Create a new droplet - digital_ocean_droplet: - state: present - name: mydroplet - oauth_token: XXX - size: 2gb - region: sfo1 - image: ubuntu-16-04-x64 - wait_timeout: 500 - ssh_keys: [ .... ] - register: my_droplet - -- debug: - msg: "ID is {{ my_droplet.data.droplet.id }}, IP is {{ my_droplet.data.ip_address }}" - -- name: Ensure a droplet is present - digital_ocean_droplet: - state: present - id: 123 - name: mydroplet - oauth_token: XXX - size: 2gb - region: sfo1 - image: ubuntu-16-04-x64 - wait_timeout: 500 - -- name: Ensure a droplet is present with SSH keys installed - digital_ocean_droplet: - state: present - id: 123 - name: mydroplet - oauth_token: XXX - size: 2gb - region: sfo1 - ssh_keys: ['1534404', '1784768'] - image: ubuntu-16-04-x64 - wait_timeout: 500 -''' - -RETURN = ''' -# Digital Ocean API info https://developers.digitalocean.com/documentation/v2/#droplets -data: - description: a DigitalOcean Droplet - returned: changed - type: dict - sample: { - "ip_address": "104.248.118.172", - "ipv6_address": "2604:a880:400:d1::90a:6001", - "private_ipv4_address": "10.136.122.141", - "droplet": { - "id": 3164494, - "name": "example.com", - "memory": 512, - "vcpus": 1, - "disk": 20, - "locked": true, - "status": "new", - "kernel": { - "id": 2233, - "name": "Ubuntu 14.04 x64 vmlinuz-3.13.0-37-generic", - "version": "3.13.0-37-generic" - }, - "created_at": "2014-11-14T16:36:31Z", - "features": ["virtio"], - "backup_ids": [], - "snapshot_ids": [], - "image": {}, - "volume_ids": [], - "size": {}, - "size_slug": "512mb", - "networks": {}, - "region": {}, - "tags": ["web"] - } - } -''' - -import time -import json -from ansible.module_utils.basic import AnsibleModule, env_fallback -from ansible_collections.community.general.plugins.module_utils.digital_ocean import DigitalOceanHelper - - -class DODroplet(object): - def __init__(self, module): - self.rest = DigitalOceanHelper(module) - self.module = module - self.wait = self.module.params.pop('wait', True) - self.wait_timeout = self.module.params.pop('wait_timeout', 120) - self.unique_name = self.module.params.pop('unique_name', False) - # pop the oauth token so we don't include it in the POST data - self.module.params.pop('oauth_token') - - def get_by_id(self, droplet_id): - if not droplet_id: - return None - response = self.rest.get('droplets/{0}'.format(droplet_id)) - json_data = response.json - if response.status_code == 200: - return json_data - return None - - def get_by_name(self, droplet_name): - if not droplet_name: - return None - page = 1 - while page is not None: - response = self.rest.get('droplets?page={0}'.format(page)) - json_data = response.json - if response.status_code == 200: - for droplet in json_data['droplets']: - if droplet['name'] == droplet_name: - return {'droplet': droplet} - if 'links' in json_data and 'pages' in json_data['links'] and 'next' in json_data['links']['pages']: - page += 1 - else: - page = None - return None - - def get_addresses(self, data): - """ - Expose IP addresses as their own property allowing users extend to additional tasks - """ - _data = data - for k, v in data.items(): - setattr(self, k, v) - networks = _data['droplet']['networks'] - for network in networks.get('v4', []): - if network['type'] == 'public': - _data['ip_address'] = network['ip_address'] - else: - _data['private_ipv4_address'] = network['ip_address'] - for network in networks.get('v6', []): - if network['type'] == 'public': - _data['ipv6_address'] = network['ip_address'] - else: - _data['private_ipv6_address'] = network['ip_address'] - return _data - - def get_droplet(self): - json_data = self.get_by_id(self.module.params['id']) - if not json_data and self.unique_name: - json_data = self.get_by_name(self.module.params['name']) - return json_data - - def create(self): - json_data = self.get_droplet() - droplet_data = None - if json_data: - droplet_data = self.get_addresses(json_data) - self.module.exit_json(changed=False, data=droplet_data) - if self.module.check_mode: - self.module.exit_json(changed=True) - request_params = dict(self.module.params) - del request_params['id'] - response = self.rest.post('droplets', data=request_params) - json_data = response.json - if response.status_code >= 400: - self.module.fail_json(changed=False, msg=json_data['message']) - if self.wait: - json_data = self.ensure_power_on(json_data['droplet']['id']) - droplet_data = self.get_addresses(json_data) - self.module.exit_json(changed=True, data=droplet_data) - - def delete(self): - json_data = self.get_droplet() - if json_data: - if self.module.check_mode: - self.module.exit_json(changed=True) - response = self.rest.delete('droplets/{0}'.format(json_data['droplet']['id'])) - json_data = response.json - if response.status_code == 204: - self.module.exit_json(changed=True, msg='Droplet deleted') - self.module.fail_json(changed=False, msg='Failed to delete droplet') - else: - self.module.exit_json(changed=False, msg='Droplet not found') - - def ensure_power_on(self, droplet_id): - end_time = time.time() + self.wait_timeout - while time.time() < end_time: - response = self.rest.get('droplets/{0}'.format(droplet_id)) - json_data = response.json - if json_data['droplet']['status'] == 'active': - return json_data - time.sleep(min(2, end_time - time.time())) - self.module.fail_json(msg='Wait for droplet powering on timeout') - - -def core(module): - state = module.params.pop('state') - droplet = DODroplet(module) - if state == 'present': - droplet.create() - elif state == 'absent': - droplet.delete() - - -def main(): - module = AnsibleModule( - argument_spec=dict( - state=dict(choices=['present', 'absent'], default='present'), - oauth_token=dict( - aliases=['API_TOKEN'], - no_log=True, - fallback=(env_fallback, ['DO_API_TOKEN', 'DO_API_KEY', 'DO_OAUTH_TOKEN']) - ), - name=dict(type='str'), - size=dict(aliases=['size_id']), - image=dict(aliases=['image_id']), - region=dict(aliases=['region_id']), - ssh_keys=dict(type='list'), - private_networking=dict(type='bool', default=False), - vpc_uuid=dict(type='str'), - backups=dict(type='bool', default=False), - monitoring=dict(type='bool', default=False), - id=dict(aliases=['droplet_id'], type='int'), - user_data=dict(default=None), - ipv6=dict(type='bool', default=False), - volumes=dict(type='list'), - tags=dict(type='list'), - wait=dict(type='bool', default=True), - wait_timeout=dict(default=120, type='int'), - unique_name=dict(type='bool', default=False), - ), - required_one_of=( - ['id', 'name'], - ), - required_if=([ - ('state', 'present', ['name', 'size', 'image', 'region']), - ]), - supports_check_mode=True, - ) - - core(module) - - -if __name__ == '__main__': - main() diff --git a/plugins/modules/cloud/digital_ocean/digital_ocean_firewall_facts.py b/plugins/modules/cloud/digital_ocean/digital_ocean_firewall_facts.py deleted file mode 120000 index 847f422b67..0000000000 --- a/plugins/modules/cloud/digital_ocean/digital_ocean_firewall_facts.py +++ /dev/null @@ -1 +0,0 @@ -digital_ocean_firewall_info.py \ No newline at end of file diff --git a/plugins/modules/cloud/digital_ocean/digital_ocean_firewall_info.py b/plugins/modules/cloud/digital_ocean/digital_ocean_firewall_info.py deleted file mode 100644 index fe1b3dfe1b..0000000000 --- a/plugins/modules/cloud/digital_ocean/digital_ocean_firewall_info.py +++ /dev/null @@ -1,131 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -# Copyright: (c) 2018, Ansible Project -# Copyright: (c) 2018, Anthony Bond -# 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 = ''' ---- -module: digital_ocean_firewall_info -short_description: Gather information about DigitalOcean firewalls -description: - - This module can be used to gather information about DigitalOcean firewalls. - - This module was called C(digital_ocean_firewall_facts) before Ansible 2.9. The usage did not change. -author: "Anthony Bond (@BondAnthony)" -options: - name: - description: - - Firewall rule name that can be used to identify and reference a specific firewall rule. - required: false -requirements: - - "python >= 2.6" -extends_documentation_fragment: -- community.general.digital_ocean.documentation - -''' - - -EXAMPLES = ''' -- name: Gather information about all firewalls - digital_ocean_firewall_info: - oauth_token: "{{ oauth_token }}" - -- name: Gather information about a specific firewall by name - digital_ocean_firewall_info: - oauth_token: "{{ oauth_token }}" - name: "firewall_name" - -- name: Gather information from a firewall rule - digital_ocean_firewall_info: - name: SSH - register: resp_out - -- set_fact: - firewall_id: "{{ resp_out.data.id }}" - -- debug: - msg: "{{ firewall_id }}" -''' - - -RETURN = ''' -data: - description: DigitalOcean firewall information - returned: success - type: list - sample: [ - { - "id": "435tbg678-1db53-32b6-t543-28322569t252", - "name": "metrics", - "status": "succeeded", - "inbound_rules": [ - { - "protocol": "tcp", - "ports": "9100", - "sources": { - "addresses": [ - "1.1.1.1" - ] - } - } - ], - "outbound_rules": [], - "created_at": "2018-01-15T07:04:25Z", - "droplet_ids": [ - 87426985 - ], - "tags": [], - "pending_changes": [] - }, - ] -''' - -from traceback import format_exc -from ansible.module_utils.basic import AnsibleModule -from ansible_collections.community.general.plugins.module_utils.digital_ocean import DigitalOceanHelper -from ansible.module_utils._text import to_native - - -def core(module): - firewall_name = module.params.get('name', None) - rest = DigitalOceanHelper(module) - base_url = 'firewalls?' - - response = rest.get("%s" % base_url) - status_code = response.status_code - if status_code != 200: - module.fail_json(msg="Failed to retrieve firewalls from Digital Ocean") - firewalls = rest.get_paginated_data(base_url=base_url, data_key_name='firewalls') - - if firewall_name is not None: - rule = {} - for firewall in firewalls: - if firewall['name'] == firewall_name: - rule.update(firewall) - module.exit_json(changed=False, data=rule) - else: - module.exit_json(changed=False, data=firewalls) - - -def main(): - argument_spec = DigitalOceanHelper.digital_ocean_argument_spec() - argument_spec.update( - name=dict(type='str', required=False), - ) - module = AnsibleModule(argument_spec=argument_spec) - if module._name in ('digital_ocean_firewall_facts', 'community.general.digital_ocean_firewall_facts'): - module.deprecate("The 'digital_ocean_firewall_facts' module has been renamed to 'digital_ocean_firewall_info'", - version='3.0.0', collection_name='community.general') # was Ansible 2.13 - - try: - core(module) - except Exception as e: - module.fail_json(msg=to_native(e), exception=format_exc()) - - -if __name__ == '__main__': - main() diff --git a/plugins/modules/cloud/digital_ocean/digital_ocean_floating_ip.py b/plugins/modules/cloud/digital_ocean/digital_ocean_floating_ip.py deleted file mode 100644 index 7682dbfb67..0000000000 --- a/plugins/modules/cloud/digital_ocean/digital_ocean_floating_ip.py +++ /dev/null @@ -1,311 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -# -# (c) 2015, Patrick F. Marques -# 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 = ''' ---- -module: digital_ocean_floating_ip -short_description: Manage DigitalOcean Floating IPs -description: - - Create/delete/assign a floating IP. -author: "Patrick Marques (@pmarques)" -options: - state: - description: - - Indicate desired state of the target. - default: present - choices: ['present', 'absent'] - ip: - description: - - Public IP address of the Floating IP. Used to remove an IP - region: - description: - - The region that the Floating IP is reserved to. - droplet_id: - description: - - The Droplet that the Floating IP has been assigned to. - oauth_token: - description: - - DigitalOcean OAuth token. - required: true -notes: - - Version 2 of DigitalOcean API is used. -requirements: - - "python >= 2.6" -''' - - -EXAMPLES = ''' -- name: "Create a Floating IP in region lon1" - digital_ocean_floating_ip: - state: present - region: lon1 - -- name: "Create a Floating IP assigned to Droplet ID 123456" - digital_ocean_floating_ip: - state: present - droplet_id: 123456 - -- name: "Delete a Floating IP with ip 1.2.3.4" - digital_ocean_floating_ip: - state: absent - ip: "1.2.3.4" - -''' - - -RETURN = ''' -# Digital Ocean API info https://developers.digitalocean.com/documentation/v2/#floating-ips -data: - description: a DigitalOcean Floating IP resource - returned: success and no resource constraint - type: dict - sample: { - "action": { - "id": 68212728, - "status": "in-progress", - "type": "assign_ip", - "started_at": "2015-10-15T17:45:44Z", - "completed_at": null, - "resource_id": 758603823, - "resource_type": "floating_ip", - "region": { - "name": "New York 3", - "slug": "nyc3", - "sizes": [ - "512mb", - "1gb", - "2gb", - "4gb", - "8gb", - "16gb", - "32gb", - "48gb", - "64gb" - ], - "features": [ - "private_networking", - "backups", - "ipv6", - "metadata" - ], - "available": true - }, - "region_slug": "nyc3" - } - } -''' - -import json -import time - -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 Rest(object): - - def __init__(self, module, headers): - self.module = module - self.headers = headers - self.baseurl = 'https://api.digitalocean.com/v2' - - def _url_builder(self, path): - if path[0] == '/': - path = path[1:] - return '%s/%s' % (self.baseurl, 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'] - - 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 - 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 wait_action(module, rest, ip, action_id, timeout=10): - end_time = time.time() + 10 - while time.time() < end_time: - response = rest.get('floating_ips/{0}/actions/{1}'.format(ip, action_id)) - status_code = response.status_code - status = response.json['action']['status'] - # TODO: check status_code == 200? - if status == 'completed': - return True - elif status == 'errored': - module.fail_json(msg='Floating ip action error [ip: {0}: action: {1}]'.format( - ip, action_id), data=json) - - module.fail_json(msg='Floating ip action timeout [ip: {0}: action: {1}]'.format( - ip, action_id), data=json) - - -def core(module): - api_token = module.params['oauth_token'] - state = module.params['state'] - ip = module.params['ip'] - droplet_id = module.params['droplet_id'] - - rest = Rest(module, {'Authorization': 'Bearer {0}'.format(api_token), - 'Content-type': 'application/json'}) - - if state in ('present'): - if droplet_id is not None and module.params['ip'] is not None: - # Lets try to associate the ip to the specified droplet - associate_floating_ips(module, rest) - else: - create_floating_ips(module, rest) - - elif state in ('absent'): - response = rest.delete("floating_ips/{0}".format(ip)) - status_code = response.status_code - json_data = response.json - if status_code == 204: - module.exit_json(changed=True) - elif status_code == 404: - module.exit_json(changed=False) - else: - module.exit_json(changed=False, data=json_data) - - -def get_floating_ip_details(module, rest): - ip = module.params['ip'] - - response = rest.get("floating_ips/{0}".format(ip)) - status_code = response.status_code - json_data = response.json - if status_code == 200: - return json_data['floating_ip'] - else: - module.fail_json(msg="Error assigning floating ip [{0}: {1}]".format( - status_code, json_data["message"]), region=module.params['region']) - - -def assign_floating_id_to_droplet(module, rest): - ip = module.params['ip'] - - payload = { - "type": "assign", - "droplet_id": module.params['droplet_id'], - } - - response = rest.post("floating_ips/{0}/actions".format(ip), data=payload) - status_code = response.status_code - json_data = response.json - if status_code == 201: - wait_action(module, rest, ip, json_data['action']['id']) - - module.exit_json(changed=True, data=json_data) - else: - module.fail_json(msg="Error creating floating ip [{0}: {1}]".format( - status_code, json_data["message"]), region=module.params['region']) - - -def associate_floating_ips(module, rest): - floating_ip = get_floating_ip_details(module, rest) - droplet = floating_ip['droplet'] - - # TODO: If already assigned to a droplet verify if is one of the specified as valid - if droplet is not None and str(droplet['id']) in [module.params['droplet_id']]: - module.exit_json(changed=False) - else: - assign_floating_id_to_droplet(module, rest) - - -def create_floating_ips(module, rest): - payload = { - } - - if module.params['region'] is not None: - payload["region"] = module.params['region'] - if module.params['droplet_id'] is not None: - payload["droplet_id"] = module.params['droplet_id'] - - response = rest.post("floating_ips", data=payload) - status_code = response.status_code - json_data = response.json - if status_code == 202: - module.exit_json(changed=True, data=json_data) - else: - module.fail_json(msg="Error creating floating ip [{0}: {1}]".format( - status_code, json_data["message"]), region=module.params['region']) - - -def main(): - module = AnsibleModule( - argument_spec=dict( - state=dict(choices=['present', 'absent'], default='present'), - ip=dict(aliases=['id'], required=False), - region=dict(required=False), - droplet_id=dict(required=False), - oauth_token=dict( - no_log=True, - # Support environment variable for DigitalOcean OAuth Token - fallback=(env_fallback, ['DO_API_TOKEN', 'DO_API_KEY', 'DO_OAUTH_TOKEN']), - required=True, - ), - validate_certs=dict(type='bool', default=True), - timeout=dict(type='int', default=30), - ), - required_if=[ - ('state', 'delete', ['ip']) - ], - mutually_exclusive=[ - ['region', 'droplet_id'] - ], - ) - - core(module) - - -if __name__ == '__main__': - main() diff --git a/plugins/modules/cloud/digital_ocean/digital_ocean_floating_ip_facts.py b/plugins/modules/cloud/digital_ocean/digital_ocean_floating_ip_facts.py deleted file mode 120000 index bd71456669..0000000000 --- a/plugins/modules/cloud/digital_ocean/digital_ocean_floating_ip_facts.py +++ /dev/null @@ -1 +0,0 @@ -digital_ocean_floating_ip_info.py \ No newline at end of file diff --git a/plugins/modules/cloud/digital_ocean/digital_ocean_floating_ip_info.py b/plugins/modules/cloud/digital_ocean/digital_ocean_floating_ip_info.py deleted file mode 100644 index fa181cb203..0000000000 --- a/plugins/modules/cloud/digital_ocean/digital_ocean_floating_ip_info.py +++ /dev/null @@ -1,119 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -# Copyright: (C) 2017-18, 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 = ''' ---- -module: digital_ocean_floating_ip_info -short_description: DigitalOcean Floating IPs information -description: - - This module can be used to fetch DigitalOcean Floating IPs information. - - This module was called C(digital_ocean_floating_ip_facts) before Ansible 2.9. The usage did not change. -author: "Patrick Marques (@pmarques)" -extends_documentation_fragment: -- community.general.digital_ocean.documentation - -notes: - - Version 2 of DigitalOcean API is used. -requirements: - - "python >= 2.6" -''' - - -EXAMPLES = ''' -- name: "Gather information about all Floating IPs" - digital_ocean_floating_ip_info: - register: result - -- name: "List of current floating ips" - debug: var=result.floating_ips -''' - - -RETURN = ''' -# Digital Ocean API info https://developers.digitalocean.com/documentation/v2/#floating-ips -floating_ips: - description: a DigitalOcean Floating IP resource - returned: success and no resource constraint - type: list - sample: [ - { - "ip": "45.55.96.47", - "droplet": null, - "region": { - "name": "New York 3", - "slug": "nyc3", - "sizes": [ - "512mb", - "1gb", - "2gb", - "4gb", - "8gb", - "16gb", - "32gb", - "48gb", - "64gb" - ], - "features": [ - "private_networking", - "backups", - "ipv6", - "metadata" - ], - "available": true - }, - "locked": false - } - ] -''' - -from ansible.module_utils.basic import AnsibleModule -from ansible_collections.community.general.plugins.module_utils.digital_ocean import DigitalOceanHelper -from ansible.module_utils._text import to_native - - -def core(module): - rest = DigitalOceanHelper(module) - - page = 1 - has_next = True - floating_ips = [] - status_code = None - while has_next or status_code != 200: - response = rest.get("floating_ips?page={0}&per_page=20".format(page)) - status_code = response.status_code - # stop if any error during pagination - if status_code != 200: - break - page += 1 - floating_ips.extend(response.json["floating_ips"]) - has_next = "pages" in response.json["links"] and "next" in response.json["links"]["pages"] - - if status_code == 200: - module.exit_json(changed=False, floating_ips=floating_ips) - else: - module.fail_json(msg="Error fetching information [{0}: {1}]".format( - status_code, response.json["message"])) - - -def main(): - module = AnsibleModule( - argument_spec=DigitalOceanHelper.digital_ocean_argument_spec() - ) - if module._name in ('digital_ocean_floating_ip_facts', 'community.general.digital_ocean_floating_ip_facts'): - module.deprecate("The 'digital_ocean_floating_ip_facts' module has been renamed to 'digital_ocean_floating_ip_info'", - version='3.0.0', collection_name='community.general') # was Ansible 2.13 - - try: - core(module) - except Exception as e: - module.fail_json(msg=to_native(e)) - - -if __name__ == '__main__': - main() diff --git a/plugins/modules/cloud/digital_ocean/digital_ocean_image_facts.py b/plugins/modules/cloud/digital_ocean/digital_ocean_image_facts.py deleted file mode 120000 index e25fb47543..0000000000 --- a/plugins/modules/cloud/digital_ocean/digital_ocean_image_facts.py +++ /dev/null @@ -1 +0,0 @@ -digital_ocean_image_info.py \ No newline at end of file diff --git a/plugins/modules/cloud/digital_ocean/digital_ocean_image_info.py b/plugins/modules/cloud/digital_ocean/digital_ocean_image_info.py deleted file mode 100644 index 74fa7dc3a5..0000000000 --- a/plugins/modules/cloud/digital_ocean/digital_ocean_image_info.py +++ /dev/null @@ -1,148 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -# Copyright: (c) 2018, Ansible Project -# Copyright: (c) 2018, Abhijeet Kasurde -# 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 = ''' ---- -module: digital_ocean_image_info -short_description: Gather information about DigitalOcean images -description: - - This module can be used to gather information about DigitalOcean provided images. - - These images can be either of type C(distribution), C(application) and C(private). - - This module was called C(digital_ocean_image_facts) before Ansible 2.9. The usage did not change. -author: "Abhijeet Kasurde (@Akasurde)" -options: - image_type: - description: - - Specifies the type of image information to be retrieved. - - If set to C(application), then information are gathered related to all application images. - - If set to C(distribution), then information are gathered related to all distribution images. - - If set to C(private), then information are gathered related to all private images. - - If not set to any of above, then information are gathered related to all images. - default: 'all' - choices: [ 'all', 'application', 'distribution', 'private' ] - required: false -requirements: - - "python >= 2.6" -extends_documentation_fragment: -- community.general.digital_ocean.documentation - -''' - - -EXAMPLES = ''' -- name: Gather information about all images - digital_ocean_image_info: - image_type: all - oauth_token: "{{ oauth_token }}" - -- name: Gather information about application images - digital_ocean_image_info: - image_type: application - oauth_token: "{{ oauth_token }}" - -- name: Gather information about distribution images - digital_ocean_image_info: - image_type: distribution - oauth_token: "{{ oauth_token }}" - -- name: Get distribution about image with slug coreos-beta - digital_ocean_image_info: - register: resp_out -- set_fact: - distribution_name: "{{ item.distribution }}" - loop: "{{ resp_out.data|json_query(name) }}" - vars: - name: "[?slug=='coreos-beta']" -- debug: var=distribution_name - -''' - - -RETURN = ''' -data: - description: DigitalOcean image information - returned: success - type: list - sample: [ - { - "created_at": "2018-02-02T07:11:43Z", - "distribution": "CoreOS", - "id": 31434061, - "min_disk_size": 20, - "name": "1662.1.0 (beta)", - "public": true, - "regions": [ - "nyc1", - "sfo1", - "nyc2", - "ams2", - "sgp1", - "lon1", - "nyc3", - "ams3", - "fra1", - "tor1", - "sfo2", - "blr1" - ], - "size_gigabytes": 0.42, - "slug": "coreos-beta", - "type": "snapshot" - }, - ] -''' - -from traceback import format_exc -from ansible.module_utils.basic import AnsibleModule -from ansible_collections.community.general.plugins.module_utils.digital_ocean import DigitalOceanHelper -from ansible.module_utils._text import to_native - - -def core(module): - image_type = module.params['image_type'] - - rest = DigitalOceanHelper(module) - - base_url = 'images?' - if image_type == 'distribution': - base_url += "type=distribution&" - elif image_type == 'application': - base_url += "type=application&" - elif image_type == 'private': - base_url += "private=true&" - - images = rest.get_paginated_data(base_url=base_url, data_key_name='images') - - module.exit_json(changed=False, data=images) - - -def main(): - argument_spec = DigitalOceanHelper.digital_ocean_argument_spec() - argument_spec.update( - image_type=dict(type='str', - required=False, - choices=['all', 'application', 'distribution', 'private'], - default='all' - ) - ) - - module = AnsibleModule(argument_spec=argument_spec) - if module._name in ('digital_ocean_image_facts', 'community.general.digital_ocean_image_facts'): - module.deprecate("The 'digital_ocean_image_facts' module has been renamed to 'digital_ocean_image_info'", - version='3.0.0', collection_name='community.general') # was Ansible 2.13 - - try: - core(module) - except Exception as e: - module.fail_json(msg=to_native(e), exception=format_exc()) - - -if __name__ == '__main__': - main() diff --git a/plugins/modules/cloud/digital_ocean/digital_ocean_load_balancer_facts.py b/plugins/modules/cloud/digital_ocean/digital_ocean_load_balancer_facts.py deleted file mode 120000 index 2883d53ecd..0000000000 --- a/plugins/modules/cloud/digital_ocean/digital_ocean_load_balancer_facts.py +++ /dev/null @@ -1 +0,0 @@ -digital_ocean_load_balancer_info.py \ No newline at end of file diff --git a/plugins/modules/cloud/digital_ocean/digital_ocean_load_balancer_info.py b/plugins/modules/cloud/digital_ocean/digital_ocean_load_balancer_info.py deleted file mode 100644 index 19b87c20bf..0000000000 --- a/plugins/modules/cloud/digital_ocean/digital_ocean_load_balancer_info.py +++ /dev/null @@ -1,115 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -# Copyright: (c) 2018, Ansible Project -# Copyright: (c) 2018, Abhijeet Kasurde -# 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 = ''' ---- -module: digital_ocean_load_balancer_info -short_description: Gather information about DigitalOcean load balancers -description: - - This module can be used to gather information about DigitalOcean provided load balancers. - - This module was called C(digital_ocean_load_balancer_facts) before Ansible 2.9. The usage did not change. -author: "Abhijeet Kasurde (@Akasurde)" -options: - load_balancer_id: - description: - - Load balancer ID that can be used to identify and reference a load_balancer. - required: false -requirements: - - "python >= 2.6" -extends_documentation_fragment: -- community.general.digital_ocean.documentation - -''' - - -EXAMPLES = ''' -- name: Gather information about all load balancers - digital_ocean_load_balancer_info: - oauth_token: "{{ oauth_token }}" - -- name: Gather information about load balancer with given id - digital_ocean_load_balancer_info: - oauth_token: "{{ oauth_token }}" - load_balancer_id: "4de7ac8b-495b-4884-9a69-1050c6793cd6" - -- name: Get name from load balancer id - digital_ocean_load_balancer_info: - register: resp_out -- set_fact: - load_balancer_name: "{{ item.name }}" - loop: "{{ resp_out.data|json_query(name) }}" - vars: - name: "[?id=='4de7ac8b-495b-4884-9a69-1050c6793cd6']" -- debug: var=load_balancer_name -''' - - -RETURN = ''' -data: - description: DigitalOcean Load balancer information - returned: success - type: list - sample: [ - { - "id": "4de7ac8b-495b-4884-9a69-1050c6793cd6", - "name": "example-lb-01", - "ip": "104.131.186.241", - "algorithm": "round_robin", - "status": "new", - "created_at": "2017-02-01T22:22:58Z", - ... - }, - ] -''' - -from traceback import format_exc -from ansible.module_utils.basic import AnsibleModule -from ansible_collections.community.general.plugins.module_utils.digital_ocean import DigitalOceanHelper -from ansible.module_utils._text import to_native - - -def core(module): - load_balancer_id = module.params.get('load_balancer_id', None) - rest = DigitalOceanHelper(module) - - base_url = 'load_balancers?' - if load_balancer_id is not None: - response = rest.get("%s/%s" % (base_url, load_balancer_id)) - status_code = response.status_code - - if status_code != 200: - module.fail_json(msg="Failed to retrieve load balancers for DigitalOcean") - - resp_json = response.json - load_balancer = resp_json['load_balancer'] - else: - load_balancer = rest.get_paginated_data(base_url=base_url, data_key_name='load_balancers') - - module.exit_json(changed=False, data=load_balancer) - - -def main(): - argument_spec = DigitalOceanHelper.digital_ocean_argument_spec() - argument_spec.update( - load_balancer_id=dict(type='str', required=False), - ) - module = AnsibleModule(argument_spec=argument_spec) - if module._name in ('digital_ocean_load_balancer_facts', 'community.general.digital_ocean_load_balancer_facts'): - module.deprecate("The 'digital_ocean_load_balancer_facts' module has been renamed to 'digital_ocean_load_balancer_info'", - version='3.0.0', collection_name='community.general') # was Ansible 2.13 - - try: - core(module) - except Exception as e: - module.fail_json(msg=to_native(e), exception=format_exc()) - - -if __name__ == '__main__': - main() diff --git a/plugins/modules/cloud/digital_ocean/digital_ocean_region_facts.py b/plugins/modules/cloud/digital_ocean/digital_ocean_region_facts.py deleted file mode 120000 index c4ade0405c..0000000000 --- a/plugins/modules/cloud/digital_ocean/digital_ocean_region_facts.py +++ /dev/null @@ -1 +0,0 @@ -digital_ocean_region_info.py \ No newline at end of file diff --git a/plugins/modules/cloud/digital_ocean/digital_ocean_region_info.py b/plugins/modules/cloud/digital_ocean/digital_ocean_region_info.py deleted file mode 100644 index 3ae292f9c9..0000000000 --- a/plugins/modules/cloud/digital_ocean/digital_ocean_region_info.py +++ /dev/null @@ -1,115 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -# Copyright: (c) 2018, Ansible Project -# Copyright: (c) 2018, Abhijeet Kasurde -# 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 = ''' ---- -module: digital_ocean_region_info -short_description: Gather information about DigitalOcean regions -description: - - This module can be used to gather information about regions. - - This module was called C(digital_ocean_region_facts) before Ansible 2.9. The usage did not change. -author: "Abhijeet Kasurde (@Akasurde)" -extends_documentation_fragment: -- community.general.digital_ocean.documentation - -requirements: - - "python >= 2.6" -''' - - -EXAMPLES = ''' -- name: Gather information about all regions - digital_ocean_region_info: - oauth_token: "{{ oauth_token }}" - -- name: Get Name of region where slug is known - digital_ocean_region_info: - oauth_token: "{{ oauth_token }}" - register: resp_out -- debug: var=resp_out -- set_fact: - region_slug: "{{ item.name }}" - loop: "{{ resp_out.data|json_query(name) }}" - vars: - name: "[?slug==`nyc1`]" -- debug: var=region_slug -''' - - -RETURN = ''' -data: - description: DigitalOcean regions information - returned: success - type: list - sample: [ - { - "available": true, - "features": [ - "private_networking", - "backups", - "ipv6", - "metadata", - "install_agent", - "storage" - ], - "name": "New York 1", - "sizes": [ - "512mb", - "s-1vcpu-1gb", - "1gb", - "s-3vcpu-1gb", - "s-1vcpu-2gb", - "s-2vcpu-2gb", - "2gb", - "s-1vcpu-3gb", - "s-2vcpu-4gb", - "4gb", - "c-2", - "m-1vcpu-8gb", - "8gb", - "s-4vcpu-8gb", - "s-6vcpu-16gb", - "16gb" - ], - "slug": "nyc1" - }, - ] -''' - -from traceback import format_exc -from ansible.module_utils.basic import AnsibleModule -from ansible_collections.community.general.plugins.module_utils.digital_ocean import DigitalOceanHelper -from ansible.module_utils._text import to_native - - -def core(module): - rest = DigitalOceanHelper(module) - - base_url = 'regions?' - regions = rest.get_paginated_data(base_url=base_url, data_key_name='regions') - - module.exit_json(changed=False, data=regions) - - -def main(): - argument_spec = DigitalOceanHelper.digital_ocean_argument_spec() - module = AnsibleModule(argument_spec=argument_spec) - if module._name in ('digital_ocean_region_facts', 'community.general.digital_ocean_region_facts'): - module.deprecate("The 'digital_ocean_region_facts' module has been renamed to 'digital_ocean_region_info'", - version='3.0.0', collection_name='community.general') # was Ansible 2.13 - - try: - core(module) - except Exception as e: - module.fail_json(msg=to_native(e), exception=format_exc()) - - -if __name__ == '__main__': - main() diff --git a/plugins/modules/cloud/digital_ocean/digital_ocean_size_facts.py b/plugins/modules/cloud/digital_ocean/digital_ocean_size_facts.py deleted file mode 120000 index 01aabd5750..0000000000 --- a/plugins/modules/cloud/digital_ocean/digital_ocean_size_facts.py +++ /dev/null @@ -1 +0,0 @@ -digital_ocean_size_info.py \ No newline at end of file diff --git a/plugins/modules/cloud/digital_ocean/digital_ocean_size_info.py b/plugins/modules/cloud/digital_ocean/digital_ocean_size_info.py deleted file mode 100644 index 1b182b94e2..0000000000 --- a/plugins/modules/cloud/digital_ocean/digital_ocean_size_info.py +++ /dev/null @@ -1,113 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -# Copyright: (c) 2018, Ansible Project -# Copyright: (c) 2018, Abhijeet Kasurde -# 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 = ''' ---- -module: digital_ocean_size_info -short_description: Gather information about DigitalOcean Droplet sizes -description: - - This module can be used to gather information about droplet sizes. - - This module was called C(digital_ocean_size_facts) before Ansible 2.9. The usage did not change. -author: "Abhijeet Kasurde (@Akasurde)" -requirements: - - "python >= 2.6" -extends_documentation_fragment: -- community.general.digital_ocean.documentation - -''' - - -EXAMPLES = ''' -- name: Gather information about all droplet sizes - digital_ocean_size_info: - oauth_token: "{{ oauth_token }}" - -- name: Get droplet Size Slug where vcpus is 1 - digital_ocean_size_info: - oauth_token: "{{ oauth_token }}" - register: resp_out -- debug: var=resp_out -- set_fact: - size_slug: "{{ item.slug }}" - loop: "{{ resp_out.data|json_query(name) }}" - vars: - name: "[?vcpus==`1`]" -- debug: var=size_slug - - -''' - - -RETURN = ''' -data: - description: DigitalOcean droplet size information - returned: success - type: list - sample: [ - { - "available": true, - "disk": 20, - "memory": 512, - "price_hourly": 0.00744, - "price_monthly": 5.0, - "regions": [ - "ams2", - "ams3", - "blr1", - "fra1", - "lon1", - "nyc1", - "nyc2", - "nyc3", - "sfo1", - "sfo2", - "sgp1", - "tor1" - ], - "slug": "512mb", - "transfer": 1.0, - "vcpus": 1 - }, - ] -''' - -from traceback import format_exc -from ansible.module_utils.basic import AnsibleModule -from ansible_collections.community.general.plugins.module_utils.digital_ocean import DigitalOceanHelper -from ansible.module_utils._text import to_native - - -def core(module): - rest = DigitalOceanHelper(module) - - response = rest.get('sizes') - if response.status_code != 200: - module.fail_json(msg="Failed to fetch 'sizes' information due to error : %s" % response.json['message']) - - module.exit_json(changed=False, data=response.json['sizes']) - - -def main(): - argument_spec = DigitalOceanHelper.digital_ocean_argument_spec() - module = AnsibleModule( - argument_spec=argument_spec, - ) - if module._name in ('digital_ocean_size_facts', 'community.general.digital_ocean_size_facts'): - module.deprecate("The 'digital_ocean_size_facts' module has been renamed to 'digital_ocean_size_info'", - version='3.0.0', collection_name='community.general') # was Ansible 2.13 - - try: - core(module) - except Exception as e: - module.fail_json(msg=to_native(e), exception=format_exc()) - - -if __name__ == '__main__': - main() diff --git a/plugins/modules/cloud/digital_ocean/digital_ocean_snapshot_facts.py b/plugins/modules/cloud/digital_ocean/digital_ocean_snapshot_facts.py deleted file mode 120000 index c902df906e..0000000000 --- a/plugins/modules/cloud/digital_ocean/digital_ocean_snapshot_facts.py +++ /dev/null @@ -1 +0,0 @@ -digital_ocean_snapshot_info.py \ No newline at end of file diff --git a/plugins/modules/cloud/digital_ocean/digital_ocean_snapshot_info.py b/plugins/modules/cloud/digital_ocean/digital_ocean_snapshot_info.py deleted file mode 100644 index d75e8abeb6..0000000000 --- a/plugins/modules/cloud/digital_ocean/digital_ocean_snapshot_info.py +++ /dev/null @@ -1,160 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -# Copyright: (c) 2018, Ansible Project -# Copyright: (c) 2018, Abhijeet Kasurde -# 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 = ''' ---- -module: digital_ocean_snapshot_info -short_description: Gather information about DigitalOcean Snapshot -description: - - This module can be used to gather information about snapshot information based upon provided values such as droplet, volume and snapshot id. - - This module was called C(digital_ocean_snapshot_facts) before Ansible 2.9. The usage did not change. -author: "Abhijeet Kasurde (@Akasurde)" -options: - snapshot_type: - description: - - Specifies the type of snapshot information to be retrieved. - - If set to C(droplet), then information are gathered related to snapshots based on Droplets only. - - If set to C(volume), then information are gathered related to snapshots based on volumes only. - - If set to C(by_id), then information are gathered related to snapshots based on snapshot id only. - - If not set to any of the above, then information are gathered related to all snapshots. - default: 'all' - choices: [ 'all', 'droplet', 'volume', 'by_id'] - required: false - snapshot_id: - description: - - To retrieve information about a snapshot, please specify this as a snapshot id. - - If set to actual snapshot id, then information are gathered related to that particular snapshot only. - - This is required parameter, if C(snapshot_type) is set to C(by_id). - required: false -requirements: - - "python >= 2.6" -extends_documentation_fragment: -- community.general.digital_ocean.documentation - -''' - - -EXAMPLES = ''' -- name: Gather information about all snapshots - digital_ocean_snapshot_info: - snapshot_type: all - oauth_token: "{{ oauth_token }}" - -- name: Gather information about droplet snapshots - digital_ocean_snapshot_info: - snapshot_type: droplet - oauth_token: "{{ oauth_token }}" - -- name: Gather information about volume snapshots - digital_ocean_snapshot_info: - snapshot_type: volume - oauth_token: "{{ oauth_token }}" - -- name: Gather information about snapshot by snapshot id - digital_ocean_snapshot_info: - snapshot_type: by_id - snapshot_id: 123123123 - oauth_token: "{{ oauth_token }}" - -- name: Get information about snapshot named big-data-snapshot1 - digital_ocean_snapshot_info: - register: resp_out -- set_fact: - snapshot_id: "{{ item.id }}" - loop: "{{ resp_out.data|json_query(name) }}" - vars: - name: "[?name=='big-data-snapshot1']" -- debug: var=snapshot_id - -''' - - -RETURN = ''' -data: - description: DigitalOcean snapshot information - returned: success - type: list - sample: [ - { - "id": "4f60fc64-85d1-11e6-a004-000f53315871", - "name": "big-data-snapshot1", - "regions": [ - "nyc1" - ], - "created_at": "2016-09-28T23:14:30Z", - "resource_id": "89bcc42f-85cf-11e6-a004-000f53315871", - "resource_type": "volume", - "min_disk_size": 10, - "size_gigabytes": 0 - }, - ] -''' - -from traceback import format_exc -from ansible.module_utils.basic import AnsibleModule -from ansible_collections.community.general.plugins.module_utils.digital_ocean import DigitalOceanHelper -from ansible.module_utils._text import to_native - - -def core(module): - snapshot_type = module.params['snapshot_type'] - - rest = DigitalOceanHelper(module) - - base_url = 'snapshots?' - snapshot = [] - - if snapshot_type == 'by_id': - base_url += "/{0}".format(module.params.get('snapshot_id')) - response = rest.get(base_url) - status_code = response.status_code - - if status_code != 200: - module.fail_json(msg="Failed to fetch snapshot information due to error : %s" % response.json['message']) - - snapshot.extend(response.json["snapshot"]) - else: - if snapshot_type == 'droplet': - base_url += "resource_type=droplet&" - elif snapshot_type == 'volume': - base_url += "resource_type=volume&" - - snapshot = rest.get_paginated_data(base_url=base_url, data_key_name='snapshots') - module.exit_json(changed=False, data=snapshot) - - -def main(): - argument_spec = DigitalOceanHelper.digital_ocean_argument_spec() - argument_spec.update( - snapshot_type=dict(type='str', - required=False, - choices=['all', 'droplet', 'volume', 'by_id'], - default='all'), - snapshot_id=dict(type='str', - required=False), - ) - module = AnsibleModule( - argument_spec=argument_spec, - required_if=[ - ['snapshot_type', 'by_id', ['snapshot_id']], - ], - ) - if module._name in ('digital_ocean_snapshot_facts', 'community.general.digital_ocean_snapshot_facts'): - module.deprecate("The 'digital_ocean_snapshot_facts' module has been renamed to 'digital_ocean_snapshot_info'", - version='3.0.0', collection_name='community.general') # was Ansible 2.13 - - try: - core(module) - except Exception as e: - module.fail_json(msg=to_native(e), exception=format_exc()) - - -if __name__ == '__main__': - main() diff --git a/plugins/modules/cloud/digital_ocean/digital_ocean_sshkey.py b/plugins/modules/cloud/digital_ocean/digital_ocean_sshkey.py deleted file mode 100644 index eb32924858..0000000000 --- a/plugins/modules/cloud/digital_ocean/digital_ocean_sshkey.py +++ /dev/null @@ -1,257 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -# Copyright: 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 = ''' ---- -module: digital_ocean_sshkey -short_description: Manage DigitalOcean SSH keys -description: - - Create/delete DigitalOcean SSH keys. -author: "Patrick Marques (@pmarques)" -options: - state: - description: - - Indicate desired state of the target. - default: present - choices: ['present', 'absent'] - fingerprint: - description: - - This is a unique identifier for the SSH key used to delete a key - aliases: ['id'] - name: - description: - - The name for the SSH key - ssh_pub_key: - description: - - The Public SSH key to add. - oauth_token: - description: - - DigitalOcean OAuth token. - required: true -notes: - - Version 2 of DigitalOcean API is used. -requirements: - - "python >= 2.6" -''' - - -EXAMPLES = ''' -- name: "Create ssh key" - digital_ocean_sshkey: - oauth_token: "{{ oauth_token }}" - name: "My SSH Public Key" - ssh_pub_key: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAQQDDHr/jh2Jy4yALcK4JyWbVkPRaWmhck3IgCoeOO3z1e2dBowLh64QAM+Qb72pxekALga2oi4GvT+TlWNhzPH4V example" - state: present - register: result - -- name: "Delete ssh key" - digital_ocean_sshkey: - oauth_token: "{{ oauth_token }}" - state: "absent" - fingerprint: "3b:16:bf:e4:8b:00:8b:b8:59:8c:a9:d3:f0:19:45:fa" -''' - - -RETURN = ''' -# Digital Ocean API info https://developers.digitalocean.com/documentation/v2/#list-all-keys -data: - description: This is only present when C(state=present) - returned: when C(state=present) - type: dict - sample: { - "ssh_key": { - "id": 512189, - "fingerprint": "3b:16:bf:e4:8b:00:8b:b8:59:8c:a9:d3:f0:19:45:fa", - "name": "My SSH Public Key", - "public_key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAQQDDHr/jh2Jy4yALcK4JyWbVkPRaWmhck3IgCoeOO3z1e2dBowLh64QAM+Qb72pxekALga2oi4GvT+TlWNhzPH4V example" - } - } -''' - -import json -import hashlib -import base64 - -from ansible.module_utils.basic import env_fallback -from ansible.module_utils.basic import AnsibleModule -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 Rest(object): - - def __init__(self, module, headers): - self.module = module - self.headers = headers - self.baseurl = 'https://api.digitalocean.com/v2' - - def _url_builder(self, path): - if path[0] == '/': - path = path[1:] - return '%s/%s' % (self.baseurl, 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'] - - 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 - 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 core(module): - api_token = module.params['oauth_token'] - state = module.params['state'] - fingerprint = module.params['fingerprint'] - name = module.params['name'] - ssh_pub_key = module.params['ssh_pub_key'] - - rest = Rest(module, {'Authorization': 'Bearer {0}'.format(api_token), - 'Content-type': 'application/json'}) - - fingerprint = fingerprint or ssh_key_fingerprint(ssh_pub_key) - response = rest.get('account/keys/{0}'.format(fingerprint)) - status_code = response.status_code - json = response.json - - if status_code not in (200, 404): - module.fail_json(msg='Error getting ssh key [{0}: {1}]'.format( - status_code, response.json['message']), fingerprint=fingerprint) - - if state in ('present'): - if status_code == 404: - # IF key not found create it! - - if module.check_mode: - module.exit_json(changed=True) - - payload = { - 'name': name, - 'public_key': ssh_pub_key - } - response = rest.post('account/keys', data=payload) - status_code = response.status_code - json = response.json - if status_code == 201: - module.exit_json(changed=True, data=json) - - module.fail_json(msg='Error creating ssh key [{0}: {1}]'.format( - status_code, response.json['message'])) - - elif status_code == 200: - # If key found was found, check if name needs to be updated - if name is None or json['ssh_key']['name'] == name: - module.exit_json(changed=False, data=json) - - if module.check_mode: - module.exit_json(changed=True) - - payload = { - 'name': name, - } - response = rest.put('account/keys/{0}'.format(fingerprint), data=payload) - status_code = response.status_code - json = response.json - if status_code == 200: - module.exit_json(changed=True, data=json) - - module.fail_json(msg='Error updating ssh key name [{0}: {1}]'.format( - status_code, response.json['message']), fingerprint=fingerprint) - - elif state in ('absent'): - if status_code == 404: - module.exit_json(changed=False) - - if module.check_mode: - module.exit_json(changed=True) - - response = rest.delete('account/keys/{0}'.format(fingerprint)) - status_code = response.status_code - json = response.json - if status_code == 204: - module.exit_json(changed=True) - - module.fail_json(msg='Error creating ssh key [{0}: {1}]'.format( - status_code, response.json['message'])) - - -def ssh_key_fingerprint(ssh_pub_key): - key = ssh_pub_key.split(None, 2)[1] - fingerprint = hashlib.md5(base64.b64decode(key)).hexdigest() - return ':'.join(a + b for a, b in zip(fingerprint[::2], fingerprint[1::2])) - - -def main(): - module = AnsibleModule( - argument_spec=dict( - state=dict(choices=['present', 'absent'], default='present'), - fingerprint=dict(aliases=['id'], required=False), - name=dict(required=False), - ssh_pub_key=dict(required=False), - oauth_token=dict( - no_log=True, - # Support environment variable for DigitalOcean OAuth Token - fallback=(env_fallback, ['DO_API_TOKEN', 'DO_API_KEY', 'DO_OAUTH_TOKEN']), - required=True, - ), - validate_certs=dict(type='bool', default=True), - timeout=dict(type='int', default=30), - ), - required_one_of=( - ('fingerprint', 'ssh_pub_key'), - ), - supports_check_mode=True, - ) - - core(module) - - -if __name__ == '__main__': - main() diff --git a/plugins/modules/cloud/digital_ocean/digital_ocean_sshkey_facts.py b/plugins/modules/cloud/digital_ocean/digital_ocean_sshkey_facts.py deleted file mode 100644 index 0701021dc9..0000000000 --- a/plugins/modules/cloud/digital_ocean/digital_ocean_sshkey_facts.py +++ /dev/null @@ -1,101 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -# -# Copyright: 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 = ''' ---- -module: digital_ocean_sshkey_facts -deprecated: - removed_in: 3.0.0 # was Ansible 2.13 - why: Deprecated in favour of C(_info) module. - alternative: Use M(community.general.digital_ocean_sshkey_info) instead. -short_description: DigitalOcean SSH keys facts -description: - - Fetch DigitalOcean SSH keys facts. -author: "Patrick Marques (@pmarques)" -extends_documentation_fragment: -- community.general.digital_ocean.documentation - -notes: - - Version 2 of DigitalOcean API is used. -requirements: - - "python >= 2.6" -''' - - -EXAMPLES = ''' -- digital_ocean_sshkey_facts: - oauth_token: "{{ my_do_key }}" - -- set_fact: - pubkey: "{{ item.public_key }}" - loop: "{{ ssh_keys|json_query(ssh_pubkey) }}" - vars: - ssh_pubkey: "[?name=='ansible_ctrl']" - -- debug: - msg: "{{ pubkey }}" -''' - - -RETURN = ''' -# Digital Ocean API info https://developers.digitalocean.com/documentation/v2/#list-all-keys -data: - description: List of SSH keys on DigitalOcean - returned: success and no resource constraint - type: dict - sample: { - "ssh_keys": [ - { - "id": 512189, - "fingerprint": "3b:16:bf:e4:8b:00:8b:b8:59:8c:a9:d3:f0:19:45:fa", - "public_key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAQQDDHr/jh2Jy4yALcK4JyWbVkPRaWmhck3IgCoeOO3z1e2dBowLh64QAM+Qb72pxekALga2oi4GvT+TlWNhzPH4V example", - "name": "My SSH Public Key" - } - ], - "links": { - }, - "meta": { - "total": 1 - } - } -''' - -from ansible.module_utils.basic import AnsibleModule -from ansible_collections.community.general.plugins.module_utils.digital_ocean import DigitalOceanHelper - - -def core(module): - rest = DigitalOceanHelper(module) - - response = rest.get("account/keys") - status_code = response.status_code - json = response.json - if status_code == 200: - module.exit_json(changed=False, ansible_facts=json) - else: - module.fail_json(msg='Error fetching facts [{0}: {1}]'.format( - status_code, response.json['message'])) - - -def main(): - module = AnsibleModule( - argument_spec=DigitalOceanHelper.digital_ocean_argument_spec(), - supports_check_mode=False, - ) - - module.deprecate("The 'digital_ocean_sshkey_facts' module has been deprecated, use the new 'digital_ocean_sshkey_info' module", - version='3.0.0', collection_name='community.general') # was Ansible 2.13 - - core(module) - - -if __name__ == '__main__': - main() diff --git a/plugins/modules/cloud/digital_ocean/digital_ocean_sshkey_info.py b/plugins/modules/cloud/digital_ocean/digital_ocean_sshkey_info.py deleted file mode 100644 index a29ad955ca..0000000000 --- a/plugins/modules/cloud/digital_ocean/digital_ocean_sshkey_info.py +++ /dev/null @@ -1,92 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -# -# Copyright: 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 = ''' ---- -module: digital_ocean_sshkey_info -short_description: Gather information about DigitalOcean SSH keys -description: - - This module can be used to gather information about DigitalOcean SSH keys. - - This module replaces the C(digital_ocean_sshkey_facts) module. -author: "Patrick Marques (@pmarques)" -extends_documentation_fragment: -- community.general.digital_ocean.documentation - -notes: - - Version 2 of DigitalOcean API is used. -requirements: - - "python >= 2.6" -''' - - -EXAMPLES = ''' -- name: Gather information about DigitalOcean SSH keys - digital_ocean_sshkey_info: - oauth_token: "{{ my_do_key }}" - register: ssh_keys - -- name: Set facts based on the gathered information - set_fact: - pubkey: "{{ item.public_key }}" - loop: "{{ ssh_keys.data|json_query(ssh_pubkey) }}" - vars: - ssh_pubkey: "[?name=='ansible_ctrl']" - -- name: Print SSH public key - debug: - msg: "{{ pubkey }}" -''' - - -RETURN = ''' -# Digital Ocean API info https://developers.digitalocean.com/documentation/v2/#list-all-keys -data: - description: List of SSH keys on DigitalOcean - returned: success and no resource constraint - type: dict - sample: [ - { - "id": 512189, - "fingerprint": "3b:16:bf:e4:8b:00:8b:b8:59:8c:a9:d3:f0:19:45:fa", - "public_key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAQQDDHr/jh2Jy4yALcK4JyWbVkPRaWmhck3IgCoeOO3z1e2dBowLh64QAM+Qb72pxekALga2oi4GvT+TlWNhzPH4V example", - "name": "My SSH Public Key" - } - ] -''' - -from ansible.module_utils.basic import AnsibleModule -from ansible_collections.community.general.plugins.module_utils.digital_ocean import DigitalOceanHelper - - -def core(module): - rest = DigitalOceanHelper(module) - - response = rest.get("account/keys") - status_code = response.status_code - json = response.json - if status_code == 200: - module.exit_json(changed=False, data=json['ssh_keys']) - else: - module.fail_json(msg='Error fetching SSH Key information [{0}: {1}]'.format( - status_code, response.json['message'])) - - -def main(): - module = AnsibleModule( - argument_spec=DigitalOceanHelper.digital_ocean_argument_spec(), - supports_check_mode=True, - ) - - core(module) - - -if __name__ == '__main__': - main() diff --git a/plugins/modules/cloud/digital_ocean/digital_ocean_tag.py b/plugins/modules/cloud/digital_ocean/digital_ocean_tag.py deleted file mode 100644 index 2d2e59ce02..0000000000 --- a/plugins/modules/cloud/digital_ocean/digital_ocean_tag.py +++ /dev/null @@ -1,205 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -# Copyright: 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 = ''' ---- -module: digital_ocean_tag -short_description: Create and remove tag(s) to DigitalOcean resource. -description: - - Create and remove tag(s) to DigitalOcean resource. -author: "Victor Volle (@kontrafiktion)" -options: - name: - description: - - The name of the tag. The supported characters for names include - alphanumeric characters, dashes, and underscores. - required: true - resource_id: - description: - - The ID of the resource to operate on. - - The data type of resource_id is changed from integer to string since Ansible 2.5. - aliases: ['droplet_id'] - resource_type: - description: - - The type of resource to operate on. Currently, only tagging of - droplets is supported. - default: droplet - choices: ['droplet'] - state: - description: - - Whether the tag should be present or absent on the resource. - default: present - choices: ['present', 'absent'] -extends_documentation_fragment: -- community.general.digital_ocean.documentation - -notes: - - Two environment variables can be used, DO_API_KEY and DO_API_TOKEN. - They both refer to the v2 token. - - As of Ansible 2.0, Version 2 of the DigitalOcean API is used. - -requirements: - - "python >= 2.6" -''' - - -EXAMPLES = ''' -- name: Create a tag - digital_ocean_tag: - name: production - state: present - -- name: Tag a resource; creating the tag if it does not exist - digital_ocean_tag: - name: "{{ item }}" - resource_id: "73333005" - state: present - loop: - - staging - - dbserver - -- name: Untag a resource - digital_ocean_tag: - name: staging - resource_id: "73333005" - state: absent - -# Deleting a tag also untags all the resources that have previously been -# tagged with it -- name: Remove a tag - digital_ocean_tag: - name: dbserver - state: absent -''' - - -RETURN = ''' -data: - description: a DigitalOcean Tag resource - returned: success and no resource constraint - type: dict - sample: { - "tag": { - "name": "awesome", - "resources": { - "droplets": { - "count": 0, - "last_tagged": null - } - } - } - } -''' - -from traceback import format_exc -from ansible.module_utils.basic import AnsibleModule -from ansible_collections.community.general.plugins.module_utils.digital_ocean import DigitalOceanHelper -from ansible.module_utils._text import to_native - - -def core(module): - state = module.params['state'] - name = module.params['name'] - resource_id = module.params['resource_id'] - resource_type = module.params['resource_type'] - - rest = DigitalOceanHelper(module) - - if state == 'present': - response = rest.get('tags/{0}'.format(name)) - status_code = response.status_code - resp_json = response.json - changed = False - if status_code == 200 and resp_json['tag']['name'] == name: - changed = False - else: - # Ensure Tag exists - response = rest.post("tags", data={'name': name}) - status_code = response.status_code - resp_json = response.json - if status_code == 201: - changed = True - elif status_code == 422: - changed = False - else: - module.exit_json(changed=False, data=resp_json) - - if resource_id is None: - # No resource defined, we're done. - module.exit_json(changed=changed, data=resp_json) - else: - # Check if resource is already tagged or not - found = False - url = "{0}?tag_name={1}".format(resource_type, name) - if resource_type == 'droplet': - url = "droplets?tag_name={0}".format(name) - response = rest.get(url) - status_code = response.status_code - resp_json = response.json - if status_code == 200: - for resource in resp_json['droplets']: - if not found and resource['id'] == int(resource_id): - found = True - break - if not found: - # If resource is not tagged, tag a resource - url = "tags/{0}/resources".format(name) - payload = { - 'resources': [{ - 'resource_id': resource_id, - 'resource_type': resource_type}]} - response = rest.post(url, data=payload) - if response.status_code == 204: - module.exit_json(changed=True) - else: - module.fail_json(msg="error tagging resource '{0}': {1}".format(resource_id, response.json["message"])) - else: - # Already tagged resource - module.exit_json(changed=False) - else: - # Unable to find resource specified by user - module.fail_json(msg=resp_json['message']) - - elif state == 'absent': - if resource_id: - url = "tags/{0}/resources".format(name) - payload = { - 'resources': [{ - 'resource_id': resource_id, - 'resource_type': resource_type}]} - response = rest.delete(url, data=payload) - else: - url = "tags/{0}".format(name) - response = rest.delete(url) - if response.status_code == 204: - module.exit_json(changed=True) - else: - module.exit_json(changed=False, data=response.json) - - -def main(): - argument_spec = DigitalOceanHelper.digital_ocean_argument_spec() - argument_spec.update( - name=dict(type='str', required=True), - resource_id=dict(aliases=['droplet_id'], type='str'), - resource_type=dict(choices=['droplet'], default='droplet'), - state=dict(choices=['present', 'absent'], default='present'), - ) - - module = AnsibleModule(argument_spec=argument_spec) - - try: - core(module) - except Exception as e: - module.fail_json(msg=to_native(e), exception=format_exc()) - - -if __name__ == '__main__': - main() diff --git a/plugins/modules/cloud/digital_ocean/digital_ocean_tag_facts.py b/plugins/modules/cloud/digital_ocean/digital_ocean_tag_facts.py deleted file mode 120000 index a29f869b96..0000000000 --- a/plugins/modules/cloud/digital_ocean/digital_ocean_tag_facts.py +++ /dev/null @@ -1 +0,0 @@ -digital_ocean_tag_info.py \ No newline at end of file diff --git a/plugins/modules/cloud/digital_ocean/digital_ocean_tag_info.py b/plugins/modules/cloud/digital_ocean/digital_ocean_tag_info.py deleted file mode 100644 index 2c91411f40..0000000000 --- a/plugins/modules/cloud/digital_ocean/digital_ocean_tag_info.py +++ /dev/null @@ -1,115 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -# Copyright: (c) 2018, Ansible Project -# Copyright: (c) 2018, Abhijeet Kasurde -# 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 = ''' ---- -module: digital_ocean_tag_info -short_description: Gather information about DigitalOcean tags -description: - - This module can be used to gather information about DigitalOcean provided tags. - - This module was called C(digital_ocean_tag_facts) before Ansible 2.9. The usage did not change. -author: "Abhijeet Kasurde (@Akasurde)" -options: - tag_name: - description: - - Tag name that can be used to identify and reference a tag. - required: false -requirements: - - "python >= 2.6" -extends_documentation_fragment: -- community.general.digital_ocean.documentation - -''' - - -EXAMPLES = ''' -- name: Gather information about all tags - digital_ocean_tag_info: - oauth_token: "{{ oauth_token }}" - -- name: Gather information about tag with given name - digital_ocean_tag_info: - oauth_token: "{{ oauth_token }}" - tag_name: "extra_awesome_tag" - -- name: Get resources from tag name - digital_ocean_tag_info: - register: resp_out -- set_fact: - resources: "{{ item.resources }}" - loop: "{{ resp_out.data|json_query(name) }}" - vars: - name: "[?name=='extra_awesome_tag']" -- debug: var=resources -''' - - -RETURN = ''' -data: - description: DigitalOcean tag information - returned: success - type: list - sample: [ - { - "name": "extra-awesome", - "resources": { - "droplets": { - "count": 1, - ... - } - } - }, - ] -''' - -from traceback import format_exc -from ansible.module_utils.basic import AnsibleModule -from ansible_collections.community.general.plugins.module_utils.digital_ocean import DigitalOceanHelper -from ansible.module_utils._text import to_native - - -def core(module): - tag_name = module.params.get('tag_name', None) - rest = DigitalOceanHelper(module) - - base_url = 'tags' - if tag_name is not None: - response = rest.get("%s/%s" % (base_url, tag_name)) - status_code = response.status_code - - if status_code != 200: - module.fail_json(msg="Failed to retrieve tags for DigitalOcean") - - resp_json = response.json - tag = resp_json['tag'] - else: - tag = rest.get_paginated_data(base_url=base_url + '?', data_key_name='tags') - - module.exit_json(changed=False, data=tag) - - -def main(): - argument_spec = DigitalOceanHelper.digital_ocean_argument_spec() - argument_spec.update( - tag_name=dict(type='str', required=False), - ) - module = AnsibleModule(argument_spec=argument_spec) - if module._name in ('digital_ocean_tag_facts', 'community.general.digital_ocean_tag_facts'): - module.deprecate("The 'digital_ocean_tag_facts' module has been renamed to 'digital_ocean_tag_info'", - version='3.0.0', collection_name='community.general') # was Ansible 2.13 - - try: - core(module) - except Exception as e: - module.fail_json(msg=to_native(e), exception=format_exc()) - - -if __name__ == '__main__': - main() diff --git a/plugins/modules/cloud/digital_ocean/digital_ocean_volume_facts.py b/plugins/modules/cloud/digital_ocean/digital_ocean_volume_facts.py deleted file mode 120000 index b6491ad79e..0000000000 --- a/plugins/modules/cloud/digital_ocean/digital_ocean_volume_facts.py +++ /dev/null @@ -1 +0,0 @@ -digital_ocean_volume_info.py \ No newline at end of file diff --git a/plugins/modules/cloud/digital_ocean/digital_ocean_volume_info.py b/plugins/modules/cloud/digital_ocean/digital_ocean_volume_info.py deleted file mode 100644 index 476233ddfd..0000000000 --- a/plugins/modules/cloud/digital_ocean/digital_ocean_volume_info.py +++ /dev/null @@ -1,140 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -# Copyright: (c) 2018, Ansible Project -# Copyright: (c) 2018, Abhijeet Kasurde -# 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 = ''' ---- -module: digital_ocean_volume_info -short_description: Gather information about DigitalOcean volumes -description: - - This module can be used to gather information about DigitalOcean provided volumes. - - This module was called C(digital_ocean_volume_facts) before Ansible 2.9. The usage did not change. -author: "Abhijeet Kasurde (@Akasurde)" -options: - region_name: - description: - - Name of region to restrict results to volumes available in a specific region. - - Please use M(community.general.digital_ocean_region_info) for getting valid values related regions. - required: false - -requirements: - - "python >= 2.6" - -extends_documentation_fragment: -- community.general.digital_ocean.documentation - -''' - - -EXAMPLES = ''' -- name: Gather information about all volume - digital_ocean_volume_info: - oauth_token: "{{ oauth_token }}" - -- name: Gather information about volume in given region - digital_ocean_volume_info: - region_name: nyc1 - oauth_token: "{{ oauth_token }}" - -- name: Get information about volume named nyc3-test-volume - digital_ocean_volume_info: - register: resp_out -- set_fact: - volume_id: "{{ item.id }}" - loop: "{{ resp_out.data|json_query(name) }}" - vars: - name: "[?name=='nyc3-test-volume']" -- debug: var=volume_id -''' - - -RETURN = ''' -data: - description: DigitalOcean volume information - returned: success - type: list - sample: [ - { - "id": "506f78a4-e098-11e5-ad9f-000f53306ae1", - "region": { - "name": "New York 1", - "slug": "nyc1", - "sizes": [ - "s-1vcpu-1gb", - "s-1vcpu-2gb", - "s-1vcpu-3gb", - "s-2vcpu-2gb", - "s-3vcpu-1gb", - "s-2vcpu-4gb", - "s-4vcpu-8gb", - "s-6vcpu-16gb", - "s-8vcpu-32gb", - "s-12vcpu-48gb", - "s-16vcpu-64gb", - "s-20vcpu-96gb", - "s-24vcpu-128gb", - "s-32vcpu-192gb" - ], - "features": [ - "private_networking", - "backups", - "ipv6", - "metadata" - ], - "available": true - }, - "droplet_ids": [ - - ], - "name": "example", - "description": "Block store for examples", - "size_gigabytes": 10, - "created_at": "2016-03-02T17:00:49Z" - } - ] -''' - -from traceback import format_exc -from ansible.module_utils.basic import AnsibleModule -from ansible_collections.community.general.plugins.module_utils.digital_ocean import DigitalOceanHelper -from ansible.module_utils._text import to_native - - -def core(module): - region_name = module.params.get('region_name', None) - - rest = DigitalOceanHelper(module) - - base_url = 'volumes?' - if region_name is not None: - base_url += "region=%s&" % region_name - - volumes = rest.get_paginated_data(base_url=base_url, data_key_name='volumes') - - module.exit_json(changed=False, data=volumes) - - -def main(): - argument_spec = DigitalOceanHelper.digital_ocean_argument_spec() - argument_spec.update( - region_name=dict(type='str', required=False), - ) - module = AnsibleModule(argument_spec=argument_spec) - if module._name in ('digital_ocean_volume_facts', 'community.general.digital_ocean_volume_facts'): - module.deprecate("The 'digital_ocean_volume_facts' module has been renamed to 'digital_ocean_volume_info'", - version='3.0.0', collection_name='community.general') # was Ansible 2.13 - - try: - core(module) - except Exception as e: - module.fail_json(msg=to_native(e), exception=format_exc()) - - -if __name__ == '__main__': - main() diff --git a/plugins/modules/digital_ocean.py b/plugins/modules/digital_ocean.py deleted file mode 120000 index 27ea82c415..0000000000 --- a/plugins/modules/digital_ocean.py +++ /dev/null @@ -1 +0,0 @@ -./cloud/digital_ocean/digital_ocean.py \ No newline at end of file diff --git a/plugins/modules/digital_ocean_account_facts.py b/plugins/modules/digital_ocean_account_facts.py deleted file mode 120000 index b334a7e051..0000000000 --- a/plugins/modules/digital_ocean_account_facts.py +++ /dev/null @@ -1 +0,0 @@ -cloud/digital_ocean/digital_ocean_account_facts.py \ No newline at end of file diff --git a/plugins/modules/digital_ocean_account_info.py b/plugins/modules/digital_ocean_account_info.py deleted file mode 120000 index a822ec6ab6..0000000000 --- a/plugins/modules/digital_ocean_account_info.py +++ /dev/null @@ -1 +0,0 @@ -./cloud/digital_ocean/digital_ocean_account_info.py \ No newline at end of file diff --git a/plugins/modules/digital_ocean_block_storage.py b/plugins/modules/digital_ocean_block_storage.py deleted file mode 120000 index a78dfb69f4..0000000000 --- a/plugins/modules/digital_ocean_block_storage.py +++ /dev/null @@ -1 +0,0 @@ -./cloud/digital_ocean/digital_ocean_block_storage.py \ No newline at end of file diff --git a/plugins/modules/digital_ocean_certificate.py b/plugins/modules/digital_ocean_certificate.py deleted file mode 120000 index 8f388c1d47..0000000000 --- a/plugins/modules/digital_ocean_certificate.py +++ /dev/null @@ -1 +0,0 @@ -./cloud/digital_ocean/digital_ocean_certificate.py \ No newline at end of file diff --git a/plugins/modules/digital_ocean_certificate_facts.py b/plugins/modules/digital_ocean_certificate_facts.py deleted file mode 120000 index 6fe8c17d9d..0000000000 --- a/plugins/modules/digital_ocean_certificate_facts.py +++ /dev/null @@ -1 +0,0 @@ -cloud/digital_ocean/digital_ocean_certificate_facts.py \ No newline at end of file diff --git a/plugins/modules/digital_ocean_certificate_info.py b/plugins/modules/digital_ocean_certificate_info.py deleted file mode 120000 index f985a9a1e3..0000000000 --- a/plugins/modules/digital_ocean_certificate_info.py +++ /dev/null @@ -1 +0,0 @@ -./cloud/digital_ocean/digital_ocean_certificate_info.py \ No newline at end of file diff --git a/plugins/modules/digital_ocean_domain.py b/plugins/modules/digital_ocean_domain.py deleted file mode 120000 index 40d5e575f5..0000000000 --- a/plugins/modules/digital_ocean_domain.py +++ /dev/null @@ -1 +0,0 @@ -./cloud/digital_ocean/digital_ocean_domain.py \ No newline at end of file diff --git a/plugins/modules/digital_ocean_domain_facts.py b/plugins/modules/digital_ocean_domain_facts.py deleted file mode 120000 index 2638e3c7c9..0000000000 --- a/plugins/modules/digital_ocean_domain_facts.py +++ /dev/null @@ -1 +0,0 @@ -cloud/digital_ocean/digital_ocean_domain_facts.py \ No newline at end of file diff --git a/plugins/modules/digital_ocean_domain_info.py b/plugins/modules/digital_ocean_domain_info.py deleted file mode 120000 index 02659ae64f..0000000000 --- a/plugins/modules/digital_ocean_domain_info.py +++ /dev/null @@ -1 +0,0 @@ -./cloud/digital_ocean/digital_ocean_domain_info.py \ No newline at end of file diff --git a/plugins/modules/digital_ocean_droplet.py b/plugins/modules/digital_ocean_droplet.py deleted file mode 120000 index c25ac0e790..0000000000 --- a/plugins/modules/digital_ocean_droplet.py +++ /dev/null @@ -1 +0,0 @@ -./cloud/digital_ocean/digital_ocean_droplet.py \ No newline at end of file diff --git a/plugins/modules/digital_ocean_firewall_facts.py b/plugins/modules/digital_ocean_firewall_facts.py deleted file mode 120000 index 5325d7394c..0000000000 --- a/plugins/modules/digital_ocean_firewall_facts.py +++ /dev/null @@ -1 +0,0 @@ -cloud/digital_ocean/digital_ocean_firewall_facts.py \ No newline at end of file diff --git a/plugins/modules/digital_ocean_firewall_info.py b/plugins/modules/digital_ocean_firewall_info.py deleted file mode 120000 index a0d0808bf2..0000000000 --- a/plugins/modules/digital_ocean_firewall_info.py +++ /dev/null @@ -1 +0,0 @@ -./cloud/digital_ocean/digital_ocean_firewall_info.py \ No newline at end of file diff --git a/plugins/modules/digital_ocean_floating_ip.py b/plugins/modules/digital_ocean_floating_ip.py deleted file mode 120000 index fe65adb798..0000000000 --- a/plugins/modules/digital_ocean_floating_ip.py +++ /dev/null @@ -1 +0,0 @@ -./cloud/digital_ocean/digital_ocean_floating_ip.py \ No newline at end of file diff --git a/plugins/modules/digital_ocean_floating_ip_facts.py b/plugins/modules/digital_ocean_floating_ip_facts.py deleted file mode 120000 index d66a97f6c0..0000000000 --- a/plugins/modules/digital_ocean_floating_ip_facts.py +++ /dev/null @@ -1 +0,0 @@ -cloud/digital_ocean/digital_ocean_floating_ip_facts.py \ No newline at end of file diff --git a/plugins/modules/digital_ocean_floating_ip_info.py b/plugins/modules/digital_ocean_floating_ip_info.py deleted file mode 120000 index 4a9b737f3a..0000000000 --- a/plugins/modules/digital_ocean_floating_ip_info.py +++ /dev/null @@ -1 +0,0 @@ -./cloud/digital_ocean/digital_ocean_floating_ip_info.py \ No newline at end of file diff --git a/plugins/modules/digital_ocean_image_facts.py b/plugins/modules/digital_ocean_image_facts.py deleted file mode 120000 index 5661926625..0000000000 --- a/plugins/modules/digital_ocean_image_facts.py +++ /dev/null @@ -1 +0,0 @@ -cloud/digital_ocean/digital_ocean_image_facts.py \ No newline at end of file diff --git a/plugins/modules/digital_ocean_image_info.py b/plugins/modules/digital_ocean_image_info.py deleted file mode 120000 index 4dde9e1c72..0000000000 --- a/plugins/modules/digital_ocean_image_info.py +++ /dev/null @@ -1 +0,0 @@ -./cloud/digital_ocean/digital_ocean_image_info.py \ No newline at end of file diff --git a/plugins/modules/digital_ocean_load_balancer_facts.py b/plugins/modules/digital_ocean_load_balancer_facts.py deleted file mode 120000 index 851bff1902..0000000000 --- a/plugins/modules/digital_ocean_load_balancer_facts.py +++ /dev/null @@ -1 +0,0 @@ -cloud/digital_ocean/digital_ocean_load_balancer_facts.py \ No newline at end of file diff --git a/plugins/modules/digital_ocean_load_balancer_info.py b/plugins/modules/digital_ocean_load_balancer_info.py deleted file mode 120000 index fb2ac11d68..0000000000 --- a/plugins/modules/digital_ocean_load_balancer_info.py +++ /dev/null @@ -1 +0,0 @@ -./cloud/digital_ocean/digital_ocean_load_balancer_info.py \ No newline at end of file diff --git a/plugins/modules/digital_ocean_region_facts.py b/plugins/modules/digital_ocean_region_facts.py deleted file mode 120000 index fad46627fd..0000000000 --- a/plugins/modules/digital_ocean_region_facts.py +++ /dev/null @@ -1 +0,0 @@ -cloud/digital_ocean/digital_ocean_region_facts.py \ No newline at end of file diff --git a/plugins/modules/digital_ocean_region_info.py b/plugins/modules/digital_ocean_region_info.py deleted file mode 120000 index 738834aa4f..0000000000 --- a/plugins/modules/digital_ocean_region_info.py +++ /dev/null @@ -1 +0,0 @@ -./cloud/digital_ocean/digital_ocean_region_info.py \ No newline at end of file diff --git a/plugins/modules/digital_ocean_size_facts.py b/plugins/modules/digital_ocean_size_facts.py deleted file mode 120000 index ae6777b916..0000000000 --- a/plugins/modules/digital_ocean_size_facts.py +++ /dev/null @@ -1 +0,0 @@ -cloud/digital_ocean/digital_ocean_size_facts.py \ No newline at end of file diff --git a/plugins/modules/digital_ocean_size_info.py b/plugins/modules/digital_ocean_size_info.py deleted file mode 120000 index fc24946af9..0000000000 --- a/plugins/modules/digital_ocean_size_info.py +++ /dev/null @@ -1 +0,0 @@ -./cloud/digital_ocean/digital_ocean_size_info.py \ No newline at end of file diff --git a/plugins/modules/digital_ocean_snapshot_facts.py b/plugins/modules/digital_ocean_snapshot_facts.py deleted file mode 120000 index 921c2c71e3..0000000000 --- a/plugins/modules/digital_ocean_snapshot_facts.py +++ /dev/null @@ -1 +0,0 @@ -cloud/digital_ocean/digital_ocean_snapshot_facts.py \ No newline at end of file diff --git a/plugins/modules/digital_ocean_snapshot_info.py b/plugins/modules/digital_ocean_snapshot_info.py deleted file mode 120000 index e9057572cf..0000000000 --- a/plugins/modules/digital_ocean_snapshot_info.py +++ /dev/null @@ -1 +0,0 @@ -./cloud/digital_ocean/digital_ocean_snapshot_info.py \ No newline at end of file diff --git a/plugins/modules/digital_ocean_sshkey.py b/plugins/modules/digital_ocean_sshkey.py deleted file mode 120000 index 4cb8d2d4cd..0000000000 --- a/plugins/modules/digital_ocean_sshkey.py +++ /dev/null @@ -1 +0,0 @@ -./cloud/digital_ocean/digital_ocean_sshkey.py \ No newline at end of file diff --git a/plugins/modules/digital_ocean_sshkey_facts.py b/plugins/modules/digital_ocean_sshkey_facts.py deleted file mode 120000 index 191339fbda..0000000000 --- a/plugins/modules/digital_ocean_sshkey_facts.py +++ /dev/null @@ -1 +0,0 @@ -./cloud/digital_ocean/digital_ocean_sshkey_facts.py \ No newline at end of file diff --git a/plugins/modules/digital_ocean_sshkey_info.py b/plugins/modules/digital_ocean_sshkey_info.py deleted file mode 120000 index ab6de775f5..0000000000 --- a/plugins/modules/digital_ocean_sshkey_info.py +++ /dev/null @@ -1 +0,0 @@ -./cloud/digital_ocean/digital_ocean_sshkey_info.py \ No newline at end of file diff --git a/plugins/modules/digital_ocean_tag.py b/plugins/modules/digital_ocean_tag.py deleted file mode 120000 index bac1891333..0000000000 --- a/plugins/modules/digital_ocean_tag.py +++ /dev/null @@ -1 +0,0 @@ -./cloud/digital_ocean/digital_ocean_tag.py \ No newline at end of file diff --git a/plugins/modules/digital_ocean_tag_facts.py b/plugins/modules/digital_ocean_tag_facts.py deleted file mode 120000 index 857d6d15d0..0000000000 --- a/plugins/modules/digital_ocean_tag_facts.py +++ /dev/null @@ -1 +0,0 @@ -cloud/digital_ocean/digital_ocean_tag_facts.py \ No newline at end of file diff --git a/plugins/modules/digital_ocean_tag_info.py b/plugins/modules/digital_ocean_tag_info.py deleted file mode 120000 index 8c8b92f80c..0000000000 --- a/plugins/modules/digital_ocean_tag_info.py +++ /dev/null @@ -1 +0,0 @@ -./cloud/digital_ocean/digital_ocean_tag_info.py \ No newline at end of file diff --git a/plugins/modules/digital_ocean_volume_facts.py b/plugins/modules/digital_ocean_volume_facts.py deleted file mode 120000 index 62176608ee..0000000000 --- a/plugins/modules/digital_ocean_volume_facts.py +++ /dev/null @@ -1 +0,0 @@ -cloud/digital_ocean/digital_ocean_volume_facts.py \ No newline at end of file diff --git a/plugins/modules/digital_ocean_volume_info.py b/plugins/modules/digital_ocean_volume_info.py deleted file mode 120000 index 9afe31e46d..0000000000 --- a/plugins/modules/digital_ocean_volume_info.py +++ /dev/null @@ -1 +0,0 @@ -./cloud/digital_ocean/digital_ocean_volume_info.py \ No newline at end of file diff --git a/scripts/inventory/digital_ocean.ini b/scripts/inventory/digital_ocean.ini deleted file mode 100644 index b809554b20..0000000000 --- a/scripts/inventory/digital_ocean.ini +++ /dev/null @@ -1,34 +0,0 @@ -# Ansible DigitalOcean external inventory script settings -# - -[digital_ocean] - -# The module needs your DigitalOcean API Token. -# It may also be specified on the command line via --api-token -# or via the environment variables DO_API_TOKEN or DO_API_KEY -# -#api_token = 123456abcdefg - - -# API calls to DigitalOcean may be slow. For this reason, we cache the results -# of an API call. Set this to the path you want cache files to be written to. -# One file will be written to this directory: -# - ansible-digital_ocean.cache -# -cache_path = /tmp - - -# The number of seconds a cache file is considered valid. After this many -# seconds, a new API call will be made, and the cache file will be updated. -# -cache_max_age = 300 - -# Use the private network IP address instead of the public when available. -# -use_private_network = False - -# Pass variables to every group, e.g.: -# -# group_variables = { 'ansible_user': 'root' } -# -group_variables = {} diff --git a/scripts/inventory/digital_ocean.py b/scripts/inventory/digital_ocean.py deleted file mode 100644 index 383b329a11..0000000000 --- a/scripts/inventory/digital_ocean.py +++ /dev/null @@ -1,541 +0,0 @@ -#!/usr/bin/env python - -""" -DigitalOcean external inventory script -====================================== - -Generates Ansible inventory of DigitalOcean Droplets. - -In addition to the --list and --host options used by Ansible, there are options -for generating JSON of other DigitalOcean data. This is useful when creating -droplets. For example, --regions will return all the DigitalOcean Regions. -This information can also be easily found in the cache file, whose default -location is /tmp/ansible-digital_ocean.cache). - -The --pretty (-p) option pretty-prints the output for better human readability. - ----- -Although the cache stores all the information received from DigitalOcean, -the cache is not used for current droplet information (in --list, --host, ---all, and --droplets). This is so that accurate droplet information is always -found. You can force this script to use the cache with --force-cache. - ----- -Configuration is read from `digital_ocean.ini`, then from environment variables, -and then from command-line arguments. - -Most notably, the DigitalOcean API Token must be specified. It can be specified -in the INI file or with the following environment variables: - export DO_API_TOKEN='abc123' or - export DO_API_KEY='abc123' - -Alternatively, it can be passed on the command-line with --api-token. - -If you specify DigitalOcean credentials in the INI file, a handy way to -get them into your environment (e.g., to use the digital_ocean module) -is to use the output of the --env option with export: - export $(digital_ocean.py --env) - ----- -The following groups are generated from --list: - - ID (droplet ID) - - NAME (droplet NAME) - - digital_ocean - - image_ID - - image_NAME - - distro_NAME (distribution NAME from image) - - region_NAME - - size_NAME - - status_STATUS - -For each host, the following variables are registered: - - do_backup_ids - - do_created_at - - do_disk - - do_features - list - - do_id - - do_image - object - - do_ip_address - - do_private_ip_address - - do_kernel - object - - do_locked - - do_memory - - do_name - - do_networks - object - - do_next_backup_window - - do_region - object - - do_size - object - - do_size_slug - - do_snapshot_ids - list - - do_status - - do_tags - - do_vcpus - - do_volume_ids - ------ -``` -usage: digital_ocean.py [-h] [--list] [--host HOST] [--all] [--droplets] - [--regions] [--images] [--sizes] [--ssh-keys] - [--domains] [--tags] [--pretty] - [--cache-path CACHE_PATH] - [--cache-max_age CACHE_MAX_AGE] [--force-cache] - [--refresh-cache] [--env] [--api-token API_TOKEN] - -Produce an Ansible Inventory file based on DigitalOcean credentials - -optional arguments: - -h, --help show this help message and exit - --list List all active Droplets as Ansible inventory - (default: True) - --host HOST Get all Ansible inventory variables about a specific - Droplet - --all List all DigitalOcean information as JSON - --droplets, -d List Droplets as JSON - --regions List Regions as JSON - --images List Images as JSON - --sizes List Sizes as JSON - --ssh-keys List SSH keys as JSON - --domains List Domains as JSON - --tags List Tags as JSON - --pretty, -p Pretty-print results - --cache-path CACHE_PATH - Path to the cache files (default: .) - --cache-max_age CACHE_MAX_AGE - Maximum age of the cached items (default: 0) - --force-cache Only use data from the cache - --refresh-cache, -r Force refresh of cache by making API requests to - DigitalOcean (default: False - use cache files) - --env, -e Display DO_API_TOKEN - --api-token API_TOKEN, -a API_TOKEN - DigitalOcean API Token -``` - -""" - -# (c) 2013, Evan Wies -# (c) 2017, Ansible Project -# (c) 2017, Abhijeet Kasurde -# -# Inspired by the EC2 inventory plugin: -# https://github.com/ansible/ansible/blob/devel/contrib/inventory/ec2.py -# -# 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 - -###################################################################### - -import argparse -import ast -import os -import re -import requests -import sys -from time import time - -try: - import ConfigParser -except ImportError: - import configparser as ConfigParser - -import json - - -class DoManager: - def __init__(self, api_token): - self.api_token = api_token - self.api_endpoint = 'https://api.digitalocean.com/v2' - self.headers = {'Authorization': 'Bearer {0}'.format(self.api_token), - 'Content-type': 'application/json'} - self.timeout = 60 - - def _url_builder(self, path): - if path[0] == '/': - path = path[1:] - return '%s/%s' % (self.api_endpoint, path) - - def send(self, url, method='GET', data=None): - url = self._url_builder(url) - data = json.dumps(data) - try: - if method == 'GET': - resp_data = {} - incomplete = True - while incomplete: - resp = requests.get(url, data=data, headers=self.headers, timeout=self.timeout) - json_resp = resp.json() - - for key, value in json_resp.items(): - if isinstance(value, list) and key in resp_data: - resp_data[key] += value - else: - resp_data[key] = value - - try: - url = json_resp['links']['pages']['next'] - except KeyError: - incomplete = False - - except ValueError as e: - sys.exit("Unable to parse result from %s: %s" % (url, e)) - return resp_data - - def all_active_droplets(self): - resp = self.send('droplets/') - return resp['droplets'] - - def all_regions(self): - resp = self.send('regions/') - return resp['regions'] - - def all_images(self, filter_name='global'): - params = {'filter': filter_name} - resp = self.send('images/', data=params) - return resp['images'] - - def sizes(self): - resp = self.send('sizes/') - return resp['sizes'] - - def all_ssh_keys(self): - resp = self.send('account/keys') - return resp['ssh_keys'] - - def all_domains(self): - resp = self.send('domains/') - return resp['domains'] - - def show_droplet(self, droplet_id): - resp = self.send('droplets/%s' % droplet_id) - return resp['droplet'] - - def all_tags(self): - resp = self.send('tags') - return resp['tags'] - - -class DigitalOceanInventory(object): - - ########################################################################### - # Main execution path - ########################################################################### - - def __init__(self): - """Main execution path """ - - # DigitalOceanInventory data - self.data = {} # All DigitalOcean data - self.inventory = {} # Ansible Inventory - - # Define defaults - self.cache_path = '.' - self.cache_max_age = 0 - self.use_private_network = False - self.group_variables = {} - - # Read settings, environment variables, and CLI arguments - self.read_settings() - self.read_environment() - self.read_cli_args() - - # Verify credentials were set - if not hasattr(self, 'api_token'): - msg = 'Could not find values for DigitalOcean api_token. They must be specified via either ini file, ' \ - 'command line argument (--api-token), or environment variables (DO_API_TOKEN)\n' - sys.stderr.write(msg) - sys.exit(-1) - - # env command, show DigitalOcean credentials - if self.args.env: - print("DO_API_TOKEN=%s" % self.api_token) - sys.exit(0) - - # Manage cache - self.cache_filename = self.cache_path + "/ansible-digital_ocean.cache" - self.cache_refreshed = False - - if self.is_cache_valid(): - self.load_from_cache() - if len(self.data) == 0: - if self.args.force_cache: - sys.stderr.write('Cache is empty and --force-cache was specified\n') - sys.exit(-1) - - self.manager = DoManager(self.api_token) - - # Pick the json_data to print based on the CLI command - if self.args.droplets: - self.load_from_digital_ocean('droplets') - json_data = {'droplets': self.data['droplets']} - elif self.args.regions: - self.load_from_digital_ocean('regions') - json_data = {'regions': self.data['regions']} - elif self.args.images: - self.load_from_digital_ocean('images') - json_data = {'images': self.data['images']} - elif self.args.sizes: - self.load_from_digital_ocean('sizes') - json_data = {'sizes': self.data['sizes']} - elif self.args.ssh_keys: - self.load_from_digital_ocean('ssh_keys') - json_data = {'ssh_keys': self.data['ssh_keys']} - elif self.args.domains: - self.load_from_digital_ocean('domains') - json_data = {'domains': self.data['domains']} - elif self.args.tags: - self.load_from_digital_ocean('tags') - json_data = {'tags': self.data['tags']} - elif self.args.all: - self.load_from_digital_ocean() - json_data = self.data - elif self.args.host: - json_data = self.load_droplet_variables_for_host() - else: # '--list' this is last to make it default - self.load_from_digital_ocean('droplets') - self.build_inventory() - json_data = self.inventory - - if self.cache_refreshed: - self.write_to_cache() - - if self.args.pretty: - print(json.dumps(json_data, indent=2)) - else: - print(json.dumps(json_data)) - - ########################################################################### - # Script configuration - ########################################################################### - - def read_settings(self): - """ Reads the settings from the digital_ocean.ini file """ - config = ConfigParser.ConfigParser() - config_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'digital_ocean.ini') - config.read(config_path) - - # Credentials - if config.has_option('digital_ocean', 'api_token'): - self.api_token = config.get('digital_ocean', 'api_token') - - # Cache related - if config.has_option('digital_ocean', 'cache_path'): - self.cache_path = config.get('digital_ocean', 'cache_path') - if config.has_option('digital_ocean', 'cache_max_age'): - self.cache_max_age = config.getint('digital_ocean', 'cache_max_age') - - # Private IP Address - if config.has_option('digital_ocean', 'use_private_network'): - self.use_private_network = config.getboolean('digital_ocean', 'use_private_network') - - # Group variables - if config.has_option('digital_ocean', 'group_variables'): - self.group_variables = ast.literal_eval(config.get('digital_ocean', 'group_variables')) - - def read_environment(self): - """ Reads the settings from environment variables """ - # Setup credentials - if os.getenv("DO_API_TOKEN"): - self.api_token = os.getenv("DO_API_TOKEN") - if os.getenv("DO_API_KEY"): - self.api_token = os.getenv("DO_API_KEY") - - def read_cli_args(self): - """ Command line argument processing """ - parser = argparse.ArgumentParser(description='Produce an Ansible Inventory file based on DigitalOcean credentials') - - parser.add_argument('--list', action='store_true', help='List all active Droplets as Ansible inventory (default: True)') - parser.add_argument('--host', action='store', help='Get all Ansible inventory variables about a specific Droplet') - - parser.add_argument('--all', action='store_true', help='List all DigitalOcean information as JSON') - parser.add_argument('--droplets', '-d', action='store_true', help='List Droplets as JSON') - parser.add_argument('--regions', action='store_true', help='List Regions as JSON') - parser.add_argument('--images', action='store_true', help='List Images as JSON') - parser.add_argument('--sizes', action='store_true', help='List Sizes as JSON') - parser.add_argument('--ssh-keys', action='store_true', help='List SSH keys as JSON') - parser.add_argument('--domains', action='store_true', help='List Domains as JSON') - parser.add_argument('--tags', action='store_true', help='List Tags as JSON') - - parser.add_argument('--pretty', '-p', action='store_true', help='Pretty-print results') - - parser.add_argument('--cache-path', action='store', help='Path to the cache files (default: .)') - parser.add_argument('--cache-max_age', action='store', help='Maximum age of the cached items (default: 0)') - parser.add_argument('--force-cache', action='store_true', default=False, help='Only use data from the cache') - parser.add_argument('--refresh-cache', '-r', action='store_true', default=False, - help='Force refresh of cache by making API requests to DigitalOcean (default: False - use cache files)') - - parser.add_argument('--env', '-e', action='store_true', help='Display DO_API_TOKEN') - parser.add_argument('--api-token', '-a', action='store', help='DigitalOcean API Token') - - self.args = parser.parse_args() - - if self.args.api_token: - self.api_token = self.args.api_token - - # Make --list default if none of the other commands are specified - if (not self.args.droplets and not self.args.regions and - not self.args.images and not self.args.sizes and - not self.args.ssh_keys and not self.args.domains and - not self.args.tags and - not self.args.all and not self.args.host): - self.args.list = True - - ########################################################################### - # Data Management - ########################################################################### - - def load_from_digital_ocean(self, resource=None): - """Get JSON from DigitalOcean API """ - if self.args.force_cache and os.path.isfile(self.cache_filename): - return - # We always get fresh droplets - if self.is_cache_valid() and not (resource == 'droplets' or resource is None): - return - if self.args.refresh_cache: - resource = None - - if resource == 'droplets' or resource is None: - self.data['droplets'] = self.manager.all_active_droplets() - self.cache_refreshed = True - if resource == 'regions' or resource is None: - self.data['regions'] = self.manager.all_regions() - self.cache_refreshed = True - if resource == 'images' or resource is None: - self.data['images'] = self.manager.all_images() - self.cache_refreshed = True - if resource == 'sizes' or resource is None: - self.data['sizes'] = self.manager.sizes() - self.cache_refreshed = True - if resource == 'ssh_keys' or resource is None: - self.data['ssh_keys'] = self.manager.all_ssh_keys() - self.cache_refreshed = True - if resource == 'domains' or resource is None: - self.data['domains'] = self.manager.all_domains() - self.cache_refreshed = True - if resource == 'tags' or resource is None: - self.data['tags'] = self.manager.all_tags() - self.cache_refreshed = True - - def add_inventory_group(self, key): - """ Method to create group dict """ - host_dict = {'hosts': [], 'vars': {}} - self.inventory[key] = host_dict - return - - def add_host(self, group, host): - """ Helper method to reduce host duplication """ - if group not in self.inventory: - self.add_inventory_group(group) - - if host not in self.inventory[group]['hosts']: - self.inventory[group]['hosts'].append(host) - return - - def build_inventory(self): - """ Build Ansible inventory of droplets """ - self.inventory = { - 'all': { - 'hosts': [], - 'vars': self.group_variables - }, - '_meta': {'hostvars': {}} - } - - # add all droplets by id and name - for droplet in self.data['droplets']: - for net in droplet['networks']['v4']: - if net['type'] == 'public': - dest = net['ip_address'] - else: - continue - - self.inventory['all']['hosts'].append(dest) - - self.add_host(droplet['id'], dest) - - self.add_host(droplet['name'], dest) - - # groups that are always present - for group in ('digital_ocean', - 'region_' + droplet['region']['slug'], - 'image_' + str(droplet['image']['id']), - 'size_' + droplet['size']['slug'], - 'distro_' + DigitalOceanInventory.to_safe(droplet['image']['distribution']), - 'status_' + droplet['status']): - self.add_host(group, dest) - - # groups that are not always present - for group in (droplet['image']['slug'], - droplet['image']['name']): - if group: - image = 'image_' + DigitalOceanInventory.to_safe(group) - self.add_host(image, dest) - - if droplet['tags']: - for tag in droplet['tags']: - self.add_host(tag, dest) - - # hostvars - info = self.do_namespace(droplet) - self.inventory['_meta']['hostvars'][dest] = info - - def load_droplet_variables_for_host(self): - """ Generate a JSON response to a --host call """ - host = int(self.args.host) - droplet = self.manager.show_droplet(host) - info = self.do_namespace(droplet) - return {'droplet': info} - - ########################################################################### - # Cache Management - ########################################################################### - - def is_cache_valid(self): - """ Determines if the cache files have expired, or if it is still valid """ - if os.path.isfile(self.cache_filename): - mod_time = os.path.getmtime(self.cache_filename) - current_time = time() - if (mod_time + self.cache_max_age) > current_time: - return True - return False - - def load_from_cache(self): - """ Reads the data from the cache file and assigns it to member variables as Python Objects """ - try: - with open(self.cache_filename, 'r') as cache: - json_data = cache.read() - data = json.loads(json_data) - except IOError: - data = {'data': {}, 'inventory': {}} - - self.data = data['data'] - self.inventory = data['inventory'] - - def write_to_cache(self): - """ Writes data in JSON format to a file """ - data = {'data': self.data, 'inventory': self.inventory} - json_data = json.dumps(data, indent=2) - - with open(self.cache_filename, 'w') as cache: - cache.write(json_data) - - ########################################################################### - # Utilities - ########################################################################### - @staticmethod - def to_safe(word): - """ Converts 'bad' characters in a string to underscores so they can be used as Ansible groups """ - return re.sub(r"[^A-Za-z0-9\-.]", "_", word) - - @staticmethod - def do_namespace(data): - """ Returns a copy of the dictionary with all the keys put in a 'do_' namespace """ - info = {} - for k, v in data.items(): - info['do_' + k] = v - return info - - -########################################################################### -# Run the script -DigitalOceanInventory() diff --git a/tests/integration/targets/digital_ocean_floating_ip/aliases b/tests/integration/targets/digital_ocean_floating_ip/aliases deleted file mode 100644 index ad7ccf7ada..0000000000 --- a/tests/integration/targets/digital_ocean_floating_ip/aliases +++ /dev/null @@ -1 +0,0 @@ -unsupported diff --git a/tests/integration/targets/digital_ocean_floating_ip/tasks/main.yml b/tests/integration/targets/digital_ocean_floating_ip/tasks/main.yml deleted file mode 100644 index 91b10d7726..0000000000 --- a/tests/integration/targets/digital_ocean_floating_ip/tasks/main.yml +++ /dev/null @@ -1,42 +0,0 @@ ---- -- name: Test API key is provided. - fail: - msg: do_api_key should be defined in integration_config.yml - when: do_api_key is not defined - -- name: "Make sure that the Floating IP is absent" - digital_ocean_floating_ip: - state: absent - ip: "8.8.8.8" - oauth_token: "{{ do_api_key }}" - register: result - -- name: Verify that the Floating IP didn't change - assert: - that: - - "not result.changed" - -- name: "Create a Floating IP" - digital_ocean_floating_ip: - state: present - region: "lon1" - oauth_token: "{{ do_api_key }}" - register: result - -- name: Verify that a Floating IP was created - assert: - that: - - "result.changed" - -- name: "Destroy Floating IP" - digital_ocean_floating_ip: - state: absent - ip: "{{ result.data.floating_ip.ip }}" - region: "lon1" - oauth_token: "{{ do_api_key }}" - register: result - -- name: Verify that a Floating IP was deleted - assert: - that: - - " result.changed" diff --git a/tests/integration/targets/digital_ocean_sshkey/aliases b/tests/integration/targets/digital_ocean_sshkey/aliases deleted file mode 100644 index ad7ccf7ada..0000000000 --- a/tests/integration/targets/digital_ocean_sshkey/aliases +++ /dev/null @@ -1 +0,0 @@ -unsupported diff --git a/tests/integration/targets/digital_ocean_sshkey/tasks/main.yml b/tests/integration/targets/digital_ocean_sshkey/tasks/main.yml deleted file mode 100644 index ce82c20813..0000000000 --- a/tests/integration/targets/digital_ocean_sshkey/tasks/main.yml +++ /dev/null @@ -1,29 +0,0 @@ ---- -- name: Test API key is provided. - fail: - msg: do_api_key should be defined in integration_config.yml - when: do_api_key is not defined - -- name: Create ssh key - digital_ocean_sshkey: - name: test-key1 - ssh_pub_key: "{{ dummy_ssh_pub_key }}" - oauth_token: "{{ do_api_key }}" - register: result - -- name: Verify that SSH key was created - assert: - that: - - "result.changed" - -- name: "Delete ssh key" - digital_ocean_sshkey: - state: "absent" - fingerprint: "{{ result.data.ssh_key.fingerprint }}" - oauth_token: "{{ do_api_key }}" - register: result - -- name: Verify that SSH key was deleted - assert: - that: - - "result.changed" diff --git a/tests/integration/targets/digital_ocean_tag/aliases b/tests/integration/targets/digital_ocean_tag/aliases deleted file mode 100644 index 6320774d67..0000000000 --- a/tests/integration/targets/digital_ocean_tag/aliases +++ /dev/null @@ -1,2 +0,0 @@ -digital_ocean -unsupported diff --git a/tests/integration/targets/digital_ocean_tag/tasks/main.yml b/tests/integration/targets/digital_ocean_tag/tasks/main.yml deleted file mode 100644 index aea355facc..0000000000 --- a/tests/integration/targets/digital_ocean_tag/tasks/main.yml +++ /dev/null @@ -1,51 +0,0 @@ ---- -- block: - - name: Test API key is provided. - fail: - msg: do_api_key should be defined in integration_config.yml - when: do_api_key is not defined - - - name: Create a new tag - digital_ocean_tag: - oauth_token: '{{do_api_key}}' - name: integration-test - state: present - register: create_tag - - - name: Create a new tag for idempotency - digital_ocean_tag: - oauth_token: '{{do_api_key}}' - name: integration-test - state: present - register: create_tag_idempotent - - - debug: - var: create_tag - - - assert: - that: - - create_tag.changed == True - - create_tag_idempotent.changed == False - - create_tag.data.tag.name == "integration-test" - - always: - - name: Delete tag - digital_ocean_tag: - oauth_token: '{{do_api_key}}' - name: integration-test - state: absent - register: delete_tag - -# FIXME: Deleting a tag isn't idempotent -# - name: Delete tag with idempotency -# digital_ocean_tag: -# oauth_token: '{{do_api_key}}' -# name: integration-test -# state: absent -# register: delete_tag_idempotent - - - assert: - that: - - delete_tag.changed == True -# FIXME: Deleting a tag isn't idempotent -# - delete_tag_idempotent.changed == False diff --git a/tests/sanity/ignore-2.10.txt b/tests/sanity/ignore-2.10.txt index 3c08bc6d89..b865e42c86 100644 --- a/tests/sanity/ignore-2.10.txt +++ b/tests/sanity/ignore-2.10.txt @@ -46,40 +46,6 @@ plugins/modules/cloud/centurylink/clc_server_snapshot.py validate-modules:doc-mi plugins/modules/cloud/centurylink/clc_server_snapshot.py validate-modules:implied-parameter-type-mismatch plugins/modules/cloud/centurylink/clc_server_snapshot.py validate-modules:parameter-list-no-elements plugins/modules/cloud/centurylink/clc_server_snapshot.py validate-modules:parameter-type-not-in-doc -plugins/modules/cloud/digital_ocean/digital_ocean.py validate-modules:doc-missing-type -plugins/modules/cloud/digital_ocean/digital_ocean.py validate-modules:parameter-list-no-elements -plugins/modules/cloud/digital_ocean/digital_ocean.py validate-modules:parameter-type-not-in-doc -plugins/modules/cloud/digital_ocean/digital_ocean.py validate-modules:undocumented-parameter -plugins/modules/cloud/digital_ocean/digital_ocean_block_storage.py validate-modules:doc-missing-type -plugins/modules/cloud/digital_ocean/digital_ocean_block_storage.py validate-modules:doc-required-mismatch -plugins/modules/cloud/digital_ocean/digital_ocean_block_storage.py validate-modules:parameter-type-not-in-doc -plugins/modules/cloud/digital_ocean/digital_ocean_certificate.py validate-modules:doc-missing-type -plugins/modules/cloud/digital_ocean/digital_ocean_certificate.py validate-modules:doc-required-mismatch -plugins/modules/cloud/digital_ocean/digital_ocean_certificate.py validate-modules:parameter-type-not-in-doc -plugins/modules/cloud/digital_ocean/digital_ocean_certificate_info.py validate-modules:parameter-type-not-in-doc -plugins/modules/cloud/digital_ocean/digital_ocean_domain.py validate-modules:doc-missing-type -plugins/modules/cloud/digital_ocean/digital_ocean_domain.py validate-modules:parameter-type-not-in-doc -plugins/modules/cloud/digital_ocean/digital_ocean_domain_info.py validate-modules:parameter-type-not-in-doc -plugins/modules/cloud/digital_ocean/digital_ocean_droplet.py validate-modules:doc-missing-type -plugins/modules/cloud/digital_ocean/digital_ocean_droplet.py validate-modules:doc-required-mismatch -plugins/modules/cloud/digital_ocean/digital_ocean_droplet.py validate-modules:parameter-list-no-elements -plugins/modules/cloud/digital_ocean/digital_ocean_droplet.py validate-modules:parameter-type-not-in-doc -plugins/modules/cloud/digital_ocean/digital_ocean_firewall_info.py validate-modules:parameter-type-not-in-doc -plugins/modules/cloud/digital_ocean/digital_ocean_floating_ip.py validate-modules:doc-default-does-not-match-spec -plugins/modules/cloud/digital_ocean/digital_ocean_floating_ip.py validate-modules:doc-missing-type -plugins/modules/cloud/digital_ocean/digital_ocean_floating_ip.py validate-modules:parameter-type-not-in-doc -plugins/modules/cloud/digital_ocean/digital_ocean_floating_ip.py validate-modules:undocumented-parameter -plugins/modules/cloud/digital_ocean/digital_ocean_image_info.py validate-modules:parameter-type-not-in-doc -plugins/modules/cloud/digital_ocean/digital_ocean_load_balancer_info.py validate-modules:parameter-type-not-in-doc -plugins/modules/cloud/digital_ocean/digital_ocean_snapshot_info.py validate-modules:parameter-type-not-in-doc -plugins/modules/cloud/digital_ocean/digital_ocean_sshkey.py validate-modules:doc-default-does-not-match-spec -plugins/modules/cloud/digital_ocean/digital_ocean_sshkey.py validate-modules:doc-missing-type -plugins/modules/cloud/digital_ocean/digital_ocean_sshkey.py validate-modules:parameter-type-not-in-doc -plugins/modules/cloud/digital_ocean/digital_ocean_sshkey.py validate-modules:undocumented-parameter -plugins/modules/cloud/digital_ocean/digital_ocean_tag.py validate-modules:doc-missing-type -plugins/modules/cloud/digital_ocean/digital_ocean_tag.py validate-modules:parameter-type-not-in-doc -plugins/modules/cloud/digital_ocean/digital_ocean_tag_info.py validate-modules:parameter-type-not-in-doc -plugins/modules/cloud/digital_ocean/digital_ocean_volume_info.py validate-modules:parameter-type-not-in-doc plugins/modules/cloud/dimensiondata/dimensiondata_network.py validate-modules:doc-choices-do-not-match-spec plugins/modules/cloud/dimensiondata/dimensiondata_network.py validate-modules:doc-missing-type plugins/modules/cloud/dimensiondata/dimensiondata_network.py validate-modules:parameter-type-not-in-doc diff --git a/tests/sanity/ignore-2.11.txt b/tests/sanity/ignore-2.11.txt index 3c08bc6d89..b865e42c86 100644 --- a/tests/sanity/ignore-2.11.txt +++ b/tests/sanity/ignore-2.11.txt @@ -46,40 +46,6 @@ plugins/modules/cloud/centurylink/clc_server_snapshot.py validate-modules:doc-mi plugins/modules/cloud/centurylink/clc_server_snapshot.py validate-modules:implied-parameter-type-mismatch plugins/modules/cloud/centurylink/clc_server_snapshot.py validate-modules:parameter-list-no-elements plugins/modules/cloud/centurylink/clc_server_snapshot.py validate-modules:parameter-type-not-in-doc -plugins/modules/cloud/digital_ocean/digital_ocean.py validate-modules:doc-missing-type -plugins/modules/cloud/digital_ocean/digital_ocean.py validate-modules:parameter-list-no-elements -plugins/modules/cloud/digital_ocean/digital_ocean.py validate-modules:parameter-type-not-in-doc -plugins/modules/cloud/digital_ocean/digital_ocean.py validate-modules:undocumented-parameter -plugins/modules/cloud/digital_ocean/digital_ocean_block_storage.py validate-modules:doc-missing-type -plugins/modules/cloud/digital_ocean/digital_ocean_block_storage.py validate-modules:doc-required-mismatch -plugins/modules/cloud/digital_ocean/digital_ocean_block_storage.py validate-modules:parameter-type-not-in-doc -plugins/modules/cloud/digital_ocean/digital_ocean_certificate.py validate-modules:doc-missing-type -plugins/modules/cloud/digital_ocean/digital_ocean_certificate.py validate-modules:doc-required-mismatch -plugins/modules/cloud/digital_ocean/digital_ocean_certificate.py validate-modules:parameter-type-not-in-doc -plugins/modules/cloud/digital_ocean/digital_ocean_certificate_info.py validate-modules:parameter-type-not-in-doc -plugins/modules/cloud/digital_ocean/digital_ocean_domain.py validate-modules:doc-missing-type -plugins/modules/cloud/digital_ocean/digital_ocean_domain.py validate-modules:parameter-type-not-in-doc -plugins/modules/cloud/digital_ocean/digital_ocean_domain_info.py validate-modules:parameter-type-not-in-doc -plugins/modules/cloud/digital_ocean/digital_ocean_droplet.py validate-modules:doc-missing-type -plugins/modules/cloud/digital_ocean/digital_ocean_droplet.py validate-modules:doc-required-mismatch -plugins/modules/cloud/digital_ocean/digital_ocean_droplet.py validate-modules:parameter-list-no-elements -plugins/modules/cloud/digital_ocean/digital_ocean_droplet.py validate-modules:parameter-type-not-in-doc -plugins/modules/cloud/digital_ocean/digital_ocean_firewall_info.py validate-modules:parameter-type-not-in-doc -plugins/modules/cloud/digital_ocean/digital_ocean_floating_ip.py validate-modules:doc-default-does-not-match-spec -plugins/modules/cloud/digital_ocean/digital_ocean_floating_ip.py validate-modules:doc-missing-type -plugins/modules/cloud/digital_ocean/digital_ocean_floating_ip.py validate-modules:parameter-type-not-in-doc -plugins/modules/cloud/digital_ocean/digital_ocean_floating_ip.py validate-modules:undocumented-parameter -plugins/modules/cloud/digital_ocean/digital_ocean_image_info.py validate-modules:parameter-type-not-in-doc -plugins/modules/cloud/digital_ocean/digital_ocean_load_balancer_info.py validate-modules:parameter-type-not-in-doc -plugins/modules/cloud/digital_ocean/digital_ocean_snapshot_info.py validate-modules:parameter-type-not-in-doc -plugins/modules/cloud/digital_ocean/digital_ocean_sshkey.py validate-modules:doc-default-does-not-match-spec -plugins/modules/cloud/digital_ocean/digital_ocean_sshkey.py validate-modules:doc-missing-type -plugins/modules/cloud/digital_ocean/digital_ocean_sshkey.py validate-modules:parameter-type-not-in-doc -plugins/modules/cloud/digital_ocean/digital_ocean_sshkey.py validate-modules:undocumented-parameter -plugins/modules/cloud/digital_ocean/digital_ocean_tag.py validate-modules:doc-missing-type -plugins/modules/cloud/digital_ocean/digital_ocean_tag.py validate-modules:parameter-type-not-in-doc -plugins/modules/cloud/digital_ocean/digital_ocean_tag_info.py validate-modules:parameter-type-not-in-doc -plugins/modules/cloud/digital_ocean/digital_ocean_volume_info.py validate-modules:parameter-type-not-in-doc plugins/modules/cloud/dimensiondata/dimensiondata_network.py validate-modules:doc-choices-do-not-match-spec plugins/modules/cloud/dimensiondata/dimensiondata_network.py validate-modules:doc-missing-type plugins/modules/cloud/dimensiondata/dimensiondata_network.py validate-modules:parameter-type-not-in-doc diff --git a/tests/sanity/ignore-2.9.txt b/tests/sanity/ignore-2.9.txt index 289e1e27cf..28603a0d31 100644 --- a/tests/sanity/ignore-2.9.txt +++ b/tests/sanity/ignore-2.9.txt @@ -32,37 +32,6 @@ plugins/modules/cloud/centurylink/clc_server.py validate-modules:parameter-type- plugins/modules/cloud/centurylink/clc_server_snapshot.py validate-modules:doc-missing-type plugins/modules/cloud/centurylink/clc_server_snapshot.py validate-modules:implied-parameter-type-mismatch plugins/modules/cloud/centurylink/clc_server_snapshot.py validate-modules:parameter-type-not-in-doc -plugins/modules/cloud/digital_ocean/digital_ocean.py validate-modules:deprecation-mismatch -plugins/modules/cloud/digital_ocean/digital_ocean.py validate-modules:invalid-documentation -plugins/modules/cloud/digital_ocean/digital_ocean.py validate-modules:missing-main-call -plugins/modules/cloud/digital_ocean/digital_ocean_block_storage.py validate-modules:doc-missing-type -plugins/modules/cloud/digital_ocean/digital_ocean_block_storage.py validate-modules:parameter-type-not-in-doc -plugins/modules/cloud/digital_ocean/digital_ocean_certificate.py validate-modules:doc-missing-type -plugins/modules/cloud/digital_ocean/digital_ocean_certificate.py validate-modules:parameter-type-not-in-doc -plugins/modules/cloud/digital_ocean/digital_ocean_certificate_info.py validate-modules:parameter-type-not-in-doc -plugins/modules/cloud/digital_ocean/digital_ocean_domain.py validate-modules:doc-missing-type -plugins/modules/cloud/digital_ocean/digital_ocean_domain.py validate-modules:parameter-type-not-in-doc -plugins/modules/cloud/digital_ocean/digital_ocean_domain_info.py validate-modules:parameter-type-not-in-doc -plugins/modules/cloud/digital_ocean/digital_ocean_droplet.py validate-modules:doc-missing-type -plugins/modules/cloud/digital_ocean/digital_ocean_droplet.py validate-modules:parameter-type-not-in-doc -plugins/modules/cloud/digital_ocean/digital_ocean_firewall_info.py validate-modules:parameter-type-not-in-doc -plugins/modules/cloud/digital_ocean/digital_ocean_floating_ip.py validate-modules:doc-default-does-not-match-spec -plugins/modules/cloud/digital_ocean/digital_ocean_floating_ip.py validate-modules:doc-missing-type -plugins/modules/cloud/digital_ocean/digital_ocean_floating_ip.py validate-modules:parameter-type-not-in-doc -plugins/modules/cloud/digital_ocean/digital_ocean_floating_ip.py validate-modules:undocumented-parameter -plugins/modules/cloud/digital_ocean/digital_ocean_image_info.py validate-modules:parameter-type-not-in-doc -plugins/modules/cloud/digital_ocean/digital_ocean_load_balancer_info.py validate-modules:parameter-type-not-in-doc -plugins/modules/cloud/digital_ocean/digital_ocean_snapshot_info.py validate-modules:parameter-type-not-in-doc -plugins/modules/cloud/digital_ocean/digital_ocean_sshkey.py validate-modules:doc-default-does-not-match-spec -plugins/modules/cloud/digital_ocean/digital_ocean_sshkey.py validate-modules:doc-missing-type -plugins/modules/cloud/digital_ocean/digital_ocean_sshkey.py validate-modules:parameter-type-not-in-doc -plugins/modules/cloud/digital_ocean/digital_ocean_sshkey.py validate-modules:undocumented-parameter -plugins/modules/cloud/digital_ocean/digital_ocean_sshkey_facts.py validate-modules:deprecation-mismatch -plugins/modules/cloud/digital_ocean/digital_ocean_sshkey_facts.py validate-modules:invalid-documentation -plugins/modules/cloud/digital_ocean/digital_ocean_tag.py validate-modules:doc-missing-type -plugins/modules/cloud/digital_ocean/digital_ocean_tag.py validate-modules:parameter-type-not-in-doc -plugins/modules/cloud/digital_ocean/digital_ocean_tag_info.py validate-modules:parameter-type-not-in-doc -plugins/modules/cloud/digital_ocean/digital_ocean_volume_info.py validate-modules:parameter-type-not-in-doc plugins/modules/cloud/dimensiondata/dimensiondata_network.py validate-modules:doc-choices-do-not-match-spec plugins/modules/cloud/dimensiondata/dimensiondata_network.py validate-modules:doc-missing-type plugins/modules/cloud/dimensiondata/dimensiondata_network.py validate-modules:parameter-type-not-in-doc