"""
Manage kubernetes resources as salt states
==========================================
NOTE: This module requires the proper pillar values set. See
salt.modules.kubernetesmod for more information.
.. warning::
Configuration options will change in 2019.2.0.
The kubernetes module is used to manage different kubernetes resources.
.. code-block:: yaml
my-nginx:
kubernetes.deployment_present:
- namespace: default
metadata:
app: frontend
spec:
replicas: 1
template:
metadata:
labels:
run: my-nginx
spec:
containers:
- name: my-nginx
image: nginx
ports:
- containerPort: 80
my-mariadb:
kubernetes.deployment_absent:
- namespace: default
# kubernetes deployment as specified inside of
# a file containing the definition of the the
# deployment using the official kubernetes format
redis-master-deployment:
kubernetes.deployment_present:
- name: redis-master
- source: salt://k8s/redis-master-deployment.yml
require:
- pip: kubernetes-python-module
# kubernetes service as specified inside of
# a file containing the definition of the the
# service using the official kubernetes format
redis-master-service:
kubernetes.service_present:
- name: redis-master
- source: salt://k8s/redis-master-service.yml
require:
- kubernetes.deployment_present: redis-master
# kubernetes deployment as specified inside of
# a file containing the definition of the the
# deployment using the official kubernetes format
# plus some jinja directives
nginx-source-template:
kubernetes.deployment_present:
- source: salt://k8s/nginx.yml.jinja
- template: jinja
require:
- pip: kubernetes-python-module
# kubernetes deployment using a template with custom template_context variables
nginx-template-with-template_context:
kubernetes.deployment_present:
- name: nginx-template
- source: salt://k8s/nginx-template.yml.jinja
- template: jinja
- template_context:
replicas: 3
nginx_version: 1.19
environment: production
app_label: frontend
# kubernetes secret with template_context variables
cert-secret-with-template_context:
kubernetes.secret_present:
- name: tls-cert
- source: salt://k8s/tls-cert.yml.jinja
- template: jinja
- template_context:
cert_name: myapp.example.com
cert_data: |
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
- secret_type: kubernetes.io/tls
# Kubernetes secret
k8s-secret:
kubernetes.secret_present:
- name: top-secret
data:
key1: value1
key2: value2
key3: value3
.. versionadded:: 2017.7.0
"""
import copy
import logging
from salt.exceptions import CommandExecutionError
from salt.utils.dictdiffer import RecursiveDictDiffer
log = logging.getLogger(__name__)
__virtualname__ = "kubernetes"
[docs]
def __virtual__():
"""
Only load if the kubernetes module is available in __salt__
"""
if "kubernetes.ping" in __salt__:
return True
return (False, "kubernetes module could not be loaded")
def _error(ret, err_msg):
"""
Helper function to propagate errors to
the end user.
"""
ret["result"] = False
ret["comment"] = err_msg
return ret
def _changes(old, new):
"""
Return a changes dict using RecursiveDictDiffer for concise reporting.
"""
diff = RecursiveDictDiffer(old, new, ignore_missing_keys=False)
return {"old": diff.old_values, "new": diff.new_values}
[docs]
def deployment_absent(name, namespace="default", wait=False, timeout=60, **kwargs):
"""
Ensures that the named deployment is absent from the given namespace.
name
The name of the deployment
namespace
The name of the namespace
wait
.. versionadded:: 2.0.0
If set to True, the function will wait until the deployment is deleted.
timeout
.. versionadded:: 2.0.0
The time in seconds to wait for the deployment to
Example:
.. code-block:: yaml
my-nginx:
kubernetes.deployment_absent:
- namespace: default
"""
ret = {"name": name, "changes": {}, "result": False, "comment": ""}
try:
deployment = __salt__["kubernetes.show_deployment"](name, namespace, **kwargs)
if deployment is None:
ret["result"] = True
ret["comment"] = "The deployment does not exist"
return ret
if __opts__["test"]:
ret["result"] = None
ret["comment"] = "The deployment is going to be deleted"
ret["changes"] = {
"old": "present",
"new": "absent",
}
return ret
__salt__["kubernetes.delete_deployment"](
name, namespace, wait=wait, timeout=timeout, **kwargs
)
ret["result"] = True
ret["changes"] = {"old": "present", "new": "absent"}
ret["comment"] = f"Deployment {name} deleted"
except CommandExecutionError as err:
log.error(str(err), exc_info_on_loglevel=logging.DEBUG)
ret["result"] = False
ret["comment"] = str(err)
ret["changes"] = {}
return ret
[docs]
def deployment_present(
name,
namespace="default",
metadata=None,
spec=None,
source="",
template="",
template_context=None,
wait=False,
timeout=60,
**kwargs,
):
"""
Ensures that the named deployment is present inside of the specified
namespace with the given metadata and spec.
If the deployment exists, it will be patched with the desired state.
name
The name of the deployment.
namespace
The namespace holding the deployment. The 'default' one is going to be
used unless a different one is specified.
metadata
The metadata of the deployment object.
spec
The spec of the deployment object.
source
A file containing the definition of the deployment (metadata and
spec) in the official kubernetes format.
template
Template engine to be used to render the source file.
template_context
.. versionadded:: 2.0.0
Variables to be passed into the template.
wait
.. versionadded:: 2.0.0
If set to True, the function will wait until the deployment is ready.
timeout
.. versionadded:: 2.0.0
The time in seconds to wait for the deployment to be ready.
Example:
.. code-block:: yaml
my-nginx:
kubernetes.deployment_present:
- namespace: default
- metadata:
app: frontend
- spec:
replicas: 1
template:
metadata:
labels:
run: my-nginx
spec:
containers:
- name: my-nginx
image: nginx
ports:
- containerPort: 80
"""
ret = {"name": name, "changes": {}, "result": False, "comment": ""}
if (metadata or spec) and source:
return _error(ret, "'source' cannot be used in combination with 'metadata' or 'spec'")
if metadata is None:
metadata = {}
if spec is None:
spec = {}
try:
deployment = __salt__["kubernetes.show_deployment"](name, namespace, **kwargs)
if deployment is None:
try:
res = __salt__["kubernetes.create_deployment"](
name=name,
namespace=namespace,
metadata=metadata,
spec=spec,
source=source,
template=template,
saltenv=__env__,
template_context=template_context,
dry_run=bool(__opts__["test"]),
wait=wait if not __opts__["test"] else False,
timeout=timeout,
**kwargs,
)
except CommandExecutionError as err:
if not __opts__["test"]:
raise
ret["result"] = None
ret["comment"] = (
"The deployment is going to be created. "
f"Dry run failed, possibly due to dependencies not created yet: {err}"
)
return ret
ret["changes"] = {"old": {}, "new": res}
if __opts__["test"]:
ret["result"] = None
ret["comment"] = "The deployment is going to be created"
else:
ret["result"] = True
ret["comment"] = "Deployment created"
return ret
# Deployment exists — build the patch object
if source:
patch_kwargs = {
"source": source,
"template": template,
"template_context": template_context,
}
else:
patch_obj = {}
if metadata:
patch_obj["metadata"] = metadata
if spec:
patch_obj["spec"] = spec
patch_kwargs = {"patch": patch_obj}
try:
res = __salt__["kubernetes.patch_deployment"](
name,
namespace,
dry_run=bool(__opts__["test"]),
wait=wait,
timeout=timeout,
**patch_kwargs,
**kwargs,
)
except CommandExecutionError as err:
if not __opts__["test"]:
raise
ret["result"] = None
ret["comment"] = (
"The deployment is going to be updated. "
f"Dry run failed, possibly due to dependencies not created yet: {err}"
)
return ret
if res == deployment:
ret["result"] = True
ret["comment"] = "The deployment is already in the desired state"
return ret
ret["changes"] = _changes(deployment, res)
if __opts__["test"]:
ret["result"] = None
ret["comment"] = "The deployment is going to be updated"
else:
ret["result"] = True
ret["comment"] = "Deployment updated"
except CommandExecutionError as err:
log.error(str(err), exc_info_on_loglevel=logging.DEBUG)
ret["result"] = False
ret["comment"] = str(err)
ret["changes"] = {}
return ret
[docs]
def service_present(
name,
namespace="default",
metadata=None,
spec=None,
source="",
template="",
template_context=None,
wait=False,
timeout=60,
**kwargs,
):
"""
Ensures that the named service is present inside of the specified namespace
with the given metadata and spec.
If the service exists, it will be patched with the desired state.
name
The name of the service.
namespace
The namespace holding the service. The 'default' one is going to be
used unless a different one is specified.
metadata
The metadata of the service object.
spec
The spec of the service object.
source
A file containing the definition of the service (metadata and
spec) in the official kubernetes format.
template
Template engine to be used to render the source file.
template_context
.. versionadded:: 2.0.0
Variables to be passed into the template.
wait
.. versionadded:: 2.0.0
If set to True, the function will wait until the service is created.
timeout
.. versionadded:: 2.0.0
The time in seconds to wait for the service to be created.
Example:
.. code-block:: yaml
my-service:
kubernetes.service_present:
- namespace: default
- metadata:
app: frontend
- spec:
ports:
- port: 80
targetPort: 80
protocol: TCP
selector:
app: frontend
"""
ret = {"name": name, "changes": {}, "result": False, "comment": ""}
if (metadata or spec) and source:
return _error(ret, "'source' cannot be used in combination with 'metadata' or 'spec'")
if metadata is None:
metadata = {}
if spec is None:
spec = {}
try:
service = __salt__["kubernetes.show_service"](name, namespace, **kwargs)
if service is None:
try:
res = __salt__["kubernetes.create_service"](
name=name,
namespace=namespace,
metadata=metadata,
spec=spec,
source=source,
template=template,
saltenv=__env__,
template_context=template_context,
dry_run=bool(__opts__["test"]),
wait=wait if not __opts__["test"] else False,
timeout=timeout,
**kwargs,
)
except CommandExecutionError as err:
if not __opts__["test"]:
raise
ret["result"] = None
ret["comment"] = (
"The service is going to be created. "
f"Dry run failed, possibly due to dependencies not created yet: {err}"
)
return ret
ret["changes"] = {"old": {}, "new": res}
if __opts__["test"]:
ret["result"] = None
ret["comment"] = "The service is going to be created"
else:
ret["result"] = True
ret["comment"] = "Service created"
return ret
# Service exists — build the patch object
if source:
patch_kwargs = {
"source": source,
"template": template,
"template_context": template_context,
}
else:
patch_obj = {}
if metadata:
patch_obj["metadata"] = metadata
if spec:
patch_obj["spec"] = spec
patch_kwargs = {"patch": patch_obj}
try:
res = __salt__["kubernetes.patch_service"](
name,
namespace,
dry_run=bool(__opts__["test"]),
wait=wait,
timeout=timeout,
**patch_kwargs,
**kwargs,
)
except CommandExecutionError as err:
if not __opts__["test"]:
raise
ret["result"] = None
ret["comment"] = (
"The service is going to be updated. "
f"Dry run failed, possibly due to dependencies not created yet: {err}"
)
return ret
if res == service:
ret["result"] = True
ret["comment"] = "The service is already in the desired state"
return ret
ret["changes"] = _changes(service, res)
if __opts__["test"]:
ret["result"] = None
ret["comment"] = "The service is going to be updated"
else:
ret["result"] = True
ret["comment"] = "Service updated"
except CommandExecutionError as err:
log.error(str(err), exc_info_on_loglevel=logging.DEBUG)
ret["result"] = False
ret["comment"] = str(err)
ret["changes"] = {}
return ret
[docs]
def service_absent(name, namespace="default", wait=False, timeout=60, **kwargs):
"""
Ensures that the named service is absent from the given namespace.
name
The name of the service
namespace
The name of the namespace
wait
.. versionadded:: 2.0.0
If set to True, the function will wait until the service is deleted.
timeout
.. versionadded:: 2.0.0
The time in seconds to wait for the service to be deleted.
Example:
.. code-block:: yaml
my_service:
kubernetes.service_absent:
- namespace: default
"""
ret = {"name": name, "changes": {}, "result": False, "comment": ""}
try:
service = __salt__["kubernetes.show_service"](name, namespace, **kwargs)
if service is None:
ret["result"] = True
ret["comment"] = "The service does not exist"
return ret
if __opts__["test"]:
ret["comment"] = "The service is going to be deleted"
ret["result"] = None
ret["changes"] = {"old": "present", "new": "absent"}
return ret
__salt__["kubernetes.delete_service"](name, namespace, wait=wait, timeout=timeout, **kwargs)
ret["result"] = True
ret["changes"] = {"old": "present", "new": "absent"}
ret["comment"] = f"Service {name} deleted"
except CommandExecutionError as err:
log.error(str(err), exc_info_on_loglevel=logging.DEBUG)
ret["result"] = False
ret["comment"] = str(err)
ret["changes"] = {}
return ret
[docs]
def namespace_absent(name, wait=False, timeout=60, **kwargs):
"""
Ensures that the named namespace is absent.
name
The name of the namespace
wait
.. versionadded:: 2.0.0
If set to True, the function will wait until the namespace is deleted.
timeout
.. versionadded:: 2.0.0
The time in seconds to wait for the namespace to be deleted.
Example:
.. code-block:: yaml
my_namespace:
kubernetes.namespace_absent:
- namespace: default
"""
ret = {"name": name, "changes": {}, "result": False, "comment": ""}
try:
namespace = __salt__["kubernetes.show_namespace"](name, **kwargs)
if namespace is None:
ret["result"] = True
ret["comment"] = "The namespace does not exist"
return ret
if __opts__["test"]:
ret["comment"] = "The namespace is going to be deleted"
ret["result"] = None
ret["changes"] = {"old": "present", "new": "absent"}
return ret
__salt__["kubernetes.delete_namespace"](name, wait=wait, timeout=timeout, **kwargs)
ret["result"] = True
ret["changes"] = {"old": "present", "new": "absent"}
ret["comment"] = f"Namespace {name} deleted"
except CommandExecutionError as err:
log.error(str(err), exc_info_on_loglevel=logging.DEBUG)
ret["result"] = False
ret["comment"] = str(err)
ret["changes"] = {}
return ret
[docs]
def namespace_present(name, **kwargs):
"""
Ensures that the named namespace is present.
name
The name of the namespace.
Example:
.. code-block:: yaml
my_namespace:
kubernetes.namespace_present:
- namespace: default
"""
ret = {"name": name, "changes": {}, "result": False, "comment": ""}
try:
namespace = __salt__["kubernetes.show_namespace"](name, **kwargs)
if namespace is None:
if __opts__["test"]:
ret["result"] = None
ret["comment"] = "The namespace is going to be created"
ret["changes"] = {"old": {}, "new": {"metadata": {"name": name}}}
return ret
res = __salt__["kubernetes.create_namespace"](name, **kwargs)
ret["result"] = True
ret["changes"] = {"old": {}, "new": res}
else:
ret["result"] = True
ret["comment"] = "The namespace already exists"
except CommandExecutionError as err:
log.error(str(err), exc_info_on_loglevel=logging.DEBUG)
ret["result"] = False
ret["comment"] = str(err)
ret["changes"] = {}
return ret
[docs]
def secret_absent(name, namespace="default", wait=False, timeout=60, **kwargs):
"""
Ensures that the named secret is absent from the given namespace.
name
The name of the secret
namespace
The name of the namespace
wait
.. versionadded:: 2.0.0
If set to True, the function will wait until the secret is deleted.
timeout
.. versionadded:: 2.0.0
The time in seconds to wait for the secret to be deleted.
Example:
.. code-block:: yaml
my_secret:
kubernetes.secret_absent:
- namespace: default
"""
ret = {"name": name, "changes": {}, "result": False, "comment": ""}
try:
secret = __salt__["kubernetes.show_secret"](name, namespace, **kwargs)
if secret is None:
ret["result"] = True
ret["comment"] = "The secret does not exist"
return ret
if __opts__["test"]:
ret["comment"] = "The secret is going to be deleted"
ret["result"] = None
ret["changes"] = {"old": "present", "new": "absent"}
return ret
__salt__["kubernetes.delete_secret"](name, namespace, wait=wait, timeout=timeout, **kwargs)
ret["result"] = True
ret["changes"] = {"old": "present", "new": "absent"}
ret["comment"] = f"Secret {name} deleted"
except CommandExecutionError as err:
log.error(str(err), exc_info_on_loglevel=logging.DEBUG)
ret["result"] = False
ret["comment"] = str(err)
ret["changes"] = {}
return ret
[docs]
def secret_present(
name,
namespace="default",
data=None,
source=None,
template=None,
template_context=None,
secret_type=None,
metadata=None,
wait=False,
timeout=60,
**kwargs,
):
"""
Ensures that the named secret is present inside of the specified namespace
with the given data.
If the secret exists, it will be patched with the desired state.
name
The name of the secret.
namespace
The namespace holding the secret. The 'default' one is going to be
used unless a different one is specified.
data
The dictionary holding the secrets.
source
A file containing the data of the secret in plain format.
template
Template engine to be used to render the source file.
template_context
.. versionadded:: 2.0.0
Variables to be passed into the template.
secret_type
.. versionadded:: 2.0.0
The type of secret to create. Defaults to ``Opaque``.
metadata
.. versionadded:: 2.0.0
The metadata to include in the secret (annotations, labels, etc).
wait
.. versionadded:: 2.0.0
If set to True, the function will wait until the secret is created.
timeout
.. versionadded:: 2.0.0
The time in seconds to wait for the secret to be created.
Example:
.. code-block:: yaml
my_secret:
kubernetes.secret_present:
- namespace: default
- data:
key1: value1
key2: value2
key3: value3
"""
ret = {"name": name, "changes": {}, "result": False, "comment": ""}
if data and source:
return _error(ret, "'source' cannot be used in combination with 'data'")
if metadata is None:
metadata = {}
try:
secret = __salt__["kubernetes.show_secret"](name, namespace, **kwargs)
if secret is None:
if data is None:
data = {}
try:
res = __salt__["kubernetes.create_secret"](
name=name,
namespace=namespace,
data=data,
source=source,
template=template,
saltenv=__env__,
template_context=template_context,
secret_type=secret_type,
metadata=metadata,
dry_run=bool(__opts__["test"]),
wait=wait if not __opts__["test"] else False,
timeout=timeout,
**kwargs,
)
except CommandExecutionError as err:
if not __opts__["test"]:
raise
ret["result"] = None
ret["comment"] = (
"The secret is going to be created. "
f"Dry run failed, possibly due to dependencies not created yet: {err}"
)
return ret
ret["changes"] = {
"old": {},
"new": {"data": list(res.get("data") or [])},
}
if __opts__["test"]:
ret["result"] = None
ret["comment"] = "The secret is going to be created"
else:
ret["result"] = True
ret["comment"] = "Secret created"
return ret
# Secret exists — build the patch object
if source:
patch_kwargs = {
"source": source,
"template": template,
"template_context": template_context,
}
else:
patch_obj = {}
if metadata:
patch_obj["metadata"] = metadata
if data:
patch_obj["data"] = data
if secret_type:
patch_obj["type"] = secret_type
patch_kwargs = {"patch": patch_obj}
try:
res = __salt__["kubernetes.patch_secret"](
name,
namespace,
dry_run=bool(__opts__["test"]),
wait=wait,
timeout=timeout,
**patch_kwargs,
**kwargs,
)
except CommandExecutionError as err:
if not __opts__["test"]:
raise
ret["result"] = None
ret["comment"] = (
"The secret is going to be updated. "
f"Dry run failed, possibly due to dependencies not created yet: {err}"
)
return ret
if res == secret:
ret["result"] = True
ret["comment"] = "The secret is already in the desired state"
return ret
ret["changes"] = {
"old": {"data": list(secret.get("data") or [])},
"new": {"data": list(res.get("data") or [])},
}
if __opts__["test"]:
ret["result"] = None
ret["comment"] = "The secret is going to be updated"
else:
ret["result"] = True
ret["comment"] = "Secret updated"
except CommandExecutionError as err:
log.error(str(err), exc_info_on_loglevel=logging.DEBUG)
ret["result"] = False
ret["comment"] = str(err)
ret["changes"] = {}
return ret
[docs]
def configmap_absent(name, namespace="default", wait=False, timeout=60, **kwargs):
"""
Ensures that the named configmap is absent from the given namespace.
name
The name of the configmap
namespace
The namespace holding the configmap. The 'default' one is going to be
used unless a different one is specified.
wait
.. versionadded:: 2.0.0
If set to True, the function will wait until the configmap is deleted.
timeout
.. versionadded:: 2.0.0
The time in seconds to wait for the configmap to be deleted.
Example:
.. code-block:: yaml
my_configmap:
kubernetes.configmap_absent:
- namespace: default
"""
ret = {"name": name, "changes": {}, "result": False, "comment": ""}
try:
configmap = __salt__["kubernetes.show_configmap"](name, namespace, **kwargs)
if configmap is None:
ret["result"] = True
ret["comment"] = "The configmap does not exist"
return ret
if __opts__["test"]:
ret["comment"] = "The configmap is going to be deleted"
ret["result"] = None
ret["changes"] = {"old": "present", "new": "absent"}
return ret
__salt__["kubernetes.delete_configmap"](
name, namespace, wait=wait, timeout=timeout, **kwargs
)
ret["result"] = True
ret["changes"] = {"old": "present", "new": "absent"}
ret["comment"] = f"ConfigMap {name} deleted"
except CommandExecutionError as err:
log.error(str(err), exc_info_on_loglevel=logging.DEBUG)
ret["result"] = False
ret["comment"] = str(err)
ret["changes"] = {}
return ret
[docs]
def configmap_present(
name,
namespace="default",
data=None,
source=None,
template=None,
template_context=None,
wait=False,
timeout=60,
**kwargs,
):
"""
Ensures that the named configmap is present inside of the specified namespace
with the given data.
If the configmap exists, it will be patched with the desired state.
name
The name of the configmap.
namespace
The namespace holding the configmap. The 'default' one is going to be
used unless a different one is specified.
data
The dictionary holding the configmaps.
source
A file containing the data of the configmap in plain format.
.. versionchanged:: 2.0.0
The configmap definition must be a proper spec with the configmap data in
the ``data`` key. In previous versions, the rendered output was used as the
data directly.
template
Template engine to be used to render the source file.
template_context
.. versionadded:: 2.0.0
Variables to be passed into the template.
wait
.. versionadded:: 2.0.0
If set to True, the function will wait until the configmap is created.
timeout
.. versionadded:: 2.0.0
The time in seconds to wait for the configmap to be created.
Example:
.. code-block:: yaml
my_configmap:
kubernetes.configmap_present:
- namespace: default
- data:
key1: value1
key2: value2
key3: value3
"""
ret = {"name": name, "changes": {}, "result": False, "comment": ""}
if data and source:
return _error(ret, "'source' cannot be used in combination with 'data'")
elif data is None:
data = {}
try:
configmap = __salt__["kubernetes.show_configmap"](name, namespace, **kwargs)
if configmap is None:
try:
res = __salt__["kubernetes.create_configmap"](
name=name,
namespace=namespace,
data=data,
source=source,
template=template,
saltenv=__env__,
template_context=template_context,
dry_run=bool(__opts__["test"]),
wait=wait if not __opts__["test"] else False,
timeout=timeout,
**kwargs,
)
except CommandExecutionError as err:
if not __opts__["test"]:
raise
ret["result"] = None
ret["comment"] = (
"The configmap is going to be created. "
f"Dry run failed, possibly due to dependencies not created yet: {err}"
)
return ret
ret["changes"] = {"old": {}, "new": res}
if __opts__["test"]:
ret["result"] = None
ret["comment"] = "The configmap is going to be created"
else:
ret["result"] = True
ret["comment"] = "ConfigMap created"
return ret
# ConfigMap exists — build the patch object
if source:
patch_kwargs = {
"source": source,
"template": template,
"template_context": template_context,
}
else:
patch_obj = {}
if data:
patch_obj["data"] = data
patch_kwargs = {"patch": patch_obj}
try:
res = __salt__["kubernetes.patch_configmap"](
name,
namespace,
dry_run=bool(__opts__["test"]),
wait=wait,
timeout=timeout,
**patch_kwargs,
**kwargs,
)
except CommandExecutionError as err:
if not __opts__["test"]:
raise
ret["result"] = None
ret["comment"] = (
"The configmap is going to be updated. "
f"Dry run failed, possibly due to dependencies not created yet: {err}"
)
return ret
if res == configmap:
ret["result"] = True
ret["comment"] = "The configmap is already in the desired state"
return ret
ret["changes"] = _changes(configmap, res)
if __opts__["test"]:
ret["result"] = None
ret["comment"] = "The configmap is going to be updated"
else:
ret["result"] = True
ret["comment"] = "ConfigMap updated"
except CommandExecutionError as err:
ret["result"] = False
ret["comment"] = str(err)
ret["changes"] = {}
return ret
[docs]
def pod_absent(name, namespace="default", wait=False, timeout=60, **kwargs):
"""
Ensures that the named pod is absent from the given namespace.
name
The name of the pod
namespace
The name of the namespace
wait
.. versionadded:: 2.0.0
If set to True, the function will wait until the pod is deleted.
timeout
.. versionadded:: 2.0.0
The time in seconds to wait for the pod to be deleted.
Example:
.. code-block:: yaml
my_pod:
kubernetes.pod_absent:
- namespace: default
"""
ret = {"name": name, "changes": {}, "result": False, "comment": ""}
try:
pod = __salt__["kubernetes.show_pod"](name, namespace, **kwargs)
if pod is None:
ret["result"] = True
ret["comment"] = "The pod does not exist"
return ret
if __opts__["test"]:
ret["comment"] = "The pod is going to be deleted"
ret["result"] = None
ret["changes"] = {"old": "present", "new": "absent"}
return ret
__salt__["kubernetes.delete_pod"](name, namespace, wait=wait, timeout=timeout, **kwargs)
ret["result"] = True
ret["changes"] = {"old": "present", "new": "absent"}
ret["comment"] = f"Pod {name} deleted"
except CommandExecutionError as err:
log.error(str(err), exc_info_on_loglevel=logging.DEBUG)
ret["result"] = False
ret["comment"] = str(err)
ret["changes"] = {}
return ret
[docs]
def pod_present(
name,
namespace="default",
metadata=None,
spec=None,
source="",
template="",
template_context=None,
wait=False,
timeout=60,
**kwargs,
):
"""
Ensures that the named pod is present inside of the specified
namespace with the given metadata and spec.
.. note::
Pods are immutable once created. If the pod already exists, this state
will report success without changes. To update a pod, first remove it
with ``pod_absent`` and then recreate it. For managed workloads,
consider using ``deployment_present`` instead.
name
The name of the pod.
namespace
The namespace holding the pod. The 'default' one is going to be
used unless a different one is specified.
metadata
The metadata of the pod object.
spec
The spec of the pod object.
source
A file containing the definition of the pod (metadata and
spec) in the official kubernetes format.
template
Template engine to be used to render the source file.
template_context
.. versionadded:: 2.0.0
Variables to be passed into the template.
wait
.. versionadded:: 2.0.0
If set to True, the function will wait until the pod is created.
timeout
.. versionadded:: 2.0.0
The time in seconds to wait for the pod to be created.
Example:
.. code-block:: yaml
my_pod:
kubernetes.pod_present:
- namespace: default
- metadata:
app: frontend
- spec:
containers:
- name: my-nginx
image: nginx
ports:
- containerPort: 80
"""
ret = {"name": name, "changes": {}, "result": False, "comment": ""}
if (metadata or spec) and source:
return _error(ret, "'source' cannot be used in combination with 'metadata' or 'spec'")
if metadata is None:
metadata = {}
if spec is None:
spec = {}
try:
pod = __salt__["kubernetes.show_pod"](name, namespace, **kwargs)
if pod is None:
if __opts__["test"]:
ret["result"] = None
ret["comment"] = "The pod is going to be created"
return ret
res = __salt__["kubernetes.create_pod"](
name=name,
namespace=namespace,
metadata=metadata,
spec=spec,
source=source,
template=template,
saltenv=__env__,
template_context=template_context,
wait=wait,
timeout=timeout,
**kwargs,
)
ret["result"] = True
ret["changes"] = {"old": {}, "new": res}
ret["comment"] = "Pod created"
return ret
# Pod already exists — pods are immutable, report as already present
ret["result"] = True
ret["comment"] = (
"The pod already exists. Pods are immutable once created. "
"To update, remove with pod_absent first, then recreate. "
"For managed workloads, consider using deployment_present instead."
)
except CommandExecutionError as err:
log.error(str(err), exc_info_on_loglevel=logging.DEBUG)
ret["result"] = False
ret["comment"] = str(err)
ret["changes"] = {}
return ret
[docs]
def node_label_absent(name, node, **kwargs):
"""
Ensures that the named label is absent from the node.
name
The name of the label
node
The name of the node
Example:
.. code-block:: yaml
my_label:
kubernetes.node_label_absent:
- node: node_name
"""
ret = {"name": name, "changes": {}, "result": False, "comment": ""}
try:
labels = __salt__["kubernetes.node_labels"](node, **kwargs)
if name not in labels:
ret["result"] = True
ret["comment"] = "The label does not exist"
return ret
if __opts__["test"]:
ret["comment"] = "The label is going to be deleted"
ret["result"] = None
ret["changes"] = {"old": "present", "new": "absent"}
return ret
__salt__["kubernetes.node_remove_label"](node_name=node, label_name=name, **kwargs)
ret["result"] = True
ret["changes"] = {"old": "present", "new": "absent"}
ret["comment"] = "Label removed from node"
except CommandExecutionError as err:
log.error(str(err), exc_info_on_loglevel=logging.DEBUG)
ret["result"] = False
ret["comment"] = str(err)
ret["changes"] = {}
return ret
[docs]
def node_label_folder_absent(name, node, **kwargs):
"""
Ensures the label folder doesn't exist on the specified node.
name
The name of label folder
node
The name of the node
Example:
.. code-block:: yaml
my_label_folder:
kubernetes.node_label_folder_absent:
- node: node_name
"""
ret = {"name": name, "changes": {}, "result": False, "comment": ""}
try:
labels = __salt__["kubernetes.node_labels"](node, **kwargs)
folder = name.strip("/") + "/"
labels_to_drop = []
new_labels = []
for label in labels:
if label.startswith(folder):
labels_to_drop.append(label)
else:
new_labels.append(label)
if not labels_to_drop:
ret["result"] = True
ret["comment"] = "The label folder does not exist"
return ret
if __opts__["test"]:
ret["comment"] = "The label folder is going to be deleted"
ret["result"] = None
ret["changes"] = {"old": list(labels), "new": new_labels}
return ret
for label in labels_to_drop:
__salt__["kubernetes.node_remove_label"](node_name=node, label_name=label, **kwargs)
ret["result"] = True
ret["changes"] = {"old": list(labels), "new": new_labels}
ret["comment"] = "Label folder removed from node"
except CommandExecutionError as err:
log.error(str(err), exc_info_on_loglevel=logging.DEBUG)
ret["result"] = False
ret["comment"] = str(err)
ret["changes"] = {}
return ret
[docs]
def node_label_present(name, node, value, **kwargs):
"""
Ensures that the named label is set on the named node
with the given value.
If the label exists it will be replaced.
name
The name of the label.
value
Value of the label.
node
Node to change.
Example:
.. code-block:: yaml
my_label:
kubernetes.node_label_present:
- node: node_name
- value: my_value
"""
ret = {"name": name, "changes": {}, "result": False, "comment": ""}
try:
labels = __salt__["kubernetes.node_labels"](node, **kwargs)
if name not in labels:
if __opts__["test"]:
ret["result"] = None
ret["comment"] = "The label is going to be set"
old_labels = copy.copy(labels)
new_labels = copy.copy(labels)
new_labels[name] = value
ret["changes"] = {"old": old_labels, "new": new_labels}
return ret
__salt__["kubernetes.node_add_label"](
label_name=name, label_value=value, node_name=node, **kwargs
)
elif labels[name] == value:
ret["result"] = True
ret["comment"] = "The label is already set and has the specified value"
return ret
else:
if __opts__["test"]:
ret["result"] = None
ret["comment"] = "The label is going to be updated"
old_labels = copy.copy(labels)
new_labels = copy.copy(labels)
new_labels[name] = value
ret["changes"] = {"old": old_labels, "new": new_labels}
return ret
ret["comment"] = "The label is already set, changing the value"
__salt__["kubernetes.node_add_label"](
node_name=node, label_name=name, label_value=value, **kwargs
)
old_labels = copy.copy(labels)
labels[name] = value
ret["changes"] = {"old": old_labels, "new": labels}
ret["result"] = True
except CommandExecutionError as err:
log.error(str(err), exc_info_on_loglevel=logging.DEBUG)
ret["result"] = False
ret["comment"] = str(err)
ret["changes"] = {}
return ret