mirror of
https://github.com/ansible-collections/hetzner.hcloud
synced 2024-11-10 06:34:13 +00:00
feat(inventory): improve api options (#397)
##### SUMMARY - Rename the inventory `token` option to `api_token`, use aliases for backward compatibility. - Rename the inventory `token_env` option to `api_token_env`, use aliases for backward compatibility. - Deprecate the inventory `api_token_env` option, suggest using a lookup plugin (`{{ lookup('ansible.builtin.env', 'YOUR_ENV_VAR') }}`) or use the well-known `HCLOUD_TOKEN` environment variable name. - Let ansible parse the options, remove homemade options parsing. - Improve and document the existing `api_endpoint` option. ##### ISSUE TYPE - Feature Pull Request ##### COMPONENT NAME hcloud inventory
This commit is contained in:
parent
6581ed50db
commit
9905bd0e01
2 changed files with 146 additions and 96 deletions
7
changelogs/fragments/improve-inventory-api-options.yml
Normal file
7
changelogs/fragments/improve-inventory-api-options.yml
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
minor_changes:
|
||||||
|
- hcloud inventory - Rename the `token` option to `api_token`, use aliases for backward compatibility.
|
||||||
|
- hcloud inventory - Rename the `token_env` option to `api_token_env`, use aliases for backward compatibility.
|
||||||
|
- hcloud inventory - Add the `api_endpoint` option.
|
||||||
|
- hcloud inventory - Deprecate the `api_token_env` option, suggest using a lookup
|
||||||
|
plugin (`{{ lookup('ansible.builtin.env', 'YOUR_ENV_VAR') }}`) or use the
|
||||||
|
well-known `HCLOUD_TOKEN` environment variable name.
|
|
@ -2,85 +2,113 @@
|
||||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
DOCUMENTATION = r"""
|
DOCUMENTATION = r"""
|
||||||
name: hcloud
|
name: hcloud
|
||||||
author:
|
short_description: Ansible dynamic inventory plugin for the Hetzner Cloud.
|
||||||
- Lukas Kaemmerling (@lkaemmerling)
|
|
||||||
short_description: Ansible dynamic inventory plugin for the Hetzner Cloud.
|
description:
|
||||||
requirements:
|
- Reads inventories from the Hetzner Cloud API.
|
||||||
- python-dateutil >= 2.7.5
|
- Uses a YAML configuration file that ends with C(hcloud.yml) or C(hcloud.yaml).
|
||||||
- requests >=2.20
|
|
||||||
|
author:
|
||||||
|
- Lukas Kaemmerling (@lkaemmerling)
|
||||||
|
|
||||||
|
requirements:
|
||||||
|
- python-dateutil >= 2.7.5
|
||||||
|
- requests >=2.20
|
||||||
|
|
||||||
|
extends_documentation_fragment:
|
||||||
|
- constructed
|
||||||
|
- inventory_cache
|
||||||
|
|
||||||
|
options:
|
||||||
|
plugin:
|
||||||
|
description: Mark this as an C(hetzner.hcloud.hcloud) inventory instance.
|
||||||
|
required: true
|
||||||
|
choices: [hcloud, hetzner.hcloud.hcloud]
|
||||||
|
|
||||||
|
api_token:
|
||||||
description:
|
description:
|
||||||
- Reads inventories from the Hetzner Cloud API.
|
- The API Token for the Hetzner Cloud.
|
||||||
- Uses a YAML configuration file that ends with hcloud.(yml|yaml).
|
- You can also set this option by using the C(HCLOUD_TOKEN) environment variable.
|
||||||
extends_documentation_fragment:
|
type: str
|
||||||
- constructed
|
required: false # TODO: Mark as required once I(api_token_env) is removed.
|
||||||
- inventory_cache
|
aliases: [token]
|
||||||
options:
|
env:
|
||||||
plugin:
|
- name: HCLOUD_TOKEN
|
||||||
description: marks this as an instance of the "hcloud" plugin
|
api_token_env:
|
||||||
required: true
|
description:
|
||||||
choices: ["hcloud", "hetzner.hcloud.hcloud"]
|
- Environment variable name to load the Hetzner Cloud API Token from.
|
||||||
token:
|
type: str
|
||||||
description: The Hetzner Cloud API Token.
|
default: HCLOUD_TOKEN
|
||||||
required: false
|
aliases: [token_env]
|
||||||
group:
|
deprecated:
|
||||||
description: The group all servers are automatically added to.
|
why: The option is adding too much complexity, while the alternatives are preferred.
|
||||||
default: hcloud
|
collection_name: hetzner.hcloud
|
||||||
type: str
|
version: 3.0.0
|
||||||
required: false
|
alternatives: Use the ``{{ lookup('ansible.builtin.env', 'YOUR_ENV_VAR') }}`` lookup instead.
|
||||||
token_env:
|
api_endpoint:
|
||||||
description: Environment variable to load the Hetzner Cloud API Token from.
|
description:
|
||||||
default: HCLOUD_TOKEN
|
- The API Endpoint for the Hetzner Cloud.
|
||||||
type: str
|
- You can also set this option by using the C(HCLOUD_ENDPOINT) environment variable.
|
||||||
required: false
|
type: str
|
||||||
connect_with:
|
default: https://api.hetzner.cloud/v1
|
||||||
description: |
|
env:
|
||||||
Connect to the server using the value from this field. This sets the `ansible_host`
|
- name: HCLOUD_ENDPOINT
|
||||||
variable to the value indicated, if that value is available. If you need further
|
|
||||||
customization, like falling back to private ipv4 if the server has no public ipv4,
|
group:
|
||||||
you can use `compose` top-level key.
|
description: The group all servers are automatically added to.
|
||||||
default: public_ipv4
|
default: hcloud
|
||||||
type: str
|
type: str
|
||||||
choices:
|
required: false
|
||||||
- public_ipv4
|
connect_with:
|
||||||
- public_ipv6
|
description: |
|
||||||
- hostname
|
Connect to the server using the value from this field. This sets the `ansible_host`
|
||||||
- ipv4_dns_ptr
|
variable to the value indicated, if that value is available. If you need further
|
||||||
- private_ipv4
|
customization, like falling back to private ipv4 if the server has no public ipv4,
|
||||||
locations:
|
you can use `compose` top-level key.
|
||||||
description: Populate inventory with instances in this location.
|
default: public_ipv4
|
||||||
default: []
|
type: str
|
||||||
type: list
|
choices:
|
||||||
elements: str
|
- public_ipv4
|
||||||
required: false
|
- public_ipv6
|
||||||
types:
|
- hostname
|
||||||
description: Populate inventory with instances with this type.
|
- ipv4_dns_ptr
|
||||||
default: []
|
- private_ipv4
|
||||||
type: list
|
|
||||||
elements: str
|
locations:
|
||||||
required: false
|
description: Populate inventory with instances in this location.
|
||||||
images:
|
default: []
|
||||||
description: Populate inventory with instances with this image name, only available for system images.
|
type: list
|
||||||
default: []
|
elements: str
|
||||||
type: list
|
required: false
|
||||||
elements: str
|
types:
|
||||||
required: false
|
description: Populate inventory with instances with this type.
|
||||||
label_selector:
|
default: []
|
||||||
description: Populate inventory with instances with this label.
|
type: list
|
||||||
default: ""
|
elements: str
|
||||||
type: str
|
required: false
|
||||||
required: false
|
images:
|
||||||
network:
|
description: Populate inventory with instances with this image name, only available for system images.
|
||||||
description: Populate inventory with instances which are attached to this network name or ID.
|
default: []
|
||||||
default: ""
|
type: list
|
||||||
type: str
|
elements: str
|
||||||
required: false
|
required: false
|
||||||
status:
|
label_selector:
|
||||||
description: Populate inventory with instances with this status.
|
description: Populate inventory with instances with this label.
|
||||||
default: []
|
default: ""
|
||||||
type: list
|
type: str
|
||||||
elements: str
|
required: false
|
||||||
required: false
|
network:
|
||||||
|
description: Populate inventory with instances which are attached to this network name or ID.
|
||||||
|
default: ""
|
||||||
|
type: str
|
||||||
|
required: false
|
||||||
|
status:
|
||||||
|
description: Populate inventory with instances with this status.
|
||||||
|
default: []
|
||||||
|
type: list
|
||||||
|
elements: str
|
||||||
|
required: false
|
||||||
"""
|
"""
|
||||||
|
|
||||||
EXAMPLES = r"""
|
EXAMPLES = r"""
|
||||||
|
@ -113,6 +141,7 @@ from ansible.errors import AnsibleError
|
||||||
from ansible.inventory.manager import InventoryData
|
from ansible.inventory.manager import InventoryData
|
||||||
from ansible.module_utils.common.text.converters import to_native
|
from ansible.module_utils.common.text.converters import to_native
|
||||||
from ansible.plugins.inventory import BaseInventoryPlugin, Cacheable, Constructable
|
from ansible.plugins.inventory import BaseInventoryPlugin, Cacheable, Constructable
|
||||||
|
from ansible.utils.display import Display
|
||||||
|
|
||||||
from ..module_utils.hcloud import HAS_DATEUTIL, HAS_REQUESTS
|
from ..module_utils.hcloud import HAS_DATEUTIL, HAS_REQUESTS
|
||||||
from ..module_utils.vendor import hcloud
|
from ..module_utils.vendor import hcloud
|
||||||
|
@ -170,35 +199,50 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
|
||||||
NAME = "hetzner.hcloud.hcloud"
|
NAME = "hetzner.hcloud.hcloud"
|
||||||
|
|
||||||
inventory: InventoryData
|
inventory: InventoryData
|
||||||
|
display: Display
|
||||||
|
|
||||||
|
client: hcloud.Client
|
||||||
|
|
||||||
def _configure_hcloud_client(self):
|
def _configure_hcloud_client(self):
|
||||||
self.token_env = self.get_option("token_env")
|
# If api_token_env is not the default, print a deprecation warning and load the
|
||||||
self.templar.available_variables = self._vars
|
# environment variable.
|
||||||
self.api_token = self.templar.template(self.get_option("token"), fail_on_undefined=False) or os.getenv(
|
api_token_env = self.get_option("api_token_env")
|
||||||
self.token_env
|
if api_token_env != "HCLOUD_TOKEN":
|
||||||
)
|
self.display.deprecated(
|
||||||
if self.api_token is None:
|
"The 'api_token_env' option is deprecated, please use the `HCLOUD_TOKEN` "
|
||||||
|
"environment variable or use the 'ansible.builtin.env' lookup instead.",
|
||||||
|
version="3.0.0",
|
||||||
|
collection_name="hetzner.hcloud",
|
||||||
|
)
|
||||||
|
if api_token_env in os.environ:
|
||||||
|
self.set_option("api_token", os.environ.get(api_token_env))
|
||||||
|
|
||||||
|
api_token = self.get_option("api_token")
|
||||||
|
api_endpoint = self.get_option("api_endpoint")
|
||||||
|
|
||||||
|
if api_token is None: # TODO: Remove once I(api_token_env) is removed.
|
||||||
raise AnsibleError(
|
raise AnsibleError(
|
||||||
"Please specify a token, via the option token, via environment variable HCLOUD_TOKEN "
|
"No setting was provided for required configuration setting: "
|
||||||
"or via custom environment variable set by token_env option."
|
"plugin_type: inventory "
|
||||||
|
"plugin: hetzner.hcloud.hcloud "
|
||||||
|
"setting: api_token"
|
||||||
)
|
)
|
||||||
|
|
||||||
self.endpoint = os.getenv("HCLOUD_ENDPOINT") or "https://api.hetzner.cloud/v1"
|
# Resolve template string
|
||||||
|
api_token = self.templar.template(api_token)
|
||||||
|
|
||||||
self.client = hcloud.Client(
|
self.client = hcloud.Client(
|
||||||
token=self.api_token,
|
token=api_token,
|
||||||
api_endpoint=self.endpoint,
|
api_endpoint=api_endpoint,
|
||||||
application_name="ansible-inventory",
|
application_name="ansible-inventory",
|
||||||
application_version=version,
|
application_version=version,
|
||||||
)
|
)
|
||||||
|
|
||||||
def _test_hcloud_token(self):
|
|
||||||
try:
|
try:
|
||||||
# We test the API Token against the location API, because this is the API with the smallest result
|
# Ensure the api token is valid
|
||||||
# and not controllable from the customer.
|
self.client.locations.get_list()
|
||||||
self.client.locations.get_all()
|
except hcloud.APIException as exception:
|
||||||
except hcloud.APIException:
|
raise AnsibleError("Invalid Hetzner Cloud API Token.") from exception
|
||||||
raise AnsibleError("Invalid Hetzner Cloud API Token.")
|
|
||||||
|
|
||||||
def _get_servers(self):
|
def _get_servers(self):
|
||||||
if len(self.get_option("label_selector")) > 0:
|
if len(self.get_option("label_selector")) > 0:
|
||||||
|
@ -388,7 +432,6 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
|
||||||
|
|
||||||
self._read_config_data(path)
|
self._read_config_data(path)
|
||||||
self._configure_hcloud_client()
|
self._configure_hcloud_client()
|
||||||
self._test_hcloud_token()
|
|
||||||
|
|
||||||
self.servers, cached = self._get_cached_result(path, cache)
|
self.servers, cached = self._get_cached_result(path, cache)
|
||||||
if not cached:
|
if not cached:
|
||||||
|
|
Loading…
Reference in a new issue