mirror of
https://github.com/ansible-collections/kubernetes.core.git
synced 2026-05-11 20:12:18 +00:00
Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
69304d1c3b | ||
|
|
fdddb6f78f | ||
|
|
e8cf1ef517 | ||
|
|
6dbc0d5b6d | ||
|
|
0a72c87d2c | ||
|
|
c149394556 | ||
|
|
e2dec91460 | ||
|
|
edf104d687 | ||
|
|
7b09c01d98 | ||
|
|
7409eaf993 | ||
|
|
321b6dcdd8 | ||
|
|
68d45af767 |
@@ -5,6 +5,27 @@ Kubernetes Collection Release Notes
|
||||
.. contents:: Topics
|
||||
|
||||
|
||||
v2.3.2
|
||||
======
|
||||
|
||||
Minor Changes
|
||||
-------------
|
||||
|
||||
- helm_repository - mark `pass_credentials` as no_log=True to silence false warning (https://github.com/ansible-collections/kubernetes.core/issues/412).
|
||||
- kubectl.py - replace distutils.spawn.find_executable with shutil.which in the kubectl connection plugin (https://github.com/ansible-collections/kubernetes.core/pull/456).
|
||||
|
||||
v2.3.1
|
||||
======
|
||||
|
||||
Bugfixes
|
||||
--------
|
||||
|
||||
- Catch exception raised when the process is waiting for resources (https://github.com/ansible-collections/kubernetes.core/issues/407).
|
||||
- Remove `omit` placeholder when defining resource using template parameter (https://github.com/ansible-collections/kubernetes.core/issues/431).
|
||||
- k8s - fix the issue when trying to delete resources using label_selectors options (https://github.com/ansible-collections/kubernetes.core/issues/433).
|
||||
- k8s_cp - fix issue when using parameter local_path with file on managed node. (https://github.com/ansible-collections/kubernetes.core/issues/421).
|
||||
- k8s_drain - fix error occurring when trying to drain node with disable_eviction set to yes (https://github.com/ansible-collections/kubernetes.core/issues/416).
|
||||
|
||||
v2.3.0
|
||||
======
|
||||
|
||||
|
||||
2
Makefile
2
Makefile
@@ -1,5 +1,5 @@
|
||||
# Also needs to be updated in galaxy.yml
|
||||
VERSION = 2.3.0
|
||||
VERSION = 2.3.2
|
||||
|
||||
TEST_ARGS ?= ""
|
||||
PYTHON_VERSION ?= `python -c 'import platform; print(".".join(platform.python_version_tuple()[0:2]))'`
|
||||
|
||||
48
PSF-license.txt
Normal file
48
PSF-license.txt
Normal file
@@ -0,0 +1,48 @@
|
||||
PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
|
||||
--------------------------------------------
|
||||
|
||||
1. This LICENSE AGREEMENT is between the Python Software Foundation
|
||||
("PSF"), and the Individual or Organization ("Licensee") accessing and
|
||||
otherwise using this software ("Python") in source or binary form and
|
||||
its associated documentation.
|
||||
|
||||
2. Subject to the terms and conditions of this License Agreement, PSF hereby
|
||||
grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce,
|
||||
analyze, test, perform and/or display publicly, prepare derivative works,
|
||||
distribute, and otherwise use Python alone or in any derivative version,
|
||||
provided, however, that PSF's License Agreement and PSF's notice of copyright,
|
||||
i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
|
||||
2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021 Python Software Foundation;
|
||||
All Rights Reserved" are retained in Python alone or in any derivative version
|
||||
prepared by Licensee.
|
||||
|
||||
3. In the event Licensee prepares a derivative work that is based on
|
||||
or incorporates Python or any part thereof, and wants to make
|
||||
the derivative work available to others as provided herein, then
|
||||
Licensee hereby agrees to include in any such work a brief summary of
|
||||
the changes made to Python.
|
||||
|
||||
4. PSF is making Python available to Licensee on an "AS IS"
|
||||
basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
|
||||
IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND
|
||||
DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
|
||||
FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT
|
||||
INFRINGE ANY THIRD PARTY RIGHTS.
|
||||
|
||||
5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
|
||||
FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
|
||||
A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON,
|
||||
OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
|
||||
|
||||
6. This License Agreement will automatically terminate upon a material
|
||||
breach of its terms and conditions.
|
||||
|
||||
7. Nothing in this License Agreement shall be deemed to create any
|
||||
relationship of agency, partnership, or joint venture between PSF and
|
||||
Licensee. This License Agreement does not grant permission to use PSF
|
||||
trademarks or trade name in a trademark sense to endorse or promote
|
||||
products or services of Licensee, or any third party.
|
||||
|
||||
8. By copying, installing or otherwise using Python, Licensee
|
||||
agrees to be bound by the terms and conditions of this License
|
||||
Agreement.
|
||||
@@ -11,6 +11,8 @@ The collection includes a variety of Ansible content to help automate the manage
|
||||
|
||||
This collection has been tested against following Ansible versions: **>=2.9.17**.
|
||||
|
||||
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`).
|
||||
Plugins and modules within a collection may be tested with only specific Ansible versions.
|
||||
A collection may contain metadata that identifies these versions.
|
||||
PEP440 is the schema used to describe the versions of Ansible.
|
||||
@@ -90,7 +92,7 @@ You can also include it in a `requirements.yml` file and install it via `ansible
|
||||
---
|
||||
collections:
|
||||
- name: kubernetes.core
|
||||
version: 2.3.0
|
||||
version: 2.3.2
|
||||
```
|
||||
|
||||
### Installing the Kubernetes Python Library
|
||||
|
||||
@@ -568,3 +568,33 @@ releases:
|
||||
name: k8s_taint
|
||||
namespace: ''
|
||||
release_date: '2022-03-11'
|
||||
2.3.1:
|
||||
changes:
|
||||
bugfixes:
|
||||
- Catch expectation raised when the process is waiting for resources (https://github.com/ansible-collections/kubernetes.core/issues/407).
|
||||
- Remove `omit` placeholder when defining resource using template parameter
|
||||
(https://github.com/ansible-collections/kubernetes.core/issues/431).
|
||||
- k8s - fix the issue when trying to delete resources using label_selectors
|
||||
options (https://github.com/ansible-collections/kubernetes.core/issues/433).
|
||||
- k8s_cp - fix issue when using parameter local_path with file on managed node.
|
||||
(https://github.com/ansible-collections/kubernetes.core/issues/421).
|
||||
- k8s_drain - fix error occurring when trying to drain node with disable_eviction
|
||||
set to yes (https://github.com/ansible-collections/kubernetes.core/issues/416).
|
||||
fragments:
|
||||
- 408-fix-wait-on-exception.yml
|
||||
- 417-fix-k8s-drain-delete-options.yaml
|
||||
- 422-k8s_cp-fix-issue-when-issue-local_path.yaml
|
||||
- 432-fix-issue-when-using-template-parameter.yaml
|
||||
- 434-fix-k8s-delete-using-label_selector.yaml
|
||||
release_date: '2022-05-02'
|
||||
2.3.2:
|
||||
changes:
|
||||
minor_changes:
|
||||
- helm_repository - mark `pass_credentials` as no_log=True to silence false
|
||||
warning (https://github.com/ansible-collections/kubernetes.core/issues/412).
|
||||
- kubectl.py - replace distutils.spawn.find_executable with shutil.which in
|
||||
the kubectl connection plugin (https://github.com/ansible-collections/kubernetes.core/pull/456).
|
||||
fragments:
|
||||
- 412_pass_creds.yml
|
||||
- 456-replace-distutils.yml
|
||||
release_date: '2022-06-09'
|
||||
|
||||
@@ -151,7 +151,7 @@ Parameters
|
||||
</td>
|
||||
<td>
|
||||
<div>Group(s) to impersonate for the operation.</div>
|
||||
<div>Can also be specified via K8S_AUTH_IMPERSONATE_GROUPS environment. Example: 'Group1,Group2'</div>
|
||||
<div>Can also be specified via K8S_AUTH_IMPERSONATE_GROUPS environment. Example: Group1,Group2</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
||||
@@ -182,7 +182,7 @@ Parameters
|
||||
</td>
|
||||
<td>
|
||||
<div>Group(s) to impersonate for the operation.</div>
|
||||
<div>Can also be specified via K8S_AUTH_IMPERSONATE_GROUPS environment. Example: 'Group1,Group2'</div>
|
||||
<div>Can also be specified via K8S_AUTH_IMPERSONATE_GROUPS environment. Example: Group1,Group2</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
||||
@@ -302,7 +302,7 @@ Parameters
|
||||
</td>
|
||||
<td>
|
||||
<div>Group(s) to impersonate for the operation.</div>
|
||||
<div>Can also be specified via K8S_AUTH_IMPERSONATE_GROUPS environment. Example: 'Group1,Group2'</div>
|
||||
<div>Can also be specified via K8S_AUTH_IMPERSONATE_GROUPS environment. Example: Group1,Group2</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
||||
@@ -182,7 +182,7 @@ Parameters
|
||||
</td>
|
||||
<td>
|
||||
<div>Group(s) to impersonate for the operation.</div>
|
||||
<div>Can also be specified via K8S_AUTH_IMPERSONATE_GROUPS environment. Example: 'Group1,Group2'</div>
|
||||
<div>Can also be specified via K8S_AUTH_IMPERSONATE_GROUPS environment. Example: Group1,Group2</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
||||
@@ -188,7 +188,7 @@ Parameters
|
||||
</td>
|
||||
<td>
|
||||
<div>Group(s) to impersonate for the operation.</div>
|
||||
<div>Can also be specified via K8S_AUTH_IMPERSONATE_GROUPS environment. Example: 'Group1,Group2'</div>
|
||||
<div>Can also be specified via K8S_AUTH_IMPERSONATE_GROUPS environment. Example: Group1,Group2</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
||||
@@ -170,7 +170,7 @@ Parameters
|
||||
</td>
|
||||
<td>
|
||||
<div>Group(s) to impersonate for the operation.</div>
|
||||
<div>Can also be specified via K8S_AUTH_IMPERSONATE_GROUPS environment. Example: 'Group1,Group2'</div>
|
||||
<div>Can also be specified via K8S_AUTH_IMPERSONATE_GROUPS environment. Example: Group1,Group2</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
||||
@@ -189,7 +189,7 @@ Parameters
|
||||
</td>
|
||||
<td>
|
||||
<div>Group(s) to impersonate for the operation.</div>
|
||||
<div>Can also be specified via K8S_AUTH_IMPERSONATE_GROUPS environment. Example: 'Group1,Group2'</div>
|
||||
<div>Can also be specified via K8S_AUTH_IMPERSONATE_GROUPS environment. Example: Group1,Group2</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
||||
@@ -386,7 +386,7 @@ Parameters
|
||||
</td>
|
||||
<td>
|
||||
<div>Group(s) to impersonate for the operation.</div>
|
||||
<div>Can also be specified via K8S_AUTH_IMPERSONATE_GROUPS environment. Example: 'Group1,Group2'</div>
|
||||
<div>Can also be specified via K8S_AUTH_IMPERSONATE_GROUPS environment. Example: Group1,Group2</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
||||
@@ -187,7 +187,7 @@ Parameters
|
||||
</td>
|
||||
<td>
|
||||
<div>Group(s) to impersonate for the operation.</div>
|
||||
<div>Can also be specified via K8S_AUTH_IMPERSONATE_GROUPS environment. Example: 'Group1,Group2'</div>
|
||||
<div>Can also be specified via K8S_AUTH_IMPERSONATE_GROUPS environment. Example: Group1,Group2</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
||||
@@ -204,7 +204,7 @@ Parameters
|
||||
</td>
|
||||
<td>
|
||||
<div>Group(s) to impersonate for the operation.</div>
|
||||
<div>Can also be specified via K8S_AUTH_IMPERSONATE_GROUPS environment. Example: 'Group1,Group2'</div>
|
||||
<div>Can also be specified via K8S_AUTH_IMPERSONATE_GROUPS environment. Example: Group1,Group2</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
||||
@@ -187,7 +187,7 @@ Parameters
|
||||
</td>
|
||||
<td>
|
||||
<div>Group(s) to impersonate for the operation.</div>
|
||||
<div>Can also be specified via K8S_AUTH_IMPERSONATE_GROUPS environment. Example: 'Group1,Group2'</div>
|
||||
<div>Can also be specified via K8S_AUTH_IMPERSONATE_GROUPS environment. Example: Group1,Group2</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
||||
@@ -149,7 +149,7 @@ Parameters
|
||||
</td>
|
||||
<td>
|
||||
<div>Group(s) to impersonate for the operation.</div>
|
||||
<div>Can also be specified via K8S_AUTH_IMPERSONATE_GROUPS environment. Example: 'Group1,Group2'</div>
|
||||
<div>Can also be specified via K8S_AUTH_IMPERSONATE_GROUPS environment. Example: Group1,Group2</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
||||
@@ -25,7 +25,7 @@ tags:
|
||||
- openshift
|
||||
- okd
|
||||
- cluster
|
||||
version: 2.3.0
|
||||
version: 2.3.2
|
||||
build_ignore:
|
||||
- .DS_Store
|
||||
- '*.tar.gz'
|
||||
|
||||
@@ -12,7 +12,6 @@ import traceback
|
||||
import os
|
||||
from contextlib import contextmanager
|
||||
|
||||
|
||||
from ansible.config.manager import ensure_type
|
||||
from ansible.errors import (
|
||||
AnsibleError,
|
||||
@@ -26,6 +25,31 @@ from ansible.module_utils._text import to_text, to_bytes, to_native
|
||||
from ansible.plugins.action import ActionBase
|
||||
|
||||
|
||||
class RemoveOmit(object):
|
||||
def __init__(self, buffer, omit_value):
|
||||
try:
|
||||
import yaml
|
||||
except ImportError:
|
||||
raise AnsibleError("Failed to import the required Python library (PyYAML).")
|
||||
self.data = yaml.safe_load_all(buffer)
|
||||
self.omit = omit_value
|
||||
|
||||
def remove_omit(self, data):
|
||||
if isinstance(data, dict):
|
||||
result = dict()
|
||||
for key, value in iteritems(data):
|
||||
if value == self.omit:
|
||||
continue
|
||||
result[key] = self.remove_omit(value)
|
||||
return result
|
||||
if isinstance(data, list):
|
||||
return [self.remove_omit(v) for v in data if v != self.omit]
|
||||
return data
|
||||
|
||||
def output(self):
|
||||
return [self.remove_omit(d) for d in self.data]
|
||||
|
||||
|
||||
class ActionModule(ActionBase):
|
||||
|
||||
TRANSFERS_FILES = True
|
||||
@@ -180,6 +204,7 @@ class ActionModule(ActionBase):
|
||||
"'template' is only a supported parameter for the 'k8s' module."
|
||||
)
|
||||
|
||||
omit_value = task_vars.get("omit")
|
||||
template_params = []
|
||||
if isinstance(template, string_types) or isinstance(template, dict):
|
||||
template_params.append(self.get_template_args(template))
|
||||
@@ -245,6 +270,9 @@ class ActionModule(ActionBase):
|
||||
preserve_trailing_newlines=True,
|
||||
escape_backslashes=False,
|
||||
)
|
||||
if omit_value is not None:
|
||||
result_template.extend(RemoveOmit(result, omit_value).output())
|
||||
else:
|
||||
result_template.append(result)
|
||||
self._templar.available_variables = old_vars
|
||||
resource_definition = self._task.args.get("definition", None)
|
||||
@@ -352,7 +380,7 @@ class ActionModule(ActionBase):
|
||||
|
||||
local_path = self._task.args.get("local_path")
|
||||
state = self._task.args.get("state", None)
|
||||
if local_path and state == "to_pod":
|
||||
if local_path and state == "to_pod" and not remote_transport:
|
||||
new_module_args["local_path"] = self.get_file_realpath(local_path)
|
||||
|
||||
# Execute the k8s_* module.
|
||||
|
||||
@@ -171,9 +171,9 @@ DOCUMENTATION = r"""
|
||||
aliases: [ kubectl_verify_ssl ]
|
||||
"""
|
||||
|
||||
import distutils.spawn
|
||||
import os
|
||||
import os.path
|
||||
import shutil
|
||||
import subprocess
|
||||
|
||||
from ansible.parsing.yaml.loader import AnsibleLoader
|
||||
@@ -219,14 +219,9 @@ class Connection(ConnectionBase):
|
||||
# Note: kubectl runs commands as the user that started the container.
|
||||
# It is impossible to set the remote user for a kubectl connection.
|
||||
cmd_arg = "{0}_command".format(self.transport)
|
||||
if cmd_arg in kwargs:
|
||||
self.transport_cmd = kwargs[cmd_arg]
|
||||
else:
|
||||
self.transport_cmd = distutils.spawn.find_executable(self.transport)
|
||||
self.transport_cmd = kwargs.get(cmd_arg, shutil.which(self.transport))
|
||||
if not self.transport_cmd:
|
||||
raise AnsibleError(
|
||||
"{0} command not found in PATH".format(self.transport)
|
||||
)
|
||||
raise AnsibleError("{0} command not found in PATH".format(self.transport))
|
||||
|
||||
def _build_exec_cmd(self, cmd):
|
||||
"""Build the local kubectl exec command to run cmd on remote_host"""
|
||||
@@ -240,12 +235,12 @@ class Connection(ConnectionBase):
|
||||
# Translate verify_ssl to skip_verify_ssl, and output as string
|
||||
skip_verify_ssl = not self.get_option(key)
|
||||
local_cmd.append(
|
||||
u"{0}={1}".format(
|
||||
"{0}={1}".format(
|
||||
self.connection_options[key], str(skip_verify_ssl).lower()
|
||||
)
|
||||
)
|
||||
censored_local_cmd.append(
|
||||
u"{0}={1}".format(
|
||||
"{0}={1}".format(
|
||||
self.connection_options[key], str(skip_verify_ssl).lower()
|
||||
)
|
||||
)
|
||||
@@ -262,12 +257,12 @@ class Connection(ConnectionBase):
|
||||
else:
|
||||
censored_local_cmd += [cmd_arg, self.get_option(key)]
|
||||
|
||||
extra_args_name = u"{0}_extra_args".format(self.transport)
|
||||
extra_args_name = "{0}_extra_args".format(self.transport)
|
||||
if self.get_option(extra_args_name):
|
||||
local_cmd += self.get_option(extra_args_name).split(" ")
|
||||
censored_local_cmd += self.get_option(extra_args_name).split(" ")
|
||||
|
||||
pod = self.get_option(u"{0}_pod".format(self.transport))
|
||||
pod = self.get_option("{0}_pod".format(self.transport))
|
||||
if not pod:
|
||||
pod = self._play_context.remote_addr
|
||||
# -i is needed to keep stdin open which allows pipelining to work
|
||||
@@ -275,7 +270,7 @@ class Connection(ConnectionBase):
|
||||
censored_local_cmd += ["exec", "-i", pod]
|
||||
|
||||
# if the pod has more than one container, then container is required
|
||||
container_arg_name = u"{0}_container".format(self.transport)
|
||||
container_arg_name = "{0}_container".format(self.transport)
|
||||
if self.get_option(container_arg_name):
|
||||
local_cmd += ["-c", self.get_option(container_arg_name)]
|
||||
censored_local_cmd += ["-c", self.get_option(container_arg_name)]
|
||||
@@ -290,7 +285,7 @@ class Connection(ConnectionBase):
|
||||
super(Connection, self)._connect()
|
||||
if not self._connected:
|
||||
display.vvv(
|
||||
u"ESTABLISH {0} CONNECTION".format(self.transport),
|
||||
"ESTABLISH {0} CONNECTION".format(self.transport),
|
||||
host=self._play_context.remote_addr,
|
||||
)
|
||||
self._connected = True
|
||||
|
||||
@@ -128,7 +128,7 @@ options:
|
||||
impersonate_groups:
|
||||
description:
|
||||
- Group(s) to impersonate for the operation.
|
||||
- "Can also be specified via K8S_AUTH_IMPERSONATE_GROUPS environment. Example: 'Group1,Group2'"
|
||||
- "Can also be specified via K8S_AUTH_IMPERSONATE_GROUPS environment. Example: Group1,Group2"
|
||||
type: list
|
||||
elements: str
|
||||
version_added: 2.3.0
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# Implements multiple version numbering conventions for the
|
||||
# Python Module Distribution Utilities.
|
||||
#
|
||||
# PSF License (see licenses/PSF-license.txt or https://opensource.org/licenses/Python-2.0)
|
||||
# PSF License (see PSF-license.txt or https://opensource.org/licenses/Python-2.0)
|
||||
#
|
||||
|
||||
"""Provides classes to represent module version numbers (one class for
|
||||
|
||||
@@ -421,18 +421,25 @@ class K8sAnsibleMixin(object):
|
||||
field_selectors = []
|
||||
|
||||
result = None
|
||||
try:
|
||||
result = resource.get(
|
||||
params = dict(
|
||||
name=name,
|
||||
namespace=namespace,
|
||||
label_selector=",".join(label_selectors),
|
||||
field_selector=",".join(field_selectors),
|
||||
)
|
||||
try:
|
||||
result = resource.get(**params)
|
||||
except BadRequestError:
|
||||
return dict(resources=[], api_found=True)
|
||||
except NotFoundError:
|
||||
if not wait or name is None:
|
||||
return dict(resources=[], api_found=True)
|
||||
except Exception as e:
|
||||
if not wait or name is None:
|
||||
err = "Exception '{0}' raised while trying to get resource using {1}".format(
|
||||
e, params
|
||||
)
|
||||
return dict(resources=[], msg=err, api_found=True)
|
||||
|
||||
if not wait:
|
||||
result = result.to_dict()
|
||||
@@ -452,21 +459,27 @@ class K8sAnsibleMixin(object):
|
||||
and not result.get("items")
|
||||
)
|
||||
|
||||
last_exception = None
|
||||
while result_empty(result) and _elapsed() < wait_timeout:
|
||||
try:
|
||||
result = resource.get(
|
||||
name=name,
|
||||
namespace=namespace,
|
||||
label_selector=",".join(label_selectors),
|
||||
field_selector=",".join(field_selectors),
|
||||
)
|
||||
result = resource.get(**params)
|
||||
except NotFoundError:
|
||||
pass
|
||||
except Exception as e:
|
||||
last_exception = e
|
||||
if not result_empty(result):
|
||||
break
|
||||
time.sleep(wait_sleep)
|
||||
if result_empty(result):
|
||||
return dict(resources=[], api_found=True)
|
||||
res = dict(resources=[], api_found=True)
|
||||
if last_exception is not None:
|
||||
res[
|
||||
"msg"
|
||||
] = "Exception '%s' raised while trying to get resource using %s" % (
|
||||
last_exception,
|
||||
params,
|
||||
)
|
||||
return res
|
||||
|
||||
if isinstance(result, ResourceInstance):
|
||||
satisfied_by = []
|
||||
@@ -583,6 +596,8 @@ class K8sAnsibleMixin(object):
|
||||
except NotFoundError:
|
||||
if state == "absent":
|
||||
return True, {}, _wait_for_elapsed()
|
||||
except Exception:
|
||||
pass
|
||||
if response:
|
||||
response = response.to_dict()
|
||||
return False, response, _wait_for_elapsed()
|
||||
@@ -980,6 +995,7 @@ class K8sAnsibleMixin(object):
|
||||
if self.check_mode and not self.supports_dry_run:
|
||||
return result
|
||||
else:
|
||||
params = {"namespace": namespace}
|
||||
if delete_options:
|
||||
body = {
|
||||
"apiVersion": "v1",
|
||||
@@ -990,6 +1006,16 @@ class K8sAnsibleMixin(object):
|
||||
if self.check_mode:
|
||||
params["dry_run"] = "All"
|
||||
try:
|
||||
if existing.kind.endswith("List"):
|
||||
result["result"] = []
|
||||
for item in existing.items:
|
||||
origin_name = item.metadata.name
|
||||
params["name"] = origin_name
|
||||
k8s_obj = resource.delete(**params)
|
||||
result["result"].append(k8s_obj.to_dict())
|
||||
else:
|
||||
origin_name = existing.metadata.name
|
||||
params["name"] = origin_name
|
||||
k8s_obj = resource.delete(**params)
|
||||
result["result"] = k8s_obj.to_dict()
|
||||
except DynamicApiError as exc:
|
||||
|
||||
@@ -385,9 +385,11 @@ def check_pod(k8s_ansible_mixin, module):
|
||||
def _fail(exc):
|
||||
arg = {}
|
||||
if hasattr(exc, "body"):
|
||||
msg = "Namespace={0} Kind=Pod Name={1}: Failed requested object: {2}".format(
|
||||
msg = (
|
||||
"Namespace={0} Kind=Pod Name={1}: Failed requested object: {2}".format(
|
||||
namespace, name, exc.body
|
||||
)
|
||||
)
|
||||
else:
|
||||
msg = to_native(exc)
|
||||
for attr in ["status", "reason"]:
|
||||
|
||||
@@ -123,9 +123,15 @@ def main():
|
||||
state=dict(
|
||||
type="str", default="present", choices=["present", "absent", "latest"]
|
||||
),
|
||||
plugin_path=dict(type="str",),
|
||||
plugin_name=dict(type="str",),
|
||||
plugin_version=dict(type="str",),
|
||||
plugin_path=dict(
|
||||
type="str",
|
||||
),
|
||||
plugin_name=dict(
|
||||
type="str",
|
||||
),
|
||||
plugin_version=dict(
|
||||
type="str",
|
||||
),
|
||||
# Helm options
|
||||
context=dict(
|
||||
type="str",
|
||||
|
||||
@@ -81,7 +81,9 @@ def main():
|
||||
module = AnsibleModule(
|
||||
argument_spec=dict(
|
||||
binary_path=dict(type="path"),
|
||||
plugin_name=dict(type="str",),
|
||||
plugin_name=dict(
|
||||
type="str",
|
||||
),
|
||||
# Helm options
|
||||
context=dict(
|
||||
type="str",
|
||||
|
||||
@@ -228,7 +228,7 @@ def main():
|
||||
repo_state=dict(
|
||||
default="present", choices=["present", "absent"], aliases=["state"]
|
||||
),
|
||||
pass_credentials=dict(type="bool", default=False),
|
||||
pass_credentials=dict(type="bool", default=False, no_log=True),
|
||||
# Generic auth key
|
||||
host=dict(type="str", fallback=(env_fallback, ["K8S_AUTH_HOST"])),
|
||||
ca_cert=dict(
|
||||
|
||||
@@ -140,7 +140,7 @@ from ansible.module_utils._text import to_native
|
||||
|
||||
try:
|
||||
from kubernetes.client.api import core_v1_api
|
||||
from kubernetes.client.models import V1DeleteOptions
|
||||
from kubernetes.client.models import V1DeleteOptions, V1ObjectMeta
|
||||
from kubernetes.client.exceptions import ApiException
|
||||
except ImportError:
|
||||
# ImportError are managed by the common module already.
|
||||
@@ -273,15 +273,8 @@ class K8sDrainAnsible(object):
|
||||
self._drain_options = module.params.get("delete_options", {})
|
||||
self._delete_options = None
|
||||
if self._drain_options.get("terminate_grace_period"):
|
||||
self._delete_options = {}
|
||||
self._delete_options.update({"apiVersion": "v1"})
|
||||
self._delete_options.update({"kind": "DeleteOptions"})
|
||||
self._delete_options.update(
|
||||
{
|
||||
"gracePeriodSeconds": self._drain_options.get(
|
||||
"terminate_grace_period"
|
||||
)
|
||||
}
|
||||
self._delete_options = V1DeleteOptions(
|
||||
grace_period_seconds=self._drain_options.get("terminate_grace_period")
|
||||
)
|
||||
|
||||
self._changed = False
|
||||
@@ -318,17 +311,16 @@ class K8sDrainAnsible(object):
|
||||
|
||||
def evict_pods(self, pods):
|
||||
for namespace, name in pods:
|
||||
definition = {"metadata": {"name": name, "namespace": namespace}}
|
||||
if self._delete_options:
|
||||
definition.update({"delete_options": self._delete_options})
|
||||
try:
|
||||
if self._drain_options.get("disable_eviction"):
|
||||
body = V1DeleteOptions(**definition)
|
||||
self._api_instance.delete_namespaced_pod(
|
||||
name=name, namespace=namespace, body=body
|
||||
name=name, namespace=namespace, body=self._delete_options
|
||||
)
|
||||
else:
|
||||
body = v1_eviction(**definition)
|
||||
body = v1_eviction(
|
||||
delete_options=self._delete_options,
|
||||
metadata=V1ObjectMeta(name=name, namespace=namespace),
|
||||
)
|
||||
self._api_instance.create_namespaced_pod_eviction(
|
||||
name=name, namespace=namespace, body=body
|
||||
)
|
||||
|
||||
@@ -227,7 +227,10 @@ def execute_module(module, k8s_ansible_mixin):
|
||||
|
||||
|
||||
def main():
|
||||
module = AnsibleModule(argument_spec=argspec(), supports_check_mode=True,)
|
||||
module = AnsibleModule(
|
||||
argument_spec=argspec(),
|
||||
supports_check_mode=True,
|
||||
)
|
||||
from ansible_collections.kubernetes.core.plugins.module_utils.common import (
|
||||
K8sAnsibleMixin,
|
||||
get_api_client,
|
||||
|
||||
@@ -164,7 +164,8 @@ SCALE_ARG_SPEC = {
|
||||
|
||||
|
||||
def execute_module(
|
||||
module, k8s_ansible_mixin,
|
||||
module,
|
||||
k8s_ansible_mixin,
|
||||
):
|
||||
k8s_ansible_mixin.set_resource_definitions(module)
|
||||
|
||||
|
||||
@@ -301,7 +301,10 @@ class K8sTaintAnsible:
|
||||
|
||||
|
||||
def main():
|
||||
module = AnsibleModule(argument_spec=argspec(), supports_check_mode=True,)
|
||||
module = AnsibleModule(
|
||||
argument_spec=argspec(),
|
||||
supports_check_mode=True,
|
||||
)
|
||||
k8s_taint = K8sTaintAnsible(module)
|
||||
k8s_taint.execute_module()
|
||||
|
||||
|
||||
@@ -62,7 +62,8 @@ from ansible.module_utils.basic import AnsibleModule
|
||||
def main():
|
||||
module = AnsibleModule(
|
||||
argument_spec=dict(
|
||||
binary_path=dict(type="path"), version=dict(type="str", default="3.7.0"),
|
||||
binary_path=dict(type="path"),
|
||||
version=dict(type="str", default="3.7.0"),
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
@@ -76,6 +76,51 @@
|
||||
that:
|
||||
- not pods_delete.resources
|
||||
|
||||
# test deletion using label selector
|
||||
- name: Deploy load balancer
|
||||
k8s:
|
||||
namespace: "{{ test_namespace }}"
|
||||
definition:
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
labels:
|
||||
test: deletion
|
||||
name: "deletion-svc-{{ item }}"
|
||||
spec:
|
||||
ports:
|
||||
- port: 5000
|
||||
targetPort: 5000
|
||||
selector:
|
||||
test: deletion
|
||||
type: LoadBalancer
|
||||
with_items:
|
||||
- "01"
|
||||
- "02"
|
||||
- "03"
|
||||
|
||||
- name: Delete services using label selector
|
||||
kubernetes.core.k8s:
|
||||
api_version: v1
|
||||
namespace: "{{ test_namespace }}"
|
||||
kind: Service
|
||||
state: absent
|
||||
label_selectors:
|
||||
- test=deletion
|
||||
|
||||
- name: list services using label selector
|
||||
k8s_info:
|
||||
kind: Service
|
||||
namespace: "{{ test_namespace }}"
|
||||
label_selectors:
|
||||
- test=deletion
|
||||
register: _result
|
||||
|
||||
- name: Validate that all services were deleted
|
||||
assert:
|
||||
that:
|
||||
- _result.resources | length == 0
|
||||
|
||||
always:
|
||||
- name: Remove namespace
|
||||
k8s:
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
k8s_drain
|
||||
k8s
|
||||
k8s_info
|
||||
time=78
|
||||
time=121
|
||||
|
||||
@@ -286,6 +286,72 @@
|
||||
state: uncordon
|
||||
name: '{{ node_to_drain }}'
|
||||
|
||||
- name: Create another Pod
|
||||
k8s:
|
||||
namespace: '{{ test_namespace }}'
|
||||
wait: yes
|
||||
wait_timeout: "{{ k8s_wait_timeout | default(omit) }}"
|
||||
definition:
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: '{{ drain_pod_name }}-01'
|
||||
spec:
|
||||
affinity:
|
||||
nodeAffinity:
|
||||
requiredDuringSchedulingIgnoredDuringExecution:
|
||||
nodeSelectorTerms:
|
||||
- matchFields:
|
||||
- key: metadata.name
|
||||
operator: In
|
||||
values:
|
||||
- '{{ node_to_drain }}'
|
||||
containers:
|
||||
- name: c0
|
||||
image: busybox
|
||||
command:
|
||||
- /bin/sh
|
||||
- -c
|
||||
- while true;do date;sleep 5; done
|
||||
volumeMounts:
|
||||
- mountPath: /emptydir
|
||||
name: emptydir
|
||||
volumes:
|
||||
- name: emptydir
|
||||
emptyDir: {}
|
||||
|
||||
- name: Drain node using disable_eviction set to yes
|
||||
k8s_drain:
|
||||
state: drain
|
||||
name: '{{ node_to_drain }}'
|
||||
delete_options:
|
||||
force: true
|
||||
disable_eviction: yes
|
||||
terminate_grace_period: 0
|
||||
ignore_daemonsets: yes
|
||||
wait_timeout: 0
|
||||
delete_emptydir_data: true
|
||||
register: disable_evict
|
||||
|
||||
- name: assert that node has been drained
|
||||
assert:
|
||||
that:
|
||||
- disable_evict is changed
|
||||
- '"node {{ node_to_drain }} marked unschedulable." in disable_evict.result'
|
||||
|
||||
- name: assert that unmanaged pod were deleted
|
||||
k8s_info:
|
||||
namespace: '{{ test_namespace }}'
|
||||
kind: Pod
|
||||
name: '{{ drain_pod_name }}-01'
|
||||
register: _result
|
||||
failed_when: _result.resources
|
||||
|
||||
- name: Uncordon node
|
||||
k8s_drain:
|
||||
state: uncordon
|
||||
name: '{{ node_to_drain }}'
|
||||
|
||||
always:
|
||||
- name: Uncordon node
|
||||
k8s_drain:
|
||||
|
||||
@@ -239,6 +239,63 @@
|
||||
- resource.result.results | selectattr('changed') | list | length == 1
|
||||
- resource.result.results | selectattr('error', 'defined') | list | length == 1
|
||||
|
||||
# Test resource definition using template with 'omit'
|
||||
- name: Deploy configmap using template
|
||||
k8s:
|
||||
namespace: "{{ template_namespace }}"
|
||||
name: test-data
|
||||
template: configmap.yml.j2
|
||||
|
||||
- name: Read configmap created
|
||||
k8s_info:
|
||||
kind: configmap
|
||||
namespace: "{{ template_namespace }}"
|
||||
name: test-data
|
||||
register: _configmap
|
||||
|
||||
- name: Validate that the configmap does not contains annotations
|
||||
assert:
|
||||
that:
|
||||
- '"annotations" not in _configmap.resources.0.metadata'
|
||||
|
||||
- name: Create resource once again
|
||||
k8s:
|
||||
namespace: "{{ template_namespace }}"
|
||||
name: test-data
|
||||
template: configmap.yml.j2
|
||||
register: _configmap
|
||||
|
||||
- name: assert that nothing changed
|
||||
assert:
|
||||
that:
|
||||
- _configmap is not changed
|
||||
|
||||
- name: Create resource once again (using description)
|
||||
k8s:
|
||||
namespace: "{{ template_namespace }}"
|
||||
name: test-data
|
||||
template: configmap.yml.j2
|
||||
register: _configmap
|
||||
vars:
|
||||
k8s_configmap_desc: "This is a simple configmap used to test ansible k8s collection"
|
||||
|
||||
- name: assert that configmap was changed
|
||||
assert:
|
||||
that:
|
||||
- _configmap is changed
|
||||
|
||||
- name: Read configmap created
|
||||
k8s_info:
|
||||
kind: configmap
|
||||
namespace: "{{ template_namespace }}"
|
||||
name: test-data
|
||||
register: _configmap
|
||||
|
||||
- name: Validate that the configmap does not contains annotations
|
||||
assert:
|
||||
that:
|
||||
- _configmap.resources.0.metadata.annotations.description == "This is a simple configmap used to test ansible k8s collection"
|
||||
|
||||
always:
|
||||
- name: Remove namespace (Cleanup)
|
||||
kubernetes.core.k8s:
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
annotations:
|
||||
description: "{{ k8s_configmap_desc | default(omit) }}"
|
||||
data:
|
||||
key: "testing-template"
|
||||
104
tests/unit/action/test_remove_omit.py
Normal file
104
tests/unit/action/test_remove_omit.py
Normal file
@@ -0,0 +1,104 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright: (c) 2022, 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
|
||||
|
||||
from datetime import datetime
|
||||
from ansible_collections.kubernetes.core.plugins.action.k8s_info import RemoveOmit
|
||||
|
||||
|
||||
def get_omit_token():
|
||||
return "__omit_place_holder__%s" % datetime.now().strftime("%Y%m%d%H%M%S")
|
||||
|
||||
|
||||
def test_remove_omit_from_str():
|
||||
omit_token = get_omit_token()
|
||||
src = """
|
||||
project: ansible
|
||||
collection: {omit}
|
||||
""".format(
|
||||
omit=omit_token
|
||||
)
|
||||
result = RemoveOmit(src, omit_value=omit_token).output()
|
||||
assert len(result) == 1
|
||||
assert result[0] == dict(project="ansible")
|
||||
|
||||
|
||||
def test_remove_omit_from_list():
|
||||
omit_token = get_omit_token()
|
||||
src = """
|
||||
items:
|
||||
- {omit}
|
||||
""".format(
|
||||
omit=omit_token
|
||||
)
|
||||
result = RemoveOmit(src, omit_value=omit_token).output()
|
||||
assert len(result) == 1
|
||||
assert result[0] == dict(items=[])
|
||||
|
||||
|
||||
def test_remove_omit_from_list_of_dict():
|
||||
omit_token = get_omit_token()
|
||||
src = """
|
||||
items:
|
||||
- owner: ansible
|
||||
team: {omit}
|
||||
- simple_list_item
|
||||
""".format(
|
||||
omit=omit_token
|
||||
)
|
||||
result = RemoveOmit(src, omit_value=omit_token).output()
|
||||
assert len(result) == 1
|
||||
assert result[0] == dict(items=[dict(owner="ansible"), "simple_list_item"])
|
||||
|
||||
|
||||
def test_remove_omit_combined():
|
||||
omit_token = get_omit_token()
|
||||
src = """
|
||||
items:
|
||||
- {omit}
|
||||
- list_item_a
|
||||
- list_item_b
|
||||
parent:
|
||||
child:
|
||||
subchilda: {omit}
|
||||
subchildb:
|
||||
name: {omit}
|
||||
age: 3
|
||||
""".format(
|
||||
omit=omit_token
|
||||
)
|
||||
result = RemoveOmit(src, omit_value=omit_token).output()
|
||||
assert len(result) == 1
|
||||
assert result[0] == dict(
|
||||
items=["list_item_a", "list_item_b"],
|
||||
parent=dict(child=dict(subchildb=dict(age=3))),
|
||||
)
|
||||
|
||||
|
||||
def test_remove_omit_mutiple_documents():
|
||||
omit_token = get_omit_token()
|
||||
src = [
|
||||
"""
|
||||
project: ansible
|
||||
collection: {omit}
|
||||
""".format(
|
||||
omit=omit_token
|
||||
),
|
||||
"---",
|
||||
"""
|
||||
project: kubernetes
|
||||
environment: production
|
||||
collection: {omit}""".format(
|
||||
omit=omit_token
|
||||
),
|
||||
]
|
||||
src = "\n".join(src)
|
||||
print(src)
|
||||
result = RemoveOmit(src, omit_value=omit_token).output()
|
||||
assert len(result) == 2
|
||||
assert result[0] == dict(project="ansible")
|
||||
assert result[1] == dict(project="kubernetes", environment="production")
|
||||
@@ -324,27 +324,27 @@ tests = [
|
||||
# str type and everything else was mostly unicode type (don't ask me how)
|
||||
dict(
|
||||
last_applied={
|
||||
u"kind": u"ConfigMap",
|
||||
u"data": {u"one": "1", "three": "3", "two": "2"},
|
||||
u"apiVersion": u"v1",
|
||||
u"metadata": {u"namespace": u"apply", u"name": u"apply-configmap"},
|
||||
"kind": "ConfigMap",
|
||||
"data": {"one": "1", "three": "3", "two": "2"},
|
||||
"apiVersion": "v1",
|
||||
"metadata": {"namespace": "apply", "name": "apply-configmap"},
|
||||
},
|
||||
actual={
|
||||
u"kind": u"ConfigMap",
|
||||
u"data": {u"one": "1", "three": "3", "two": "2"},
|
||||
u"apiVersion": u"v1",
|
||||
u"metadata": {
|
||||
u"namespace": u"apply",
|
||||
u"name": u"apply-configmap",
|
||||
u"resourceVersion": "1714994",
|
||||
u"creationTimestamp": u"2019-08-17T05:08:05Z",
|
||||
u"annotations": {},
|
||||
u"selfLink": u"/api/v1/namespaces/apply/configmaps/apply-configmap",
|
||||
u"uid": u"fed45fb0-c0ac-11e9-9d95-025000000001",
|
||||
"kind": "ConfigMap",
|
||||
"data": {"one": "1", "three": "3", "two": "2"},
|
||||
"apiVersion": "v1",
|
||||
"metadata": {
|
||||
"namespace": "apply",
|
||||
"name": "apply-configmap",
|
||||
"resourceVersion": "1714994",
|
||||
"creationTimestamp": "2019-08-17T05:08:05Z",
|
||||
"annotations": {},
|
||||
"selfLink": "/api/v1/namespaces/apply/configmaps/apply-configmap",
|
||||
"uid": "fed45fb0-c0ac-11e9-9d95-025000000001",
|
||||
},
|
||||
},
|
||||
desired={
|
||||
"kind": u"ConfigMap",
|
||||
"kind": "ConfigMap",
|
||||
"data": {"one": "1", "three": "3", "two": "2"},
|
||||
"apiVersion": "v1",
|
||||
"metadata": {"namespace": "apply", "name": "apply-configmap"},
|
||||
@@ -355,7 +355,7 @@ tests = [
|
||||
# then apply the Deployment again. Should un-scale the Deployment
|
||||
dict(
|
||||
last_applied={
|
||||
"kind": u"Deployment",
|
||||
"kind": "Deployment",
|
||||
"spec": {
|
||||
"replicas": 1,
|
||||
"template": {
|
||||
@@ -372,10 +372,10 @@ tests = [
|
||||
}
|
||||
},
|
||||
},
|
||||
"metadata": {"namespace": "apply", "name": u"apply-deployment"},
|
||||
"metadata": {"namespace": "apply", "name": "apply-deployment"},
|
||||
},
|
||||
actual={
|
||||
"kind": u"Deployment",
|
||||
"kind": "Deployment",
|
||||
"spec": {
|
||||
"replicas": 0,
|
||||
"template": {
|
||||
@@ -392,10 +392,10 @@ tests = [
|
||||
}
|
||||
},
|
||||
},
|
||||
"metadata": {"namespace": "apply", "name": u"apply-deployment"},
|
||||
"metadata": {"namespace": "apply", "name": "apply-deployment"},
|
||||
},
|
||||
desired={
|
||||
"kind": u"Deployment",
|
||||
"kind": "Deployment",
|
||||
"spec": {
|
||||
"replicas": 1,
|
||||
"template": {
|
||||
@@ -409,7 +409,7 @@ tests = [
|
||||
}
|
||||
},
|
||||
},
|
||||
"metadata": {"namespace": "apply", "name": u"apply-deployment"},
|
||||
"metadata": {"namespace": "apply", "name": "apply-deployment"},
|
||||
},
|
||||
expected={
|
||||
"spec": {
|
||||
|
||||
@@ -26,25 +26,49 @@ from ansible_collections.kubernetes.core.plugins.module_utils.hashes import (
|
||||
|
||||
tests = [
|
||||
dict(
|
||||
resource=dict(kind="ConfigMap", name="", data=dict(),),
|
||||
resource=dict(
|
||||
kind="ConfigMap",
|
||||
name="",
|
||||
data=dict(),
|
||||
),
|
||||
expected=b'{"data":{},"kind":"ConfigMap","name":""}',
|
||||
),
|
||||
dict(
|
||||
resource=dict(kind="ConfigMap", name="", data=dict(one=""),),
|
||||
resource=dict(
|
||||
kind="ConfigMap",
|
||||
name="",
|
||||
data=dict(one=""),
|
||||
),
|
||||
expected=b'{"data":{"one":""},"kind":"ConfigMap","name":""}',
|
||||
),
|
||||
dict(
|
||||
resource=dict(
|
||||
kind="ConfigMap", name="", data=dict(two="2", one="", three="3",),
|
||||
kind="ConfigMap",
|
||||
name="",
|
||||
data=dict(
|
||||
two="2",
|
||||
one="",
|
||||
three="3",
|
||||
),
|
||||
),
|
||||
expected=b'{"data":{"one":"","three":"3","two":"2"},"kind":"ConfigMap","name":""}',
|
||||
),
|
||||
dict(
|
||||
resource=dict(kind="Secret", type="my-type", name="", data=dict(),),
|
||||
resource=dict(
|
||||
kind="Secret",
|
||||
type="my-type",
|
||||
name="",
|
||||
data=dict(),
|
||||
),
|
||||
expected=b'{"data":{},"kind":"Secret","name":"","type":"my-type"}',
|
||||
),
|
||||
dict(
|
||||
resource=dict(kind="Secret", type="my-type", name="", data=dict(one=""),),
|
||||
resource=dict(
|
||||
kind="Secret",
|
||||
type="my-type",
|
||||
name="",
|
||||
data=dict(one=""),
|
||||
),
|
||||
expected=b'{"data":{"one":""},"kind":"Secret","name":"","type":"my-type"}',
|
||||
),
|
||||
dict(
|
||||
@@ -52,7 +76,11 @@ tests = [
|
||||
kind="Secret",
|
||||
type="my-type",
|
||||
name="",
|
||||
data=dict(two="Mg==", one="", three="Mw==",),
|
||||
data=dict(
|
||||
two="Mg==",
|
||||
one="",
|
||||
three="Mw==",
|
||||
),
|
||||
),
|
||||
expected=b'{"data":{"one":"","three":"Mw==","two":"Mg=="},"kind":"Secret","name":"","type":"my-type"}',
|
||||
),
|
||||
|
||||
4
tox.ini
4
tox.ini
@@ -21,7 +21,7 @@ commands = collection_prep_add_docs -p .
|
||||
|
||||
[testenv:black]
|
||||
deps =
|
||||
black==19.10b0
|
||||
black >= 22.0, < 23.0
|
||||
|
||||
commands =
|
||||
black -v --check --diff {toxinidir}/plugins {toxinidir}/tests
|
||||
@@ -30,7 +30,7 @@ commands =
|
||||
deps =
|
||||
yamllint
|
||||
flake8
|
||||
black==19.10b0
|
||||
{[testenv:black]deps}
|
||||
|
||||
commands =
|
||||
black -v --check --diff {toxinidir}/plugins {toxinidir}/tests
|
||||
|
||||
Reference in New Issue
Block a user