mirror of
https://github.com/ansible-collections/kubernetes.core.git
synced 2026-05-12 04:22:02 +00:00
Compare commits
45 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c47343d7b6 | ||
|
|
c213b51741 | ||
|
|
60b53b9dc9 | ||
|
|
d531368d64 | ||
|
|
c3bf5cc47f | ||
|
|
349534b85b | ||
|
|
92e3f98a20 | ||
|
|
d2dcb9e55f | ||
|
|
0eff03dd19 | ||
|
|
81fb8662da | ||
|
|
f74ee14d71 | ||
|
|
6f75d86954 | ||
|
|
c93a7e2459 | ||
|
|
2d68a37a52 | ||
|
|
c5f5398e9e | ||
|
|
05aea7727d | ||
|
|
d3f6dd186c | ||
|
|
8cee9fddbe | ||
|
|
05a942e41e | ||
|
|
fcd47ca995 | ||
|
|
f1729ce186 | ||
|
|
c37dc5b566 | ||
|
|
410855cd36 | ||
|
|
e1f52ddbee | ||
|
|
5d038db848 | ||
|
|
9d3195641e | ||
|
|
dac1448b9c | ||
|
|
4bdff5d672 | ||
|
|
19a71c82ba | ||
|
|
c73f3e3f75 | ||
|
|
2cdcc195e6 | ||
|
|
e98605eb16 | ||
|
|
e13a7fd0c6 | ||
|
|
2098dfea5e | ||
|
|
10a9b9e811 | ||
|
|
67868442f3 | ||
|
|
5eefa9c308 | ||
|
|
4ed9105797 | ||
|
|
46f8e4adfb | ||
|
|
5761205513 | ||
|
|
7b0190f8d5 | ||
|
|
c47e691101 | ||
|
|
8ae6469696 | ||
|
|
1174fee5c9 | ||
|
|
f22ffcab18 |
@@ -4,20 +4,6 @@ Kubernetes Collection Release Notes
|
|||||||
|
|
||||||
.. contents:: Topics
|
.. contents:: Topics
|
||||||
|
|
||||||
v6.0.0
|
|
||||||
======
|
|
||||||
|
|
||||||
Release Summary
|
|
||||||
---------------
|
|
||||||
|
|
||||||
This major release removes the deprecated ``k8s`` inventory plugin and also removes ``ansible-core<2.16`` support.
|
|
||||||
|
|
||||||
Breaking Changes / Porting Guide
|
|
||||||
--------------------------------
|
|
||||||
|
|
||||||
- Remove deprecated ``k8s`` invetory plugin (https://github.com/ansible-collections/kubernetes.core/pull/867).
|
|
||||||
- Remove support for ``ansible-core<2.16`` (https://github.com/ansible-collections/kubernetes.core/pull/867).
|
|
||||||
|
|
||||||
v5.3.0
|
v5.3.0
|
||||||
======
|
======
|
||||||
|
|
||||||
@@ -137,14 +123,6 @@ Bugfixes
|
|||||||
- helm - use ``reuse-values`` when running ``helm diff`` command (https://github.com/ansible-collections/kubernetes.core/issues/680).
|
- helm - use ``reuse-values`` when running ``helm diff`` command (https://github.com/ansible-collections/kubernetes.core/issues/680).
|
||||||
- integrations test helm_kubeconfig - set helm version to v3.10.3 to avoid incompatability with new bitnami charts (https://github.com/ansible-collections/kubernetes.core/pull/670).
|
- integrations test helm_kubeconfig - set helm version to v3.10.3 to avoid incompatability with new bitnami charts (https://github.com/ansible-collections/kubernetes.core/pull/670).
|
||||||
|
|
||||||
v3.3.1
|
|
||||||
======
|
|
||||||
|
|
||||||
Release Summary
|
|
||||||
---------------
|
|
||||||
|
|
||||||
This release fixes the CI issues with the ``linters`` workflow.
|
|
||||||
|
|
||||||
v3.3.0
|
v3.3.0
|
||||||
======
|
======
|
||||||
|
|
||||||
|
|||||||
2
Makefile
2
Makefile
@@ -1,5 +1,5 @@
|
|||||||
# Also needs to be updated in galaxy.yml
|
# Also needs to be updated in galaxy.yml
|
||||||
VERSION = 6.0.0
|
VERSION = 5.2.0
|
||||||
|
|
||||||
TEST_ARGS ?= ""
|
TEST_ARGS ?= ""
|
||||||
PYTHON_VERSION ?= `python -c 'import platform; print(".".join(platform.python_version_tuple()[0:2]))'`
|
PYTHON_VERSION ?= `python -c 'import platform; print(".".join(platform.python_version_tuple()[0:2]))'`
|
||||||
|
|||||||
13
README.md
13
README.md
@@ -21,9 +21,9 @@ For more information about communication, see the [Ansible communication guide](
|
|||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
<!--start requires_ansible-->
|
<!--start requires_ansible-->
|
||||||
### Ansible Version Compatibility
|
## Ansible Version Compatibility
|
||||||
|
|
||||||
This collection has been tested against following Ansible versions: **>=2.16.0**.
|
This collection has been tested against following Ansible versions: **>=2.15.0**.
|
||||||
|
|
||||||
For collections that support Ansible 2.9, please ensure you update your `network_os` to use the
|
For collections that support Ansible 2.9, please ensure you update your `network_os` to use the
|
||||||
fully qualified collection name (for example, `cisco.ios.ios`).
|
fully qualified collection name (for example, `cisco.ios.ios`).
|
||||||
@@ -52,11 +52,16 @@ Name | Description
|
|||||||
--- | ---
|
--- | ---
|
||||||
[kubernetes.core.kubectl](https://github.com/ansible-collections/kubernetes.core/blob/main/docs/kubernetes.core.kubectl_connection.rst)|Execute tasks in pods running on Kubernetes.
|
[kubernetes.core.kubectl](https://github.com/ansible-collections/kubernetes.core/blob/main/docs/kubernetes.core.kubectl_connection.rst)|Execute tasks in pods running on Kubernetes.
|
||||||
|
|
||||||
### K8s Filter Plugins
|
### K8s filter Plugins
|
||||||
Name | Description
|
Name | Description
|
||||||
--- | ---
|
--- | ---
|
||||||
kubernetes.core.k8s_config_resource_name|Generate resource name for the given resource of type ConfigMap, Secret
|
kubernetes.core.k8s_config_resource_name|Generate resource name for the given resource of type ConfigMap, Secret
|
||||||
|
|
||||||
|
### Inventory Plugins
|
||||||
|
Name | Description
|
||||||
|
--- | ---
|
||||||
|
[kubernetes.core.k8s](https://github.com/ansible-collections/kubernetes.core/blob/main/docs/kubernetes.core.k8s_inventory.rst)|Kubernetes (K8s) inventory source
|
||||||
|
|
||||||
### Lookup Plugins
|
### Lookup Plugins
|
||||||
Name | Description
|
Name | Description
|
||||||
--- | ---
|
--- | ---
|
||||||
@@ -101,7 +106,7 @@ You can also include it in a `requirements.yml` file and install it via `ansible
|
|||||||
---
|
---
|
||||||
collections:
|
collections:
|
||||||
- name: kubernetes.core
|
- name: kubernetes.core
|
||||||
version: 6.0.0
|
version: 5.3.0
|
||||||
```
|
```
|
||||||
|
|
||||||
### Installing the Kubernetes Python Library
|
### Installing the Kubernetes Python Library
|
||||||
|
|||||||
@@ -900,12 +900,6 @@ releases:
|
|||||||
- 798-drain-pdb-error-message.yaml
|
- 798-drain-pdb-error-message.yaml
|
||||||
- readme_template_update.yml
|
- readme_template_update.yml
|
||||||
release_date: '2025-01-20'
|
release_date: '2025-01-20'
|
||||||
3.3.1:
|
|
||||||
changes:
|
|
||||||
release_summary: This release fixes the CI issues with the ``linters`` workflow.
|
|
||||||
fragments:
|
|
||||||
- release_summary.yml
|
|
||||||
release_date: '2025-03-26'
|
|
||||||
4.0.0:
|
4.0.0:
|
||||||
changes:
|
changes:
|
||||||
bugfixes:
|
bugfixes:
|
||||||
@@ -1044,11 +1038,3 @@ releases:
|
|||||||
- 898-k8s-dont-delete-in-check-mode.yaml
|
- 898-k8s-dont-delete-in-check-mode.yaml
|
||||||
- 919-update-ansible-lint-version.yaml
|
- 919-update-ansible-lint-version.yaml
|
||||||
release_date: '2025-05-16'
|
release_date: '2025-05-16'
|
||||||
6.0.0:
|
|
||||||
changes:
|
|
||||||
breaking_changes:
|
|
||||||
- Remove deprecated ``k8s`` invetory plugin (https://github.com/ansible-collections/kubernetes.core/pull/867).
|
|
||||||
- Remove support for ``ansible-core<2.16`` (https://github.com/ansible-collections/kubernetes.core/pull/867).
|
|
||||||
fragments:
|
|
||||||
- 20250121-breaking-changes-6.0.0.yml
|
|
||||||
release_date: '2025-05-19'
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ Requirements
|
|||||||
|
|
||||||
To use the modules, you'll need the following:
|
To use the modules, you'll need the following:
|
||||||
|
|
||||||
- Ansible 2.16.0 or latest installed
|
- Ansible 2.9.17 or latest installed
|
||||||
- `Kubernetes Python client <https://pypi.org/project/kubernetes/>`_ installed on the host that will execute the modules.
|
- `Kubernetes Python client <https://pypi.org/project/kubernetes/>`_ installed on the host that will execute the modules.
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
88
docs/docsite/rst/kubernetes_scenarios/k8s_inventory.rst
Normal file
88
docs/docsite/rst/kubernetes_scenarios/k8s_inventory.rst
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
.. _ansible_collections.kubernetes.core.docsite.k8s_ansible_inventory:
|
||||||
|
|
||||||
|
*****************************************
|
||||||
|
Using Kubernetes dynamic inventory plugin
|
||||||
|
*****************************************
|
||||||
|
|
||||||
|
.. contents::
|
||||||
|
:local:
|
||||||
|
|
||||||
|
Kubernetes dynamic inventory plugin
|
||||||
|
===================================
|
||||||
|
|
||||||
|
|
||||||
|
The best way to interact with your Pods is to use the Kubernetes dynamic inventory plugin, which queries Kubernetes APIs using ``kubectl`` command line available on controller node and tells Ansible what Pods can be managed.
|
||||||
|
|
||||||
|
Requirements
|
||||||
|
------------
|
||||||
|
|
||||||
|
To use the Kubernetes dynamic inventory plugins, you must install `Kubernetes Python client <https://github.com/kubernetes-client/python>`_, `kubectl <https://github.com/kubernetes/kubectl>`_ on your control node (the host running Ansible).
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
$ pip install kubernetes
|
||||||
|
|
||||||
|
Please refer to Kubernetes official documentation for `installing kubectl <https://kubernetes.io/docs/tasks/tools/install-kubectl/>`_ on the given operating systems.
|
||||||
|
|
||||||
|
To use this Kubernetes dynamic inventory plugin, you need to enable it first by specifying the following in the ``ansible.cfg`` file:
|
||||||
|
|
||||||
|
.. code-block:: ini
|
||||||
|
|
||||||
|
[inventory]
|
||||||
|
enable_plugins = kubernetes.core.k8s
|
||||||
|
|
||||||
|
Then, create a file that ends in ``.k8s.yml`` or ``.k8s.yaml`` in your working directory.
|
||||||
|
|
||||||
|
The ``kubernetes.core.k8s`` inventory plugin takes in the same authentication information as any other Kubernetes modules.
|
||||||
|
|
||||||
|
Here's an example of a valid inventory file:
|
||||||
|
|
||||||
|
.. code-block:: yaml
|
||||||
|
|
||||||
|
plugin: kubernetes.core.k8s
|
||||||
|
|
||||||
|
Executing ``ansible-inventory --list -i <filename>.k8s.yml`` will create a list of Pods that are ready to be configured using Ansible.
|
||||||
|
|
||||||
|
You can also provide the namespace to gather information about specific pods from the given namespace. For example, to gather information about Pods under the ``test`` namespace you will specify the ``namespaces`` parameter:
|
||||||
|
|
||||||
|
.. code-block:: yaml
|
||||||
|
|
||||||
|
plugin: kubernetes.core.k8s
|
||||||
|
connections:
|
||||||
|
- namespaces:
|
||||||
|
- test
|
||||||
|
|
||||||
|
Using vaulted configuration files
|
||||||
|
=================================
|
||||||
|
|
||||||
|
Since the inventory configuration file contains Kubernetes related sensitive information in plain text, a security risk, you may want to
|
||||||
|
encrypt your entire inventory configuration file.
|
||||||
|
|
||||||
|
You can encrypt a valid inventory configuration file as follows:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
$ ansible-vault encrypt <filename>.k8s.yml
|
||||||
|
New Vault password:
|
||||||
|
Confirm New Vault password:
|
||||||
|
Encryption successful
|
||||||
|
|
||||||
|
$ echo "MySuperSecretPassw0rd!" > /path/to/vault_password_file
|
||||||
|
|
||||||
|
And you can use this vaulted inventory configuration file using:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
$ ansible-inventory -i <filename>.k8s.yml --list --vault-password-file=/path/to/vault_password_file
|
||||||
|
|
||||||
|
|
||||||
|
.. seealso::
|
||||||
|
|
||||||
|
`Kubernetes Python client - Issue Tracker <https://github.com/kubernetes-client/python/issues>`_
|
||||||
|
The issue tracker for Kubernetes Python client
|
||||||
|
`Kubectl installation <https://kubernetes.io/docs/tasks/tools/install-kubectl/>`_
|
||||||
|
Installation guide for installing Kubectl
|
||||||
|
:ref:`working_with_playbooks`
|
||||||
|
An introduction to playbooks
|
||||||
|
:ref:`playbooks_vault`
|
||||||
|
Using Vault in playbooks
|
||||||
@@ -13,5 +13,6 @@ To get started, please select one of the following topics.
|
|||||||
:maxdepth: 1
|
:maxdepth: 1
|
||||||
|
|
||||||
kubernetes_scenarios/k8s_intro
|
kubernetes_scenarios/k8s_intro
|
||||||
|
kubernetes_scenarios/k8s_inventory
|
||||||
kubernetes_scenarios/k8s_scenarios
|
kubernetes_scenarios/k8s_scenarios
|
||||||
|
|
||||||
|
|||||||
372
docs/kubernetes.core.k8s_inventory.rst
Normal file
372
docs/kubernetes.core.k8s_inventory.rst
Normal file
@@ -0,0 +1,372 @@
|
|||||||
|
.. _kubernetes.core.k8s_inventory:
|
||||||
|
|
||||||
|
|
||||||
|
*******************
|
||||||
|
kubernetes.core.k8s
|
||||||
|
*******************
|
||||||
|
|
||||||
|
**Kubernetes (K8s) inventory source**
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.. contents::
|
||||||
|
:local:
|
||||||
|
:depth: 1
|
||||||
|
|
||||||
|
DEPRECATED
|
||||||
|
----------
|
||||||
|
:Removed in collection release after
|
||||||
|
:Why: As discussed in https://github.com/ansible-collections/kubernetes.core/issues/31, we decided to
|
||||||
|
remove the k8s inventory plugin in release 6.0.0.
|
||||||
|
|
||||||
|
:Alternative: Use :ref:`kubernetes.core.k8s_info <kubernetes.core.k8s_info_module>` and :ref:`ansible.builtin.add_host <ansible.builtin.add_host_module>` instead.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Synopsis
|
||||||
|
--------
|
||||||
|
- Fetch containers and services for one or more clusters.
|
||||||
|
- Groups by cluster name, namespace, namespace_services, namespace_pods, and labels.
|
||||||
|
- Uses the kubectl connection plugin to access the Kubernetes cluster.
|
||||||
|
- Uses k8s.(yml|yaml) YAML configuration file to set parameter values.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Requirements
|
||||||
|
------------
|
||||||
|
The below requirements are needed on the local Ansible controller node that executes this inventory.
|
||||||
|
|
||||||
|
- python >= 3.9
|
||||||
|
- kubernetes >= 24.2.0
|
||||||
|
- PyYAML >= 3.11
|
||||||
|
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
|
||||||
|
.. raw:: html
|
||||||
|
|
||||||
|
<table border=0 cellpadding=0 class="documentation-table">
|
||||||
|
<tr>
|
||||||
|
<th colspan="2">Parameter</th>
|
||||||
|
<th>Choices/<font color="blue">Defaults</font></th>
|
||||||
|
<th>Configuration</th>
|
||||||
|
<th width="100%">Comments</th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td colspan="2">
|
||||||
|
<div class="ansibleOptionAnchor" id="parameter-"></div>
|
||||||
|
<b>connections</b>
|
||||||
|
<a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
|
||||||
|
<div style="font-size: small">
|
||||||
|
<span style="color: purple">-</span>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<div>Optional list of cluster connection settings. If no connections are provided, the default <em>~/.kube/config</em> and active context will be used, and objects will be returned for all namespaces the active user is authorized to access.</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="elbow-placeholder"></td>
|
||||||
|
<td colspan="1">
|
||||||
|
<div class="ansibleOptionAnchor" id="parameter-"></div>
|
||||||
|
<b>api_key</b>
|
||||||
|
<a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
|
||||||
|
<div style="font-size: small">
|
||||||
|
<span style="color: purple">-</span>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<div>Token used to authenticate with the API. Can also be specified via K8S_AUTH_API_KEY environment variable.</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="elbow-placeholder"></td>
|
||||||
|
<td colspan="1">
|
||||||
|
<div class="ansibleOptionAnchor" id="parameter-"></div>
|
||||||
|
<b>ca_cert</b>
|
||||||
|
<a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
|
||||||
|
<div style="font-size: small">
|
||||||
|
<span style="color: purple">-</span>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<div>Path to a CA certificate used to authenticate with the API. Can also be specified via K8S_AUTH_SSL_CA_CERT environment variable.</div>
|
||||||
|
<div style="font-size: small; color: darkgreen"><br/>aliases: ssl_ca_cert</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="elbow-placeholder"></td>
|
||||||
|
<td colspan="1">
|
||||||
|
<div class="ansibleOptionAnchor" id="parameter-"></div>
|
||||||
|
<b>client_cert</b>
|
||||||
|
<a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
|
||||||
|
<div style="font-size: small">
|
||||||
|
<span style="color: purple">-</span>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<div>Path to a certificate used to authenticate with the API. Can also be specified via K8S_AUTH_CERT_FILE environment variable.</div>
|
||||||
|
<div style="font-size: small; color: darkgreen"><br/>aliases: cert_file</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="elbow-placeholder"></td>
|
||||||
|
<td colspan="1">
|
||||||
|
<div class="ansibleOptionAnchor" id="parameter-"></div>
|
||||||
|
<b>client_key</b>
|
||||||
|
<a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
|
||||||
|
<div style="font-size: small">
|
||||||
|
<span style="color: purple">-</span>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<div>Path to a key file used to authenticate with the API. Can also be specified via K8S_AUTH_KEY_FILE environment variable.</div>
|
||||||
|
<div style="font-size: small; color: darkgreen"><br/>aliases: key_file</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="elbow-placeholder"></td>
|
||||||
|
<td colspan="1">
|
||||||
|
<div class="ansibleOptionAnchor" id="parameter-"></div>
|
||||||
|
<b>context</b>
|
||||||
|
<a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
|
||||||
|
<div style="font-size: small">
|
||||||
|
<span style="color: purple">-</span>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<div>The name of a context found in the config file. Can also be specified via K8S_AUTH_CONTEXT environment variable.</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="elbow-placeholder"></td>
|
||||||
|
<td colspan="1">
|
||||||
|
<div class="ansibleOptionAnchor" id="parameter-"></div>
|
||||||
|
<b>host</b>
|
||||||
|
<a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
|
||||||
|
<div style="font-size: small">
|
||||||
|
<span style="color: purple">-</span>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<div>Provide a URL for accessing the API. Can also be specified via K8S_AUTH_HOST environment variable.</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="elbow-placeholder"></td>
|
||||||
|
<td colspan="1">
|
||||||
|
<div class="ansibleOptionAnchor" id="parameter-"></div>
|
||||||
|
<b>kubeconfig</b>
|
||||||
|
<a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
|
||||||
|
<div style="font-size: small">
|
||||||
|
<span style="color: purple">-</span>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<div>Path to an existing Kubernetes config file. If not provided, and no other connection options are provided, the Kubernetes client will attempt to load the default configuration file from <em>~/.kube/config</em>. Can also be specified via K8S_AUTH_KUBECONFIG environment variable.</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="elbow-placeholder"></td>
|
||||||
|
<td colspan="1">
|
||||||
|
<div class="ansibleOptionAnchor" id="parameter-"></div>
|
||||||
|
<b>name</b>
|
||||||
|
<a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
|
||||||
|
<div style="font-size: small">
|
||||||
|
<span style="color: purple">-</span>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<div>Optional name to assign to the cluster. If not provided, a name is constructed from the server and port.</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="elbow-placeholder"></td>
|
||||||
|
<td colspan="1">
|
||||||
|
<div class="ansibleOptionAnchor" id="parameter-"></div>
|
||||||
|
<b>namespaces</b>
|
||||||
|
<a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
|
||||||
|
<div style="font-size: small">
|
||||||
|
<span style="color: purple">-</span>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<div>List of namespaces. If not specified, will fetch all containers for all namespaces user is authorized to access.</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="elbow-placeholder"></td>
|
||||||
|
<td colspan="1">
|
||||||
|
<div class="ansibleOptionAnchor" id="parameter-"></div>
|
||||||
|
<b>password</b>
|
||||||
|
<a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
|
||||||
|
<div style="font-size: small">
|
||||||
|
<span style="color: purple">-</span>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<div>Provide a password for authenticating with the API. Can also be specified via K8S_AUTH_PASSWORD environment variable.</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="elbow-placeholder"></td>
|
||||||
|
<td colspan="1">
|
||||||
|
<div class="ansibleOptionAnchor" id="parameter-"></div>
|
||||||
|
<b>username</b>
|
||||||
|
<a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
|
||||||
|
<div style="font-size: small">
|
||||||
|
<span style="color: purple">-</span>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<div>Provide a username for authenticating with the API. Can also be specified via K8S_AUTH_USERNAME environment variable.</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="elbow-placeholder"></td>
|
||||||
|
<td colspan="1">
|
||||||
|
<div class="ansibleOptionAnchor" id="parameter-"></div>
|
||||||
|
<b>validate_certs</b>
|
||||||
|
<a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
|
||||||
|
<div style="font-size: small">
|
||||||
|
<span style="color: purple">boolean</span>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<ul style="margin: 0; padding: 0"><b>Choices:</b>
|
||||||
|
<li>no</li>
|
||||||
|
<li>yes</li>
|
||||||
|
</ul>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<div>Whether or not to verify the API server's SSL certificates. Can also be specified via K8S_AUTH_VERIFY_SSL environment variable.</div>
|
||||||
|
<div style="font-size: small; color: darkgreen"><br/>aliases: verify_ssl</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td colspan="2">
|
||||||
|
<div class="ansibleOptionAnchor" id="parameter-"></div>
|
||||||
|
<b>plugin</b>
|
||||||
|
<a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
|
||||||
|
<div style="font-size: small">
|
||||||
|
<span style="color: purple">-</span>
|
||||||
|
/ <span style="color: red">required</span>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<ul style="margin: 0; padding: 0"><b>Choices:</b>
|
||||||
|
<li>kubernetes.core.k8s</li>
|
||||||
|
<li>k8s</li>
|
||||||
|
<li>community.kubernetes.k8s</li>
|
||||||
|
</ul>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<div>token that ensures this is a source file for the 'k8s' plugin.</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Examples
|
||||||
|
--------
|
||||||
|
|
||||||
|
.. code-block:: yaml
|
||||||
|
|
||||||
|
# File must be named k8s.yaml or k8s.yml
|
||||||
|
|
||||||
|
- name: Authenticate with token, and return all pods and services for all namespaces
|
||||||
|
plugin: kubernetes.core.k8s
|
||||||
|
connections:
|
||||||
|
- host: https://192.168.64.4:8443
|
||||||
|
api_key: xxxxxxxxxxxxxxxx
|
||||||
|
validate_certs: false
|
||||||
|
|
||||||
|
- name: Use default config (~/.kube/config) file and active context, and return objects for a specific namespace
|
||||||
|
plugin: kubernetes.core.k8s
|
||||||
|
connections:
|
||||||
|
- namespaces:
|
||||||
|
- testing
|
||||||
|
|
||||||
|
- name: Use a custom config file, and a specific context.
|
||||||
|
plugin: kubernetes.core.k8s
|
||||||
|
connections:
|
||||||
|
- kubeconfig: /path/to/config
|
||||||
|
context: 'awx/192-168-64-4:8443/developer'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Status
|
||||||
|
------
|
||||||
|
|
||||||
|
|
||||||
|
- This inventory will be removed in version 6.0.0. *[deprecated]*
|
||||||
|
- For more information see `DEPRECATED`_.
|
||||||
|
|
||||||
|
|
||||||
|
Authors
|
||||||
|
~~~~~~~
|
||||||
|
|
||||||
|
- Chris Houseknecht (@chouseknecht)
|
||||||
|
- Fabian von Feilitzsch (@fabianvf)
|
||||||
|
|
||||||
|
|
||||||
|
.. hint::
|
||||||
|
Configuration entries for each entry type have a low to high priority order. For example, a variable that is lower in the list will override a variable that is higher up.
|
||||||
@@ -25,7 +25,7 @@ tags:
|
|||||||
- openshift
|
- openshift
|
||||||
- okd
|
- okd
|
||||||
- cluster
|
- cluster
|
||||||
version: 6.0.0
|
version: 5.3.0
|
||||||
build_ignore:
|
build_ignore:
|
||||||
- .DS_Store
|
- .DS_Store
|
||||||
- "*.tar.gz"
|
- "*.tar.gz"
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
requires_ansible: '>=2.16.0'
|
requires_ansible: '>=2.15.0'
|
||||||
|
|
||||||
action_groups:
|
action_groups:
|
||||||
helm:
|
helm:
|
||||||
@@ -21,10 +21,11 @@ plugin_routing:
|
|||||||
openshift:
|
openshift:
|
||||||
redirect: community.okd.openshift
|
redirect: community.okd.openshift
|
||||||
k8s:
|
k8s:
|
||||||
tombstone:
|
deprecation:
|
||||||
removal_version: 6.0.0
|
removal_version: 6.0.0
|
||||||
warning_text: >-
|
warning_text: >-
|
||||||
The k8s inventory plugin was slated for deprecation in 3.3.0 and has been removed in release 6.0.0. Use kubernetes.core.k8s_info and ansible.builtin.add_host instead.
|
The k8s inventory plugin has been deprecated and
|
||||||
|
will be removed in release 6.0.0.
|
||||||
modules:
|
modules:
|
||||||
k8s_auth:
|
k8s_auth:
|
||||||
redirect: community.okd.k8s_auth
|
redirect: community.okd.k8s_auth
|
||||||
|
|||||||
476
plugins/inventory/k8s.py
Normal file
476
plugins/inventory/k8s.py
Normal file
@@ -0,0 +1,476 @@
|
|||||||
|
# Copyright (c) 2018 Ansible Project
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
|
from __future__ import absolute_import, division, print_function
|
||||||
|
|
||||||
|
__metaclass__ = type
|
||||||
|
|
||||||
|
DOCUMENTATION = """
|
||||||
|
name: k8s
|
||||||
|
author:
|
||||||
|
- Chris Houseknecht (@chouseknecht)
|
||||||
|
- Fabian von Feilitzsch (@fabianvf)
|
||||||
|
|
||||||
|
short_description: Kubernetes (K8s) inventory source
|
||||||
|
|
||||||
|
description:
|
||||||
|
- Fetch containers and services for one or more clusters.
|
||||||
|
- Groups by cluster name, namespace, namespace_services, namespace_pods, and labels.
|
||||||
|
- Uses the kubectl connection plugin to access the Kubernetes cluster.
|
||||||
|
- Uses k8s.(yml|yaml) YAML configuration file to set parameter values.
|
||||||
|
|
||||||
|
deprecated:
|
||||||
|
removed_in: 6.0.0
|
||||||
|
why: |
|
||||||
|
As discussed in U(https://github.com/ansible-collections/kubernetes.core/issues/31), we decided to
|
||||||
|
remove the k8s inventory plugin in release 6.0.0.
|
||||||
|
alternative: "Use M(kubernetes.core.k8s_info) and M(ansible.builtin.add_host) instead."
|
||||||
|
|
||||||
|
options:
|
||||||
|
plugin:
|
||||||
|
description: token that ensures this is a source file for the 'k8s' plugin.
|
||||||
|
required: True
|
||||||
|
choices: ['kubernetes.core.k8s', 'k8s', 'community.kubernetes.k8s']
|
||||||
|
connections:
|
||||||
|
description:
|
||||||
|
- Optional list of cluster connection settings. If no connections are provided, the default
|
||||||
|
I(~/.kube/config) and active context will be used, and objects will be returned for all namespaces
|
||||||
|
the active user is authorized to access.
|
||||||
|
suboptions:
|
||||||
|
name:
|
||||||
|
description:
|
||||||
|
- Optional name to assign to the cluster. If not provided, a name is constructed from the server
|
||||||
|
and port.
|
||||||
|
kubeconfig:
|
||||||
|
description:
|
||||||
|
- Path to an existing Kubernetes config file. If not provided, and no other connection
|
||||||
|
options are provided, the Kubernetes client will attempt to load the default
|
||||||
|
configuration file from I(~/.kube/config). Can also be specified via K8S_AUTH_KUBECONFIG
|
||||||
|
environment variable.
|
||||||
|
context:
|
||||||
|
description:
|
||||||
|
- The name of a context found in the config file. Can also be specified via K8S_AUTH_CONTEXT environment
|
||||||
|
variable.
|
||||||
|
host:
|
||||||
|
description:
|
||||||
|
- Provide a URL for accessing the API. Can also be specified via K8S_AUTH_HOST environment variable.
|
||||||
|
api_key:
|
||||||
|
description:
|
||||||
|
- Token used to authenticate with the API. Can also be specified via K8S_AUTH_API_KEY environment
|
||||||
|
variable.
|
||||||
|
username:
|
||||||
|
description:
|
||||||
|
- Provide a username for authenticating with the API. Can also be specified via K8S_AUTH_USERNAME
|
||||||
|
environment variable.
|
||||||
|
password:
|
||||||
|
description:
|
||||||
|
- Provide a password for authenticating with the API. Can also be specified via K8S_AUTH_PASSWORD
|
||||||
|
environment variable.
|
||||||
|
client_cert:
|
||||||
|
description:
|
||||||
|
- Path to a certificate used to authenticate with the API. Can also be specified via K8S_AUTH_CERT_FILE
|
||||||
|
environment variable.
|
||||||
|
aliases: [ cert_file ]
|
||||||
|
client_key:
|
||||||
|
description:
|
||||||
|
- Path to a key file used to authenticate with the API. Can also be specified via K8S_AUTH_KEY_FILE
|
||||||
|
environment variable.
|
||||||
|
aliases: [ key_file ]
|
||||||
|
ca_cert:
|
||||||
|
description:
|
||||||
|
- Path to a CA certificate used to authenticate with the API. Can also be specified via
|
||||||
|
K8S_AUTH_SSL_CA_CERT environment variable.
|
||||||
|
aliases: [ ssl_ca_cert ]
|
||||||
|
validate_certs:
|
||||||
|
description:
|
||||||
|
- "Whether or not to verify the API server's SSL certificates. Can also be specified via
|
||||||
|
K8S_AUTH_VERIFY_SSL environment variable."
|
||||||
|
type: bool
|
||||||
|
aliases: [ verify_ssl ]
|
||||||
|
namespaces:
|
||||||
|
description:
|
||||||
|
- List of namespaces. If not specified, will fetch all containers for all namespaces user is authorized
|
||||||
|
to access.
|
||||||
|
|
||||||
|
requirements:
|
||||||
|
- "python >= 3.9"
|
||||||
|
- "kubernetes >= 24.2.0"
|
||||||
|
- "PyYAML >= 3.11"
|
||||||
|
"""
|
||||||
|
|
||||||
|
EXAMPLES = r"""
|
||||||
|
# File must be named k8s.yaml or k8s.yml
|
||||||
|
|
||||||
|
- name: Authenticate with token, and return all pods and services for all namespaces
|
||||||
|
plugin: kubernetes.core.k8s
|
||||||
|
connections:
|
||||||
|
- host: https://192.168.64.4:8443
|
||||||
|
api_key: xxxxxxxxxxxxxxxx
|
||||||
|
validate_certs: false
|
||||||
|
|
||||||
|
- name: Use default config (~/.kube/config) file and active context, and return objects for a specific namespace
|
||||||
|
plugin: kubernetes.core.k8s
|
||||||
|
connections:
|
||||||
|
- namespaces:
|
||||||
|
- testing
|
||||||
|
|
||||||
|
- name: Use a custom config file, and a specific context.
|
||||||
|
plugin: kubernetes.core.k8s
|
||||||
|
connections:
|
||||||
|
- kubeconfig: /path/to/config
|
||||||
|
context: 'awx/192-168-64-4:8443/developer'
|
||||||
|
"""
|
||||||
|
|
||||||
|
import json
|
||||||
|
|
||||||
|
from ansible.errors import AnsibleError
|
||||||
|
from ansible.plugins.inventory import BaseInventoryPlugin, Cacheable, Constructable
|
||||||
|
|
||||||
|
try:
|
||||||
|
from kubernetes.dynamic.exceptions import DynamicApiError
|
||||||
|
|
||||||
|
HAS_K8S_MODULE_HELPER = True
|
||||||
|
k8s_import_exception = None
|
||||||
|
except ImportError as e:
|
||||||
|
HAS_K8S_MODULE_HELPER = False
|
||||||
|
k8s_import_exception = e
|
||||||
|
from ansible_collections.kubernetes.core.plugins.module_utils.k8s.client import (
|
||||||
|
get_api_client,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def format_dynamic_api_exc(exc):
|
||||||
|
if exc.body:
|
||||||
|
if exc.headers and exc.headers.get("Content-Type") == "application/json":
|
||||||
|
message = json.loads(exc.body).get("message")
|
||||||
|
if message:
|
||||||
|
return message
|
||||||
|
return exc.body
|
||||||
|
else:
|
||||||
|
return "%s Reason: %s" % (exc.status, exc.reason)
|
||||||
|
|
||||||
|
|
||||||
|
class K8sInventoryException(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
|
||||||
|
NAME = "kubernetes.core.k8s"
|
||||||
|
|
||||||
|
connection_plugin = "kubernetes.core.kubectl"
|
||||||
|
transport = "kubectl"
|
||||||
|
|
||||||
|
def parse(self, inventory, loader, path, cache=True):
|
||||||
|
super(InventoryModule, self).parse(inventory, loader, path)
|
||||||
|
|
||||||
|
self.display.deprecated(
|
||||||
|
"The 'k8s' inventory plugin has been deprecated and will be removed in release 6.0.0",
|
||||||
|
version="6.0.0",
|
||||||
|
collection_name="kubernetes.core",
|
||||||
|
)
|
||||||
|
cache_key = self._get_cache_prefix(path)
|
||||||
|
config_data = self._read_config_data(path)
|
||||||
|
self.setup(config_data, cache, cache_key)
|
||||||
|
|
||||||
|
def setup(self, config_data, cache, cache_key):
|
||||||
|
connections = config_data.get("connections")
|
||||||
|
|
||||||
|
if not HAS_K8S_MODULE_HELPER:
|
||||||
|
raise K8sInventoryException(
|
||||||
|
"This module requires the Kubernetes Python client. Try `pip install kubernetes`. Detail: {0}".format(
|
||||||
|
k8s_import_exception
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
source_data = None
|
||||||
|
if cache and cache_key in self._cache:
|
||||||
|
try:
|
||||||
|
source_data = self._cache[cache_key]
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
if not source_data:
|
||||||
|
self.fetch_objects(connections)
|
||||||
|
|
||||||
|
def fetch_objects(self, connections):
|
||||||
|
if connections:
|
||||||
|
if not isinstance(connections, list):
|
||||||
|
raise K8sInventoryException("Expecting connections to be a list.")
|
||||||
|
|
||||||
|
for connection in connections:
|
||||||
|
if not isinstance(connection, dict):
|
||||||
|
raise K8sInventoryException(
|
||||||
|
"Expecting connection to be a dictionary."
|
||||||
|
)
|
||||||
|
client = get_api_client(**connection)
|
||||||
|
name = connection.get(
|
||||||
|
"name", self.get_default_host_name(client.configuration.host)
|
||||||
|
)
|
||||||
|
if connection.get("namespaces"):
|
||||||
|
namespaces = connection["namespaces"]
|
||||||
|
else:
|
||||||
|
namespaces = self.get_available_namespaces(client)
|
||||||
|
for namespace in namespaces:
|
||||||
|
self.get_pods_for_namespace(client, name, namespace)
|
||||||
|
self.get_services_for_namespace(client, name, namespace)
|
||||||
|
else:
|
||||||
|
client = get_api_client()
|
||||||
|
name = self.get_default_host_name(client.configuration.host)
|
||||||
|
namespaces = self.get_available_namespaces(client)
|
||||||
|
for namespace in namespaces:
|
||||||
|
self.get_pods_for_namespace(client, name, namespace)
|
||||||
|
self.get_services_for_namespace(client, name, namespace)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_default_host_name(host):
|
||||||
|
return (
|
||||||
|
host.replace("https://", "")
|
||||||
|
.replace("http://", "")
|
||||||
|
.replace(".", "-")
|
||||||
|
.replace(":", "_")
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_available_namespaces(self, client):
|
||||||
|
v1_namespace = client.resources.get(api_version="v1", kind="Namespace")
|
||||||
|
try:
|
||||||
|
obj = v1_namespace.get()
|
||||||
|
except DynamicApiError as exc:
|
||||||
|
self.display.debug(exc)
|
||||||
|
raise K8sInventoryException(
|
||||||
|
"Error fetching Namespace list: %s" % format_dynamic_api_exc(exc)
|
||||||
|
)
|
||||||
|
return [namespace.metadata.name for namespace in obj.items]
|
||||||
|
|
||||||
|
def get_pods_for_namespace(self, client, name, namespace):
|
||||||
|
v1_pod = client.resources.get(api_version="v1", kind="Pod")
|
||||||
|
try:
|
||||||
|
obj = v1_pod.get(namespace=namespace)
|
||||||
|
except DynamicApiError as exc:
|
||||||
|
self.display.debug(exc)
|
||||||
|
raise K8sInventoryException(
|
||||||
|
"Error fetching Pod list: %s" % format_dynamic_api_exc(exc)
|
||||||
|
)
|
||||||
|
|
||||||
|
namespace_group = "namespace_{0}".format(namespace)
|
||||||
|
namespace_pods_group = "{0}_pods".format(namespace_group)
|
||||||
|
|
||||||
|
self.inventory.add_group(name)
|
||||||
|
self.inventory.add_group(namespace_group)
|
||||||
|
self.inventory.add_child(name, namespace_group)
|
||||||
|
self.inventory.add_group(namespace_pods_group)
|
||||||
|
self.inventory.add_child(namespace_group, namespace_pods_group)
|
||||||
|
|
||||||
|
for pod in obj.items:
|
||||||
|
pod_name = pod.metadata.name
|
||||||
|
pod_groups = []
|
||||||
|
pod_annotations = (
|
||||||
|
{} if not pod.metadata.annotations else dict(pod.metadata.annotations)
|
||||||
|
)
|
||||||
|
|
||||||
|
if pod.metadata.labels:
|
||||||
|
# create a group for each label_value
|
||||||
|
for key, value in pod.metadata.labels:
|
||||||
|
group_name = "label_{0}_{1}".format(key, value)
|
||||||
|
if group_name not in pod_groups:
|
||||||
|
pod_groups.append(group_name)
|
||||||
|
self.inventory.add_group(group_name)
|
||||||
|
pod_labels = dict(pod.metadata.labels)
|
||||||
|
else:
|
||||||
|
pod_labels = {}
|
||||||
|
|
||||||
|
if not pod.status.containerStatuses:
|
||||||
|
continue
|
||||||
|
|
||||||
|
for container in pod.status.containerStatuses:
|
||||||
|
# add each pod_container to the namespace group, and to each label_value group
|
||||||
|
container_name = "{0}_{1}".format(pod.metadata.name, container.name)
|
||||||
|
self.inventory.add_host(container_name)
|
||||||
|
self.inventory.add_child(namespace_pods_group, container_name)
|
||||||
|
if pod_groups:
|
||||||
|
for group in pod_groups:
|
||||||
|
self.inventory.add_child(group, container_name)
|
||||||
|
|
||||||
|
# Add hostvars
|
||||||
|
self.inventory.set_variable(container_name, "object_type", "pod")
|
||||||
|
self.inventory.set_variable(container_name, "labels", pod_labels)
|
||||||
|
self.inventory.set_variable(
|
||||||
|
container_name, "annotations", pod_annotations
|
||||||
|
)
|
||||||
|
self.inventory.set_variable(
|
||||||
|
container_name, "cluster_name", pod.metadata.clusterName
|
||||||
|
)
|
||||||
|
self.inventory.set_variable(
|
||||||
|
container_name, "pod_node_name", pod.spec.nodeName
|
||||||
|
)
|
||||||
|
self.inventory.set_variable(container_name, "pod_name", pod.spec.name)
|
||||||
|
self.inventory.set_variable(
|
||||||
|
container_name, "pod_host_ip", pod.status.hostIP
|
||||||
|
)
|
||||||
|
self.inventory.set_variable(
|
||||||
|
container_name, "pod_phase", pod.status.phase
|
||||||
|
)
|
||||||
|
self.inventory.set_variable(container_name, "pod_ip", pod.status.podIP)
|
||||||
|
self.inventory.set_variable(
|
||||||
|
container_name, "pod_self_link", pod.metadata.selfLink
|
||||||
|
)
|
||||||
|
self.inventory.set_variable(
|
||||||
|
container_name, "pod_resource_version", pod.metadata.resourceVersion
|
||||||
|
)
|
||||||
|
self.inventory.set_variable(container_name, "pod_uid", pod.metadata.uid)
|
||||||
|
self.inventory.set_variable(
|
||||||
|
container_name, "container_name", container.image
|
||||||
|
)
|
||||||
|
self.inventory.set_variable(
|
||||||
|
container_name, "container_image", container.image
|
||||||
|
)
|
||||||
|
if container.state.running:
|
||||||
|
self.inventory.set_variable(
|
||||||
|
container_name, "container_state", "Running"
|
||||||
|
)
|
||||||
|
if container.state.terminated:
|
||||||
|
self.inventory.set_variable(
|
||||||
|
container_name, "container_state", "Terminated"
|
||||||
|
)
|
||||||
|
if container.state.waiting:
|
||||||
|
self.inventory.set_variable(
|
||||||
|
container_name, "container_state", "Waiting"
|
||||||
|
)
|
||||||
|
self.inventory.set_variable(
|
||||||
|
container_name, "container_ready", container.ready
|
||||||
|
)
|
||||||
|
self.inventory.set_variable(
|
||||||
|
container_name, "ansible_remote_tmp", "/tmp/"
|
||||||
|
)
|
||||||
|
self.inventory.set_variable(
|
||||||
|
container_name, "ansible_connection", self.connection_plugin
|
||||||
|
)
|
||||||
|
self.inventory.set_variable(
|
||||||
|
container_name, "ansible_{0}_pod".format(self.transport), pod_name
|
||||||
|
)
|
||||||
|
self.inventory.set_variable(
|
||||||
|
container_name,
|
||||||
|
"ansible_{0}_container".format(self.transport),
|
||||||
|
container.name,
|
||||||
|
)
|
||||||
|
self.inventory.set_variable(
|
||||||
|
container_name,
|
||||||
|
"ansible_{0}_namespace".format(self.transport),
|
||||||
|
namespace,
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_services_for_namespace(self, client, name, namespace):
|
||||||
|
v1_service = client.resources.get(api_version="v1", kind="Service")
|
||||||
|
try:
|
||||||
|
obj = v1_service.get(namespace=namespace)
|
||||||
|
except DynamicApiError as exc:
|
||||||
|
self.display.debug(exc)
|
||||||
|
raise K8sInventoryException(
|
||||||
|
"Error fetching Service list: %s" % format_dynamic_api_exc(exc)
|
||||||
|
)
|
||||||
|
|
||||||
|
namespace_group = "namespace_{0}".format(namespace)
|
||||||
|
namespace_services_group = "{0}_services".format(namespace_group)
|
||||||
|
|
||||||
|
self.inventory.add_group(name)
|
||||||
|
self.inventory.add_group(namespace_group)
|
||||||
|
self.inventory.add_child(name, namespace_group)
|
||||||
|
self.inventory.add_group(namespace_services_group)
|
||||||
|
self.inventory.add_child(namespace_group, namespace_services_group)
|
||||||
|
|
||||||
|
for service in obj.items:
|
||||||
|
service_name = service.metadata.name
|
||||||
|
service_labels = (
|
||||||
|
{} if not service.metadata.labels else dict(service.metadata.labels)
|
||||||
|
)
|
||||||
|
service_annotations = (
|
||||||
|
{}
|
||||||
|
if not service.metadata.annotations
|
||||||
|
else dict(service.metadata.annotations)
|
||||||
|
)
|
||||||
|
|
||||||
|
self.inventory.add_host(service_name)
|
||||||
|
|
||||||
|
if service.metadata.labels:
|
||||||
|
# create a group for each label_value
|
||||||
|
for key, value in service.metadata.labels:
|
||||||
|
group_name = "label_{0}_{1}".format(key, value)
|
||||||
|
self.inventory.add_group(group_name)
|
||||||
|
self.inventory.add_child(group_name, service_name)
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.inventory.add_child(namespace_services_group, service_name)
|
||||||
|
except AnsibleError:
|
||||||
|
raise
|
||||||
|
|
||||||
|
ports = [
|
||||||
|
{
|
||||||
|
"name": port.name,
|
||||||
|
"port": port.port,
|
||||||
|
"protocol": port.protocol,
|
||||||
|
"targetPort": port.targetPort,
|
||||||
|
"nodePort": port.nodePort,
|
||||||
|
}
|
||||||
|
for port in service.spec.ports or []
|
||||||
|
]
|
||||||
|
|
||||||
|
# add hostvars
|
||||||
|
self.inventory.set_variable(service_name, "object_type", "service")
|
||||||
|
self.inventory.set_variable(service_name, "labels", service_labels)
|
||||||
|
self.inventory.set_variable(
|
||||||
|
service_name, "annotations", service_annotations
|
||||||
|
)
|
||||||
|
self.inventory.set_variable(
|
||||||
|
service_name, "cluster_name", service.metadata.clusterName
|
||||||
|
)
|
||||||
|
self.inventory.set_variable(service_name, "ports", ports)
|
||||||
|
self.inventory.set_variable(service_name, "type", service.spec.type)
|
||||||
|
self.inventory.set_variable(
|
||||||
|
service_name, "self_link", service.metadata.selfLink
|
||||||
|
)
|
||||||
|
self.inventory.set_variable(
|
||||||
|
service_name, "resource_version", service.metadata.resourceVersion
|
||||||
|
)
|
||||||
|
self.inventory.set_variable(service_name, "uid", service.metadata.uid)
|
||||||
|
|
||||||
|
if service.spec.externalTrafficPolicy:
|
||||||
|
self.inventory.set_variable(
|
||||||
|
service_name,
|
||||||
|
"external_traffic_policy",
|
||||||
|
service.spec.externalTrafficPolicy,
|
||||||
|
)
|
||||||
|
if service.spec.externalIPs:
|
||||||
|
self.inventory.set_variable(
|
||||||
|
service_name, "external_ips", service.spec.externalIPs
|
||||||
|
)
|
||||||
|
|
||||||
|
if service.spec.externalName:
|
||||||
|
self.inventory.set_variable(
|
||||||
|
service_name, "external_name", service.spec.externalName
|
||||||
|
)
|
||||||
|
|
||||||
|
if service.spec.healthCheckNodePort:
|
||||||
|
self.inventory.set_variable(
|
||||||
|
service_name,
|
||||||
|
"health_check_node_port",
|
||||||
|
service.spec.healthCheckNodePort,
|
||||||
|
)
|
||||||
|
if service.spec.loadBalancerIP:
|
||||||
|
self.inventory.set_variable(
|
||||||
|
service_name, "load_balancer_ip", service.spec.loadBalancerIP
|
||||||
|
)
|
||||||
|
if service.spec.selector:
|
||||||
|
self.inventory.set_variable(
|
||||||
|
service_name, "selector", dict(service.spec.selector)
|
||||||
|
)
|
||||||
|
|
||||||
|
if (
|
||||||
|
hasattr(service.status.loadBalancer, "ingress")
|
||||||
|
and service.status.loadBalancer.ingress
|
||||||
|
):
|
||||||
|
load_balancer = [
|
||||||
|
{"hostname": ingress.hostname, "ip": ingress.ip}
|
||||||
|
for ingress in service.status.loadBalancer.ingress
|
||||||
|
]
|
||||||
|
self.inventory.set_variable(
|
||||||
|
service_name, "load_balancer", load_balancer
|
||||||
|
)
|
||||||
3
tests/integration/targets/inventory_k8s/aliases
Normal file
3
tests/integration/targets/inventory_k8s/aliases
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
context/target
|
||||||
|
time=42
|
||||||
|
k8s
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
---
|
||||||
|
- name: Create inventory files
|
||||||
|
hosts: localhost
|
||||||
|
gather_facts: false
|
||||||
|
|
||||||
|
collections:
|
||||||
|
- kubernetes.core
|
||||||
|
|
||||||
|
roles:
|
||||||
|
- role: setup_kubeconfig
|
||||||
|
kubeconfig_operation: 'save'
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
- name: Create inventory files
|
||||||
|
copy:
|
||||||
|
content: "{{ item.content }}"
|
||||||
|
dest: "{{ item.path }}"
|
||||||
|
vars:
|
||||||
|
hostname: "{{ lookup('file', user_credentials_dir + '/host_data.txt') }}"
|
||||||
|
test_cert_file: "{{ user_credentials_dir | realpath + '/cert_file_data.txt' }}"
|
||||||
|
test_key_file: "{{ user_credentials_dir | realpath + '/key_file_data.txt' }}"
|
||||||
|
test_ca_cert: "{{ user_credentials_dir | realpath + '/ssl_ca_cert_data.txt' }}"
|
||||||
|
with_items:
|
||||||
|
- path: "test_inventory_aliases_with_ssl_k8s.yml"
|
||||||
|
content: |
|
||||||
|
---
|
||||||
|
plugin: kubernetes.core.k8s
|
||||||
|
connections:
|
||||||
|
- namespaces:
|
||||||
|
- inventory
|
||||||
|
host: "{{ hostname }}"
|
||||||
|
cert_file: "{{ test_cert_file }}"
|
||||||
|
key_file: "{{ test_key_file }}"
|
||||||
|
verify_ssl: true
|
||||||
|
ssl_ca_cert: "{{ test_ca_cert }}"
|
||||||
|
- path: "test_inventory_aliases_no_ssl_k8s.yml"
|
||||||
|
content: |
|
||||||
|
---
|
||||||
|
plugin: kubernetes.core.k8s
|
||||||
|
connections:
|
||||||
|
- namespaces:
|
||||||
|
- inventory
|
||||||
|
host: "{{ hostname }}"
|
||||||
|
cert_file: "{{ test_cert_file }}"
|
||||||
|
key_file: "{{ test_key_file }}"
|
||||||
|
verify_ssl: false
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
---
|
||||||
|
- name: Delete inventory namespace
|
||||||
|
hosts: localhost
|
||||||
|
connection: local
|
||||||
|
gather_facts: true
|
||||||
|
|
||||||
|
roles:
|
||||||
|
- role: setup_kubeconfig
|
||||||
|
kubeconfig_operation: 'revert'
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
- name: Delete temporary files
|
||||||
|
file:
|
||||||
|
state: absent
|
||||||
|
path: "{{ user_credentials_dir ~ '/' ~ item }}"
|
||||||
|
ignore_errors: true
|
||||||
|
with_items:
|
||||||
|
- test_inventory_aliases_with_ssl_k8s.yml
|
||||||
|
- test_inventory_aliases_no_ssl_k8s.yml
|
||||||
|
- ssl_ca_cert_data.txt
|
||||||
|
- key_file_data.txt
|
||||||
|
- cert_file_data.txt
|
||||||
|
- host_data.txt
|
||||||
|
|
||||||
|
- name: Remove inventory namespace
|
||||||
|
k8s:
|
||||||
|
api_version: v1
|
||||||
|
kind: Namespace
|
||||||
|
name: inventory
|
||||||
|
state: absent
|
||||||
90
tests/integration/targets/inventory_k8s/playbooks/play.yml
Normal file
90
tests/integration/targets/inventory_k8s/playbooks/play.yml
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
---
|
||||||
|
- name: Converge
|
||||||
|
hosts: localhost
|
||||||
|
connection: local
|
||||||
|
|
||||||
|
collections:
|
||||||
|
- kubernetes.core
|
||||||
|
|
||||||
|
vars_files:
|
||||||
|
- vars/main.yml
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
- name: Delete existing namespace
|
||||||
|
k8s:
|
||||||
|
api_version: v1
|
||||||
|
kind: Namespace
|
||||||
|
name: inventory
|
||||||
|
wait: yes
|
||||||
|
state: absent
|
||||||
|
|
||||||
|
- name: Ensure namespace exists
|
||||||
|
k8s:
|
||||||
|
api_version: v1
|
||||||
|
kind: Namespace
|
||||||
|
name: inventory
|
||||||
|
|
||||||
|
- name: Add a deployment
|
||||||
|
k8s:
|
||||||
|
definition:
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: inventory
|
||||||
|
namespace: inventory
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: "{{ k8s_pod_name }}"
|
||||||
|
template: "{{ k8s_pod_template }}"
|
||||||
|
wait: yes
|
||||||
|
wait_timeout: 400
|
||||||
|
vars:
|
||||||
|
k8s_pod_name: inventory
|
||||||
|
k8s_pod_image: python
|
||||||
|
k8s_pod_command:
|
||||||
|
- python
|
||||||
|
- '-m'
|
||||||
|
- http.server
|
||||||
|
k8s_pod_env:
|
||||||
|
- name: TEST
|
||||||
|
value: test
|
||||||
|
|
||||||
|
- meta: refresh_inventory
|
||||||
|
|
||||||
|
- name: Verify inventory and connection plugins
|
||||||
|
hosts: namespace_inventory_pods
|
||||||
|
gather_facts: no
|
||||||
|
|
||||||
|
vars:
|
||||||
|
file_content: |
|
||||||
|
Hello world
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
- name: End play if host not running (TODO should we not add these to the inventory?)
|
||||||
|
meta: end_host
|
||||||
|
when: pod_phase != "Running"
|
||||||
|
|
||||||
|
- debug: var=hostvars
|
||||||
|
- setup:
|
||||||
|
|
||||||
|
- debug: var=ansible_facts
|
||||||
|
|
||||||
|
- name: Assert the TEST environment variable was retrieved
|
||||||
|
assert:
|
||||||
|
that: ansible_facts.env.TEST == 'test'
|
||||||
|
|
||||||
|
- name: Copy a file into the host
|
||||||
|
copy:
|
||||||
|
content: '{{ file_content }}'
|
||||||
|
dest: /tmp/test_file
|
||||||
|
|
||||||
|
- name: Retrieve the file from the host
|
||||||
|
slurp:
|
||||||
|
src: /tmp/test_file
|
||||||
|
register: slurped_file
|
||||||
|
|
||||||
|
- name: Assert the file content matches expectations
|
||||||
|
assert:
|
||||||
|
that: (slurped_file.content|b64decode) == file_content
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
---
|
||||||
|
plugin: kubernetes.core.k8s
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
---
|
||||||
|
k8s_pod_metadata:
|
||||||
|
labels:
|
||||||
|
app: "{{ k8s_pod_name }}"
|
||||||
|
|
||||||
|
k8s_pod_spec:
|
||||||
|
serviceAccount: "{{ k8s_pod_service_account }}"
|
||||||
|
containers:
|
||||||
|
- image: "{{ k8s_pod_image }}"
|
||||||
|
imagePullPolicy: Always
|
||||||
|
name: "{{ k8s_pod_name }}"
|
||||||
|
command: "{{ k8s_pod_command }}"
|
||||||
|
readinessProbe:
|
||||||
|
initialDelaySeconds: 15
|
||||||
|
exec:
|
||||||
|
command:
|
||||||
|
- /bin/true
|
||||||
|
resources: "{{ k8s_pod_resources }}"
|
||||||
|
ports: "{{ k8s_pod_ports }}"
|
||||||
|
env: "{{ k8s_pod_env }}"
|
||||||
|
|
||||||
|
|
||||||
|
k8s_pod_service_account: default
|
||||||
|
|
||||||
|
k8s_pod_resources:
|
||||||
|
limits:
|
||||||
|
cpu: "100m"
|
||||||
|
memory: "100Mi"
|
||||||
|
|
||||||
|
k8s_pod_command: []
|
||||||
|
|
||||||
|
k8s_pod_ports: []
|
||||||
|
|
||||||
|
k8s_pod_env: []
|
||||||
|
|
||||||
|
k8s_pod_template:
|
||||||
|
metadata: "{{ k8s_pod_metadata }}"
|
||||||
|
spec: "{{ k8s_pod_spec }}"
|
||||||
30
tests/integration/targets/inventory_k8s/runme.sh
Executable file
30
tests/integration/targets/inventory_k8s/runme.sh
Executable file
@@ -0,0 +1,30 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -eux
|
||||||
|
|
||||||
|
export ANSIBLE_ROLES_PATH="../"
|
||||||
|
USER_CREDENTIALS_DIR=$(pwd)
|
||||||
|
|
||||||
|
ansible-playbook playbooks/delete_resources.yml -e "user_credentials_dir=${USER_CREDENTIALS_DIR}" "$@"
|
||||||
|
|
||||||
|
{
|
||||||
|
export ANSIBLE_CALLBACKS_ENABLED=profile_tasks
|
||||||
|
export ANSIBLE_INVENTORY_ENABLED=kubernetes.core.k8s,yaml
|
||||||
|
export ANSIBLE_PYTHON_INTERPRETER=auto_silent
|
||||||
|
|
||||||
|
ansible-playbook playbooks/play.yml -i playbooks/test.inventory_k8s.yml "$@" &&
|
||||||
|
|
||||||
|
ansible-playbook playbooks/create_resources.yml -e "user_credentials_dir=${USER_CREDENTIALS_DIR}" "$@" &&
|
||||||
|
|
||||||
|
ansible-inventory -i playbooks/test_inventory_aliases_with_ssl_k8s.yml --list "$@" &&
|
||||||
|
|
||||||
|
ansible-inventory -i playbooks/test_inventory_aliases_no_ssl_k8s.yml --list "$@" &&
|
||||||
|
|
||||||
|
unset ANSIBLE_INVENTORY_ENABLED &&
|
||||||
|
|
||||||
|
ansible-playbook playbooks/delete_resources.yml -e "user_credentials_dir=${USER_CREDENTIALS_DIR}" "$@"
|
||||||
|
|
||||||
|
} || {
|
||||||
|
ansible-playbook playbooks/delete_resources.yml -e "user_credentials_dir=${USER_CREDENTIALS_DIR}" "$@"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
31
tests/sanity/ignore-2.14.txt
Normal file
31
tests/sanity/ignore-2.14.txt
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
plugins/module_utils/client/discovery.py import-3.9!skip
|
||||||
|
plugins/module_utils/client/discovery.py import-3.10!skip
|
||||||
|
plugins/module_utils/client/discovery.py import-3.11!skip
|
||||||
|
plugins/module_utils/client/resource.py import-3.9!skip
|
||||||
|
plugins/module_utils/client/resource.py import-3.10!skip
|
||||||
|
plugins/module_utils/client/resource.py import-3.11!skip
|
||||||
|
plugins/module_utils/k8sdynamicclient.py import-3.9!skip
|
||||||
|
plugins/module_utils/k8sdynamicclient.py import-3.10!skip
|
||||||
|
plugins/module_utils/k8sdynamicclient.py import-3.11!skip
|
||||||
|
plugins/modules/k8s.py validate-modules:parameter-type-not-in-doc
|
||||||
|
plugins/modules/k8s_scale.py validate-modules:parameter-type-not-in-doc
|
||||||
|
plugins/modules/k8s_service.py validate-modules:parameter-type-not-in-doc
|
||||||
|
tests/unit/module_utils/fixtures/clusteroperator.yml yamllint!skip
|
||||||
|
tests/unit/module_utils/fixtures/definitions.yml yamllint!skip
|
||||||
|
tests/unit/module_utils/fixtures/deployments.yml yamllint!skip
|
||||||
|
tests/unit/module_utils/fixtures/pods.yml yamllint!skip
|
||||||
|
tests/integration/targets/helm/files/appversionless-chart-v2/templates/configmap.yaml yamllint!skip
|
||||||
|
tests/integration/targets/helm/files/appversionless-chart/templates/configmap.yaml yamllint!skip
|
||||||
|
tests/integration/targets/helm/files/test-chart-v2/templates/configmap.yaml yamllint!skip
|
||||||
|
tests/integration/targets/helm/files/test-chart/templates/configmap.yaml yamllint!skip
|
||||||
|
tests/integration/targets/helm_diff/files/test-chart/templates/configmap.yaml yamllint!skip
|
||||||
|
tests/integration/targets/k8s_scale/files/deployment.yaml yamllint!skip
|
||||||
|
plugins/modules/k8s.py validate-modules:return-syntax-error
|
||||||
|
plugins/modules/k8s_scale.py validate-modules:return-syntax-error
|
||||||
|
plugins/modules/k8s_service.py validate-modules:return-syntax-error
|
||||||
|
plugins/modules/k8s_taint.py validate-modules:return-syntax-error
|
||||||
|
tests/integration/targets/k8s_delete/files/deployments.yaml yamllint!skip
|
||||||
|
tests/integration/targets/helm_diff/files/test-chart-reuse-values/templates/configmap.yaml yamllint!skip
|
||||||
|
tests/integration/targets/helm_registry_auth/tasks/main.yaml yamllint!skip
|
||||||
|
tests/integration/targets/helm_diff/files/test-chart-deployment-time/templates/configmap.yaml yamllint!skip
|
||||||
|
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
|
plugins/module_utils/client/discovery.py import-3.9!skip
|
||||||
|
plugins/module_utils/client/discovery.py import-3.10!skip
|
||||||
plugins/module_utils/client/discovery.py import-3.11!skip
|
plugins/module_utils/client/discovery.py import-3.11!skip
|
||||||
plugins/module_utils/client/discovery.py import-3.12!skip
|
plugins/module_utils/client/resource.py import-3.9!skip
|
||||||
plugins/module_utils/client/discovery.py import-3.13!skip
|
plugins/module_utils/client/resource.py import-3.10!skip
|
||||||
plugins/module_utils/client/resource.py import-3.11!skip
|
plugins/module_utils/client/resource.py import-3.11!skip
|
||||||
plugins/module_utils/client/resource.py import-3.12!skip
|
plugins/module_utils/k8sdynamicclient.py import-3.9!skip
|
||||||
plugins/module_utils/client/resource.py import-3.13!skip
|
plugins/module_utils/k8sdynamicclient.py import-3.10!skip
|
||||||
plugins/module_utils/k8sdynamicclient.py import-3.11!skip
|
plugins/module_utils/k8sdynamicclient.py import-3.11!skip
|
||||||
plugins/module_utils/k8sdynamicclient.py import-3.12!skip
|
|
||||||
plugins/module_utils/k8sdynamicclient.py import-3.13!skip
|
|
||||||
plugins/module_utils/version.py pylint!skip
|
plugins/module_utils/version.py pylint!skip
|
||||||
plugins/modules/k8s.py validate-modules:parameter-type-not-in-doc
|
plugins/modules/k8s.py validate-modules:parameter-type-not-in-doc
|
||||||
plugins/modules/k8s_scale.py validate-modules:parameter-type-not-in-doc
|
plugins/modules/k8s_scale.py validate-modules:parameter-type-not-in-doc
|
||||||
@@ -2,57 +2,50 @@ from __future__ import absolute_import, division, print_function
|
|||||||
|
|
||||||
__metaclass__ = type
|
__metaclass__ = type
|
||||||
|
|
||||||
import re
|
import json
|
||||||
|
|
||||||
import kubernetes
|
import kubernetes
|
||||||
import pytest
|
import pytest
|
||||||
from ansible_collections.kubernetes.core.plugins.module_utils.k8s.core import (
|
from ansible_collections.kubernetes.core.plugins.module_utils.k8s.core import (
|
||||||
AnsibleK8SModule,
|
AnsibleK8SModule,
|
||||||
)
|
)
|
||||||
from mock import MagicMock, patch
|
|
||||||
|
|
||||||
MINIMAL_K8S_VERSION = "24.2.0"
|
MINIMAL_K8S_VERSION = "24.2.0"
|
||||||
UNSUPPORTED_K8S_VERSION = "11.0.0"
|
UNSUPPORTED_K8S_VERSION = "11.0.0"
|
||||||
|
|
||||||
|
|
||||||
class FakeAnsibleModule:
|
@pytest.mark.parametrize("stdin", [{}], indirect=["stdin"])
|
||||||
def __init__(self, **kwargs):
|
def test_no_warn(monkeypatch, stdin, capfd):
|
||||||
pass
|
|
||||||
|
|
||||||
def exit_json(self):
|
|
||||||
raise SystemExit(0)
|
|
||||||
|
|
||||||
|
|
||||||
@patch.object(AnsibleK8SModule, "warn")
|
|
||||||
def test_no_warn(m_ansible_k8s_module_warn, monkeypatch, capfd):
|
|
||||||
monkeypatch.setattr(kubernetes, "__version__", MINIMAL_K8S_VERSION)
|
monkeypatch.setattr(kubernetes, "__version__", MINIMAL_K8S_VERSION)
|
||||||
|
|
||||||
m_ansible_k8s_module_warn.side_effect = print
|
module = AnsibleK8SModule(argument_spec={})
|
||||||
module = AnsibleK8SModule(argument_spec={}, module_class=FakeAnsibleModule)
|
|
||||||
with pytest.raises(SystemExit):
|
with pytest.raises(SystemExit):
|
||||||
module.exit_json()
|
module.exit_json()
|
||||||
out, err = capfd.readouterr()
|
out, err = capfd.readouterr()
|
||||||
m_ansible_k8s_module_warn.assert_not_called()
|
|
||||||
|
return_value = json.loads(out)
|
||||||
|
|
||||||
|
assert return_value.get("exception") is None
|
||||||
|
assert return_value.get("warnings") is None
|
||||||
|
assert return_value.get("failed") is None
|
||||||
|
|
||||||
|
|
||||||
@patch.object(AnsibleK8SModule, "warn")
|
@pytest.mark.parametrize("stdin", [{}], indirect=["stdin"])
|
||||||
def test_warn_on_k8s_version(m_ansible_k8s_module_warn, monkeypatch, capfd):
|
def test_warn_on_k8s_version(monkeypatch, stdin, capfd):
|
||||||
monkeypatch.setattr(kubernetes, "__version__", UNSUPPORTED_K8S_VERSION)
|
monkeypatch.setattr(kubernetes, "__version__", UNSUPPORTED_K8S_VERSION)
|
||||||
|
|
||||||
m_ansible_k8s_module_warn.side_effect = print
|
module = AnsibleK8SModule(argument_spec={})
|
||||||
module = AnsibleK8SModule(argument_spec={}, module_class=FakeAnsibleModule)
|
|
||||||
with pytest.raises(SystemExit):
|
with pytest.raises(SystemExit):
|
||||||
module.exit_json()
|
module.exit_json()
|
||||||
|
|
||||||
m_ansible_k8s_module_warn.assert_called_once()
|
|
||||||
out, err = capfd.readouterr()
|
out, err = capfd.readouterr()
|
||||||
assert (
|
|
||||||
re.search(
|
return_value = json.loads(out)
|
||||||
r"kubernetes<([0-9]+\.[0-9]+\.[0-9]+) is not supported or tested. Some features may not work.",
|
|
||||||
out,
|
assert return_value.get("warnings") is not None
|
||||||
)
|
warnings = return_value["warnings"]
|
||||||
is not None
|
assert len(warnings) == 1
|
||||||
)
|
assert "kubernetes" in str(warnings[0])
|
||||||
|
assert MINIMAL_K8S_VERSION in str(warnings[0])
|
||||||
|
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
@@ -65,17 +58,9 @@ dependencies = [
|
|||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"stdin,desired,actual,result", [({}, *d) for d in dependencies], indirect=["stdin"]
|
"stdin,desired,actual,result", [({}, *d) for d in dependencies], indirect=["stdin"]
|
||||||
)
|
)
|
||||||
@patch.object(AnsibleK8SModule, "warn")
|
def test_has_at_least(monkeypatch, stdin, desired, actual, result, capfd):
|
||||||
def test_has_at_least(
|
|
||||||
m_ansible_k8s_module_warn, monkeypatch, stdin, desired, actual, result, capfd
|
|
||||||
):
|
|
||||||
monkeypatch.setattr(kubernetes, "__version__", actual)
|
monkeypatch.setattr(kubernetes, "__version__", actual)
|
||||||
|
|
||||||
def fake_warn(x):
|
|
||||||
print(x)
|
|
||||||
raise SystemExit(1)
|
|
||||||
|
|
||||||
m_ansible_k8s_module_warn.side_effect = fake_warn
|
|
||||||
module = AnsibleK8SModule(argument_spec={})
|
module = AnsibleK8SModule(argument_spec={})
|
||||||
|
|
||||||
assert module.has_at_least("kubernetes", desired) is result
|
assert module.has_at_least("kubernetes", desired) is result
|
||||||
@@ -95,18 +80,11 @@ def test_requires_fails_with_message(
|
|||||||
monkeypatch, stdin, dependency, version, msg, capfd
|
monkeypatch, stdin, dependency, version, msg, capfd
|
||||||
):
|
):
|
||||||
monkeypatch.setattr(kubernetes, "__version__", "24.2.0")
|
monkeypatch.setattr(kubernetes, "__version__", "24.2.0")
|
||||||
module = AnsibleK8SModule(argument_spec={}, module_class=FakeAnsibleModule)
|
module = AnsibleK8SModule(argument_spec={})
|
||||||
|
|
||||||
def fake_fail_json(**kwargs):
|
|
||||||
print(f"Printing message => {kwargs}")
|
|
||||||
print(kwargs.get("msg"))
|
|
||||||
raise SystemExit(1)
|
|
||||||
|
|
||||||
module.fail_json = MagicMock()
|
|
||||||
module.fail_json.side_effect = fake_fail_json
|
|
||||||
|
|
||||||
with pytest.raises(SystemExit):
|
with pytest.raises(SystemExit):
|
||||||
module.requires(dependency, version)
|
module.requires(dependency, version)
|
||||||
module.fail_json.assert_called_once()
|
|
||||||
out, err = capfd.readouterr()
|
out, err = capfd.readouterr()
|
||||||
assert msg in out
|
return_value = json.loads(out)
|
||||||
|
|
||||||
|
assert return_value.get("failed")
|
||||||
|
assert msg in return_value.get("msg")
|
||||||
|
|||||||
Reference in New Issue
Block a user