mirror of
https://github.com/ansible-collections/kubernetes.core.git
synced 2026-07-28 10:24:45 +00:00
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
@@ -87,7 +87,7 @@ jobs:
|
|||||||
# The 3.3.0 release of molecule introduced a breaking change. See
|
# The 3.3.0 release of molecule introduced a breaking change. See
|
||||||
# https://github.com/ansible-community/molecule/issues/3083
|
# https://github.com/ansible-community/molecule/issues/3083
|
||||||
- name: Install molecule and openshift dependencies
|
- name: Install molecule and openshift dependencies
|
||||||
run: pip install ansible "molecule<3.3.0" yamllint openshift flake8
|
run: pip install ansible "molecule<3.3.0" yamllint openshift flake8 jsonpatch
|
||||||
|
|
||||||
# The latest release doesn't work with Molecule currently.
|
# The latest release doesn't work with Molecule currently.
|
||||||
# See: https://github.com/ansible-community/molecule/issues/2757
|
# See: https://github.com/ansible-community/molecule/issues/2757
|
||||||
|
|||||||
3
changelogs/fragments/83-k8s-fix-merge_type-json.yaml
Normal file
3
changelogs/fragments/83-k8s-fix-merge_type-json.yaml
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
---
|
||||||
|
bugfixes:
|
||||||
|
- k8s - fix merge_type option when set to json (https://github.com/ansible-collections/kubernetes.core/issues/54).
|
||||||
@@ -133,6 +133,14 @@
|
|||||||
tags:
|
tags:
|
||||||
- always
|
- always
|
||||||
|
|
||||||
|
- name: Include merge_type.yml
|
||||||
|
include_tasks:
|
||||||
|
file: tasks/merge_type.yml
|
||||||
|
apply:
|
||||||
|
tags: [ merge_type, k8s ]
|
||||||
|
tags:
|
||||||
|
- always
|
||||||
|
|
||||||
roles:
|
roles:
|
||||||
- role: helm
|
- role: helm
|
||||||
tags:
|
tags:
|
||||||
|
|||||||
252
molecule/default/tasks/merge_type.yml
Normal file
252
molecule/default/tasks/merge_type.yml
Normal file
@@ -0,0 +1,252 @@
|
|||||||
|
- block:
|
||||||
|
- name: Define common facts
|
||||||
|
set_fact:
|
||||||
|
k8s_patch_namespace: "patch"
|
||||||
|
k8s_strategic_merge: "strategic-merge"
|
||||||
|
k8s_merge: "json-merge"
|
||||||
|
k8s_json: "json-patch"
|
||||||
|
|
||||||
|
- name: Ensure the namespace exist
|
||||||
|
kubernetes.core.k8s:
|
||||||
|
kind: namespace
|
||||||
|
name: "{{ k8s_patch_namespace }}"
|
||||||
|
|
||||||
|
|
||||||
|
# Strategic merge
|
||||||
|
- name: create a simple nginx deployment
|
||||||
|
kubernetes.core.k8s:
|
||||||
|
namespace: "{{ k8s_patch_namespace }}"
|
||||||
|
definition:
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: "{{ k8s_strategic_merge }}"
|
||||||
|
spec:
|
||||||
|
replicas: 2
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: nginx
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: nginx
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: "{{ k8s_strategic_merge }}-ctr"
|
||||||
|
image: nginx
|
||||||
|
tolerations:
|
||||||
|
- effect: NoSchedule
|
||||||
|
key: dedicated
|
||||||
|
value: "test-strategic-merge"
|
||||||
|
|
||||||
|
|
||||||
|
- name: patch service using strategic merge
|
||||||
|
kubernetes.core.k8s:
|
||||||
|
kind: Deployment
|
||||||
|
namespace: "{{ k8s_patch_namespace }}"
|
||||||
|
name: "{{ k8s_strategic_merge }}"
|
||||||
|
definition:
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: "{{ k8s_strategic_merge }}-ctr-2"
|
||||||
|
image: redis
|
||||||
|
register: depl_patch
|
||||||
|
|
||||||
|
- name: validate that resource was patched
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- depl_patch.changed
|
||||||
|
|
||||||
|
- name: describe "{{ k8s_strategic_merge }}" deployment
|
||||||
|
kubernetes.core.k8s_info:
|
||||||
|
kind: Deployment
|
||||||
|
name: "{{ k8s_strategic_merge }}"
|
||||||
|
namespace: "{{ k8s_patch_namespace }}"
|
||||||
|
register: deployment_out
|
||||||
|
|
||||||
|
- name: assert that deployment contains expected images
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- deployment_out.resources[0].spec.template.spec.containers | selectattr('image','equalto','nginx') | list | length == 1
|
||||||
|
- deployment_out.resources[0].spec.template.spec.containers | selectattr('image','equalto','redis') | list | length == 1
|
||||||
|
|
||||||
|
# Json merge
|
||||||
|
- name: create a simple nginx deployment (testing merge patch)
|
||||||
|
kubernetes.core.k8s:
|
||||||
|
namespace: "{{ k8s_patch_namespace }}"
|
||||||
|
definition:
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: "{{ k8s_merge }}"
|
||||||
|
spec:
|
||||||
|
replicas: 2
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: nginx
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: nginx
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: "{{ k8s_merge }}-ctr"
|
||||||
|
image: nginx
|
||||||
|
tolerations:
|
||||||
|
- effect: NoSchedule
|
||||||
|
key: dedicated
|
||||||
|
value: "test-strategic-merge"
|
||||||
|
|
||||||
|
|
||||||
|
- name: patch service using json merge patch
|
||||||
|
kubernetes.core.k8s:
|
||||||
|
kind: Deployment
|
||||||
|
namespace: "{{ k8s_patch_namespace }}"
|
||||||
|
name: "{{ k8s_merge }}"
|
||||||
|
merge_type:
|
||||||
|
- merge
|
||||||
|
definition:
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: "{{ k8s_merge }}-ctr-2"
|
||||||
|
image: python
|
||||||
|
register: merge_patch
|
||||||
|
|
||||||
|
- name: validate that resource was patched
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- merge_patch.changed
|
||||||
|
|
||||||
|
- name: describe "{{ k8s_merge }}" deployment
|
||||||
|
kubernetes.core.k8s_info:
|
||||||
|
kind: Deployment
|
||||||
|
name: "{{ k8s_merge }}"
|
||||||
|
namespace: "{{ k8s_patch_namespace }}"
|
||||||
|
register: merge_out
|
||||||
|
|
||||||
|
- name: assert that deployment contains expected images
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- merge_out.resources[0].spec.template.spec.containers | list | length == 1
|
||||||
|
- merge_out.resources[0].spec.template.spec.containers[0].image == 'python'
|
||||||
|
|
||||||
|
# Json
|
||||||
|
- name: create simple pod
|
||||||
|
kubernetes.core.k8s:
|
||||||
|
namespace: "{{ k8s_patch_namespace }}"
|
||||||
|
definition:
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Pod
|
||||||
|
metadata:
|
||||||
|
name: "{{ k8s_json }}-pod"
|
||||||
|
labels:
|
||||||
|
name: "{{ k8s_json }}-pod"
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- args:
|
||||||
|
- /bin/sh
|
||||||
|
- -c
|
||||||
|
- while true; do echo $(date); sleep 10; done
|
||||||
|
image: python:3.7-alpine
|
||||||
|
imagePullPolicy: Always
|
||||||
|
name: alpine
|
||||||
|
|
||||||
|
- name: Patch pod - update container image
|
||||||
|
kubernetes.core.k8s:
|
||||||
|
kind: Pod
|
||||||
|
namespace: "{{ k8s_patch_namespace }}"
|
||||||
|
name: "{{ k8s_json }}-pod"
|
||||||
|
merge_type:
|
||||||
|
- json
|
||||||
|
definition:
|
||||||
|
- op: replace
|
||||||
|
path: /spec/containers/0/image
|
||||||
|
value: python:3.8-alpine
|
||||||
|
register: pod_patch
|
||||||
|
|
||||||
|
- name: assert that patch was performed
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- pod_patch.changed
|
||||||
|
|
||||||
|
- name: describe Pod after patching
|
||||||
|
kubernetes.core.k8s_info:
|
||||||
|
kind: Pod
|
||||||
|
name: "{{ k8s_json }}-pod"
|
||||||
|
namespace: "{{ k8s_patch_namespace }}"
|
||||||
|
register: describe_pod
|
||||||
|
|
||||||
|
- name: assert that image name has changed
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- describe_pod.resources[0].spec.containers[0].image == 'python:3.8-alpine'
|
||||||
|
|
||||||
|
- name: create a simple nginx deployment
|
||||||
|
kubernetes.core.k8s:
|
||||||
|
namespace: "{{ k8s_patch_namespace }}"
|
||||||
|
definition:
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: "{{ k8s_json }}-depl"
|
||||||
|
labels:
|
||||||
|
name: "{{ k8s_json }}-depl"
|
||||||
|
spec:
|
||||||
|
replicas: 2
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: nginx
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: nginx
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: nginx-container
|
||||||
|
image: nginx
|
||||||
|
args:
|
||||||
|
- /bin/sh
|
||||||
|
- -c
|
||||||
|
- while true; do echo $(date); sleep 10; done
|
||||||
|
|
||||||
|
- name: Patch Nginx deployment command
|
||||||
|
kubernetes.core.k8s:
|
||||||
|
kind: Deployment
|
||||||
|
namespace: "{{ k8s_patch_namespace }}"
|
||||||
|
name: "{{ k8s_json }}-depl"
|
||||||
|
merge_type:
|
||||||
|
- json
|
||||||
|
definition:
|
||||||
|
- op: add
|
||||||
|
path: '/spec/template/spec/containers/0/args/-'
|
||||||
|
value: 'touch /var/log'
|
||||||
|
register: patch_out
|
||||||
|
|
||||||
|
- name: assert that patch succeed
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- patch_out.changed
|
||||||
|
|
||||||
|
- name: describe deployment after patching
|
||||||
|
kubernetes.core.k8s_info:
|
||||||
|
kind: Deployment
|
||||||
|
name: "{{ k8s_json }}-depl"
|
||||||
|
namespace: "{{ k8s_patch_namespace }}"
|
||||||
|
register: describe_depl
|
||||||
|
|
||||||
|
- name: assert that args changed on deployment
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- describe_depl.resources[0].spec.template.spec.containers[0].args | length == 4
|
||||||
|
|
||||||
|
always:
|
||||||
|
- name: Ensure namespace has been deleted
|
||||||
|
kubernetes.core.k8s:
|
||||||
|
kind: namespace
|
||||||
|
name: "{{ k8s_patch_namespace }}"
|
||||||
|
state: absent
|
||||||
|
ignore_errors: yes
|
||||||
@@ -106,6 +106,17 @@ except ImportError as e:
|
|||||||
K8S_IMP_ERR = traceback.format_exc()
|
K8S_IMP_ERR = traceback.format_exc()
|
||||||
|
|
||||||
|
|
||||||
|
JSON_PATCH_IMP_ERR = None
|
||||||
|
try:
|
||||||
|
import jsonpatch
|
||||||
|
HAS_JSON_PATCH = True
|
||||||
|
jsonpatch_import_exception = None
|
||||||
|
except ImportError as e:
|
||||||
|
HAS_JSON_PATCH = False
|
||||||
|
jsonpatch_import_exception = e
|
||||||
|
JSON_PATCH_IMP_ERR = traceback.format_exc()
|
||||||
|
|
||||||
|
|
||||||
def configuration_digest(configuration):
|
def configuration_digest(configuration):
|
||||||
m = hashlib.sha256()
|
m = hashlib.sha256()
|
||||||
for k in AUTH_ARG_MAP:
|
for k in AUTH_ARG_MAP:
|
||||||
@@ -851,12 +862,42 @@ class K8sAnsibleMixin(object):
|
|||||||
self.fail_json(msg=msg, **result)
|
self.fail_json(msg=msg, **result)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
def json_patch(self, existing, definition, merge_type):
|
||||||
|
if merge_type == "json":
|
||||||
|
if not HAS_JSON_PATCH:
|
||||||
|
error = {
|
||||||
|
"msg": missing_required_lib('jsonpatch'),
|
||||||
|
"exception": JSON_PATCH_IMP_ERR,
|
||||||
|
"error": to_native(jsonpatch_import_exception)
|
||||||
|
}
|
||||||
|
return None, error
|
||||||
|
try:
|
||||||
|
patch = jsonpatch.JsonPatch([definition])
|
||||||
|
result_patch = patch.apply(existing.to_dict())
|
||||||
|
return result_patch, None
|
||||||
|
except jsonpatch.InvalidJsonPatch as e:
|
||||||
|
error = {
|
||||||
|
"msg": "invalid json patch",
|
||||||
|
"error": to_native(e)
|
||||||
|
}
|
||||||
|
return None, error
|
||||||
|
except jsonpatch.JsonPatchConflict as e:
|
||||||
|
error = {
|
||||||
|
"msg": "patch could not be applied due to conflict situation",
|
||||||
|
"error": to_native(e)
|
||||||
|
}
|
||||||
|
return None, error
|
||||||
|
return definition, None
|
||||||
|
|
||||||
def patch_resource(self, resource, definition, existing, name, namespace, merge_type=None):
|
def patch_resource(self, resource, definition, existing, name, namespace, merge_type=None):
|
||||||
try:
|
try:
|
||||||
params = dict(name=name, namespace=namespace)
|
params = dict(name=name, namespace=namespace)
|
||||||
if merge_type:
|
if merge_type:
|
||||||
params['content_type'] = 'application/{0}-patch+json'.format(merge_type)
|
params['content_type'] = 'application/{0}-patch+json'.format(merge_type)
|
||||||
k8s_obj = resource.patch(definition, **params).to_dict()
|
patch_data, error = self.json_patch(existing, definition, merge_type)
|
||||||
|
if error is not None:
|
||||||
|
return None, error
|
||||||
|
k8s_obj = resource.patch(patch_data, **params).to_dict()
|
||||||
match, diffs = self.diff_objects(existing.to_dict(), k8s_obj)
|
match, diffs = self.diff_objects(existing.to_dict(), k8s_obj)
|
||||||
error = {}
|
error = {}
|
||||||
return k8s_obj, {}
|
return k8s_obj, {}
|
||||||
|
|||||||
@@ -136,6 +136,7 @@ requirements:
|
|||||||
- "python >= 2.7"
|
- "python >= 2.7"
|
||||||
- "openshift >= 0.6"
|
- "openshift >= 0.6"
|
||||||
- "PyYAML >= 3.11"
|
- "PyYAML >= 3.11"
|
||||||
|
- "jsonpatch"
|
||||||
'''
|
'''
|
||||||
|
|
||||||
EXAMPLES = r'''
|
EXAMPLES = r'''
|
||||||
|
|||||||
@@ -1,2 +1,3 @@
|
|||||||
openshift>=0.6.2
|
openshift>=0.6.2
|
||||||
requests-oauthlib
|
requests-oauthlib
|
||||||
|
jsonpatch
|
||||||
|
|||||||
Reference in New Issue
Block a user