Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extend hidden_fields to allow more complicated field definitions #643

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 15 additions & 39 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,25 +34,16 @@ jobs:
"ansible-version": "stable-2.9"
},
{
"ansible-version": "stable-2.12",
"python-version": "3.7"
},
{
"ansible-version": "stable-2.12",
"python-version": "3.11"
},
{
"ansible-version": "stable-2.13",
"python-version": "3.7"
},
{
"ansible-version": "stable-2.13",
"python-version": "3.11"
},
{
"ansible-version": "stable-2.14",
"python-version": "3.7"
},
{
"ansible-version": "stable-2.14",
"python-version": "3.8"
Expand All @@ -61,10 +52,6 @@ jobs:
"ansible-version": "stable-2.14",
"python-version": "3.11"
},
{
"ansible-version": "stable-2.15",
"python-version": "3.7"
},
{
"ansible-version": "stable-2.15",
"python-version": "3.8"
Expand All @@ -75,19 +62,19 @@ jobs:
},
{
"ansible-version": "milestone",
"python-version": "3.7"
"python-version": "3.8"
},
{
"ansible-version": "milestone",
"python-version": "3.8"
"python-version": "3.9"
},
{
"ansible-version": "devel",
"python-version": "3.7"
"python-version": "3.8"
},
{
"ansible-version": "devel",
"python-version": "3.8"
"python-version": "3.9"
}
]
unit-source:
Expand Down Expand Up @@ -138,13 +125,21 @@ jobs:
"ansible-version": "milestone",
"python-version": "3.8"
},
{
"ansible-version": "milestone",
"python-version": "3.9"
},
{
"ansible-version": "devel",
"python-version": "3.7"
},
{
"ansible-version": "devel",
"python-version": "3.8"
},
{
"ansible-version": "devel",
"python-version": "3.9"
}
]
collection_pre_install: ''
Expand Down Expand Up @@ -187,31 +182,12 @@ jobs:
fail-fast: false
matrix:
ansible-version:
- stable-2.12
- stable-2.15
- milestone
- devel
python-version:
- "3.8"
- "3.9"
exclude:
- ansible-version: stable-2.9
python-version: 3.9
- ansible-version: stable-2.9
python-version: 3.10
- ansible-version: stable-2.9
python-version: 3.11
- ansible-version: stable-2.12
python-version: 3.11
- ansible-version: stable-2.13
python-version: 3.11
- ansible-version: stable-2.14
python-version: 3.8
- ansible-version: stable-2.15
python-version: 3.8
- ansible-version: milestone
python-version: 3.8
- ansible-version: devel
python-version: 3.8
- "3.10"
- "3.11"
enable-turbo-mode:
- true
- false
Expand Down
83 changes: 64 additions & 19 deletions plugins/module_utils/k8s/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -510,23 +510,19 @@ def diff_objects(
result["before"] = diff[0]
result["after"] = diff[1]

if list(result["after"].keys()) != ["metadata"] or list(
if list(result["after"].keys()) == ["metadata"] and list(
result["before"].keys()
) != ["metadata"]:
return False, result
) == ["metadata"]:
# If only metadata.generation and metadata.resourceVersion changed, ignore it
ignored_keys = set(["generation", "resourceVersion"])

# If only metadata.generation and metadata.resourceVersion changed, ignore it
ignored_keys = set(["generation", "resourceVersion"])

if not set(result["after"]["metadata"].keys()).issubset(ignored_keys):
return False, result
if not set(result["before"]["metadata"].keys()).issubset(ignored_keys):
return False, result
if set(result["after"]["metadata"].keys()).issubset(ignored_keys) and set(result["before"]["metadata"].keys()).issubset(ignored_keys):
return True, result

result["before"] = hide_fields(result["before"], hidden_fields)
result["after"] = hide_fields(result["after"], hidden_fields)

return True, result
return False, result


def hide_fields(definition: dict, hidden_fields: Optional[list]) -> dict:
Expand All @@ -538,14 +534,63 @@ def hide_fields(definition: dict, hidden_fields: Optional[list]) -> dict:
return result


# hide_field is not hugely sophisticated and designed to cope
# with e.g. status or metadata.managedFields rather than e.g.
# spec.template.spec.containers[0].env[3].value
# hide_field should be able to cope with simple or more complicated
# field definitions
# e.g. status or metadata.managedFields or
# spec.template.spec.containers[0].env[3].value or
# metadata.annotations[kubectl.kubernetes.io/last-applied-configuration]
def hide_field(definition: dict, hidden_field: str) -> dict:
split = hidden_field.split(".", 1)
if split[0] in definition:
if len(split) == 2:
definition[split[0]] = hide_field(definition[split[0]], split[1])
def dict_contains_key(field: dict, key: str) -> bool:
return key in field

def list_contains_key(field: list, key: str) -> bool:
return key < len(field)

field_contains_key = dict_contains_key

(key, rest) = hide_field_split2(hidden_field)

if key.isdecimal():
key = int(key)
field_contains_key = list_contains_key
if field_contains_key(definition, key):
if rest:
definition[key] = hide_field(definition[key], rest)
# remove empty dicts and lists from the result
if definition[key] == dict() or definition[key] == list():
del definition[key]
else:
del definition[split[0]]
del definition[key]
return definition


# hide_field_split2 returns the first key in hidden_field and the rest of the hidden_field
# We expect the first key to either be in brackets, to be terminated by the start of a left
# bracket, or to be terminated by a dot.

# examples would be:
# field.another.next -> (field, another.next)
# field[key].value -> (field, [key].value)
# [key].value -> (key, value)
# [one][two] -> (one, [two])


def hide_field_split2(hidden_field: str) -> (str, str):
lbracket = hidden_field.find("[")
rbracket = hidden_field.find("]")
dot = hidden_field.find(".")

if lbracket == 0:
# skip past right bracket and any following dot
rest = hidden_field[rbracket + 1:]
if rest and rest[0] == ".":
rest = rest[1:]
return (hidden_field[lbracket + 1:rbracket], rest)

if lbracket != -1 and (dot == -1 or lbracket < dot):
return (hidden_field[:lbracket], hidden_field[lbracket:])

split = hidden_field.split(".", 1)
if len(split) == 1:
return split[0], ""
return split
3 changes: 2 additions & 1 deletion plugins/modules/k8s.py
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,8 @@
description:
- Hide fields matching this option in the result
- An example might be C(hidden_fields=[metadata.managedFields])
- Only field definitions that don't reference list items are supported (so V(spec.containers[0]) would not work)
or C(hidden_fields=[spec.containers[0].env[3].value])
or C(hidden_fields=[metadata.annotations[kubectl.kubernetes.io/last-applied-configuration]])
type: list
elements: str
version_added: 2.5.0
Expand Down
3 changes: 2 additions & 1 deletion plugins/modules/k8s_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@
description:
- Hide fields matching any of the field definitions in the result
- An example might be C(hidden_fields=[metadata.managedFields])
- Only field definitions that don't reference list items are supported (so V(spec.containers[0]) would not work)
or C(hidden_fields=[spec.containers[0].env[3].value])
or C(hidden_fields=[metadata.annotations[kubectl.kubernetes.io/last-applied-configuration]])
type: list
elements: str
version_added: 2.5.0
Expand Down
17 changes: 17 additions & 0 deletions tests/integration/targets/k8s_hide_fields/tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@
definition: "{{ hide_fields_base_configmap | combine({'data':{'anew':'value'}}) }}"
hidden_fields:
- data
- metadata.annotations[kubectl.kubernetes.io/last-applied-configuration]
apply: true
register: hf6
diff: true
Expand All @@ -86,6 +87,22 @@
that:
- hf6.changed

- name: Ensure hidden fields are not present
assert:
that:
- >-
'annotations' not in hf6.result.metadata or
'kubectl.kubernetes.io/last-applied-configuration'
not in hf6.result.metadata.annotations
- >-
'annotations' not in hf6.diff.before.metadata or
'kubectl.kubernetes.io/last-applied-configuration'
not in hf6.diff.before.metadata.annotations
- >-
'annotations' not in hf6.diff.after.metadata or
'kubectl.kubernetes.io/last-applied-configuration'
not in hf6.diff.after.metadata.annotations

- name: Hidden field should not show up in deletion
k8s:
definition: "{{ hide_fields_base_configmap}}"
Expand Down
Loading
Loading