Skip to content

Commit e35bc45

Browse files
author
Yorick Gruijthuijzen
committed
Added support for subresources.
1 parent 1705ced commit e35bc45

File tree

9 files changed

+187
-2
lines changed

9 files changed

+187
-2
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
minor_changes:
2+
- Added support for `subresources` to the `k8s` module.

docs/kubernetes.core.k8s_module.rst

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1087,6 +1087,22 @@ Parameters
10871087
<div>Ignored if <code>wait</code> is not set.</div>
10881088
</td>
10891089
</tr>
1090+
<tr>
1091+
<td colspan="3">
1092+
<div class="ansibleOptionAnchor" id="parameter-"></div>
1093+
<b>subresource</b>
1094+
<a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
1095+
<div style="font-size: small">
1096+
<span style="color: purple">string</span>
1097+
</div>
1098+
</td>
1099+
<td>
1100+
<b>Default:</b><br/><div style="color: blue"></div>
1101+
</td>
1102+
<td>
1103+
<div>Provide the <code>subresource</code> to run your definition against.</div>
1104+
</td>
1105+
</tr>
10901106
</table>
10911107
<br/>
10921108

@@ -1275,7 +1291,22 @@ Examples
12751291
kind: Deployment
12761292
delete_all: true
12771293
1278-
1294+
# Approve a CSR using the approval <code>subresource</code> option.
1295+
- kubernetes.core.k8s:
1296+
subresource: approval
1297+
definition:
1298+
apiVersion: certificates.k8s.io/v1
1299+
kind: certificatesigningrequests
1300+
metadata:
1301+
name: testuser
1302+
status:
1303+
conditions:
1304+
- lastTransitionTime: "2025-07-31T16:00:00Z"
1305+
lastUpdateTime: "2025-07-31T16:00:00Z"
1306+
message: Approved by Ansible
1307+
reason: Approved
1308+
status: "True"
1309+
type: Approved
12791310
12801311
Return Values
12811312
-------------

plugins/module_utils/k8s/runner.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ def perform_action(svc, definition: Dict, params: Dict) -> Dict:
136136
kind = definition.get("kind")
137137
api_version = definition.get("apiVersion")
138138
hidden_fields = params.get("hidden_fields")
139+
subresource = params.get("subresource")
139140

140141
result = {"changed": False, "result": {}}
141142
instance = {}
@@ -144,7 +145,20 @@ def perform_action(svc, definition: Dict, params: Dict) -> Dict:
144145
resource = svc.find_resource(kind, api_version, fail=True)
145146
definition["kind"] = resource.kind
146147
definition["apiVersion"] = resource.group_version
147-
existing = svc.retrieve(resource, definition)
148+
149+
if subresource and subresource is not None:
150+
if subresource not in resource.subresources.keys():
151+
raise CoreException(
152+
"The resource {resource} doesn't support the subresource {subresource}".format(
153+
resource=resource.kind,
154+
subresource=subresource,
155+
)
156+
)
157+
158+
existing = svc.retrieve(resource.subresources[subresource], definition)
159+
resource = resource.subresources[subresource]
160+
else:
161+
existing = svc.retrieve(resource, definition)
148162

149163
if state == "absent":
150164
if exists(existing) and existing.kind.endswith("List"):

plugins/modules/k8s.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,11 @@
193193
type: list
194194
elements: str
195195
version_added: 3.0.0
196+
subresource:
197+
description:
198+
- Provide the C(subresource) to run your definition against.
199+
type: str
200+
version_added: 6.1.0
196201
197202
requirements:
198203
- "python >= 3.9"
@@ -481,6 +486,7 @@ def argspec():
481486
)
482487
argument_spec["delete_all"] = dict(type="bool", default=False, aliases=["all"])
483488
argument_spec["hidden_fields"] = dict(type="list", elements="str")
489+
argument_spec["subresource"] = dict(type="str")
484490

485491
return argument_spec
486492

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
time=20
2+
k8s
3+
k8s_info
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# python 3 headers, required if submitting to Ansible
2+
from __future__ import absolute_import, division, print_function
3+
4+
__metaclass__ = type
5+
6+
DOCUMENTATION = r"""
7+
name: create_dummy_csr
8+
author: Yorick Gruijthuijzen (@yorick1989) <[email protected]>
9+
version_added: "1.0"
10+
short_description: Returns test csr content
11+
description:
12+
- Returns test csr content
13+
options:
14+
_term:
15+
description: The Common Name
16+
required: True
17+
type: string
18+
"""
19+
20+
from ansible.plugins.lookup import LookupBase
21+
from ansible.utils.display import Display
22+
23+
display = Display()
24+
25+
from cryptography import x509
26+
from cryptography.hazmat.primitives import hashes, serialization
27+
from cryptography.hazmat.primitives.asymmetric import rsa
28+
from cryptography.x509.oid import NameOID
29+
30+
31+
class LookupModule(LookupBase):
32+
"""Main module implementation"""
33+
34+
def run(self, terms, variables=None, **kwargs):
35+
common_name = terms[0]
36+
37+
display.debug("Generating CSR with the Common Name: %s" % common_name)
38+
39+
key = rsa.generate_private_key(
40+
public_exponent=65537,
41+
key_size=int(kwargs.get("key_size", 2048)),
42+
)
43+
44+
return [
45+
x509.CertificateSigningRequestBuilder()
46+
.subject_name(
47+
x509.Name(
48+
[
49+
x509.NameAttribute(NameOID.COMMON_NAME, common_name),
50+
]
51+
)
52+
)
53+
.sign(key, hashes.SHA256())
54+
.public_bytes(serialization.Encoding.PEM)
55+
]
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
- connection: local
3+
gather_facts: false
4+
hosts: localhost
5+
environment:
6+
K8S_AUTH_KUBECONFIG: "{{ lookup('ansible.builtin.env', 'K8S_AUTH_KUBECONFIG', default='~/.kube/config') }}"
7+
roles:
8+
- k8s_subresource
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#!/usr/bin/env bash
2+
set -eux
3+
export ANSIBLE_CALLBACKS_ENABLED=profile_tasks
4+
export ANSIBLE_ROLES_PATH=../
5+
ansible-playbook playbook.yaml "$@"
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
---
2+
- name: Create a CSR
3+
kubernetes.core.k8s:
4+
definition:
5+
apiVersion: certificates.k8s.io/v1
6+
kind: CertificateSigningRequest
7+
metadata:
8+
name: testuser
9+
spec:
10+
request: '{{ lookup("create_dummy_csr", "testuser") | b64encode }}'
11+
signerName: kubernetes.io/kube-apiserver-client
12+
usages:
13+
- client auth
14+
wait: yes
15+
16+
- block:
17+
- name: Get the date_time
18+
ansible.builtin.setup:
19+
gather_subset: date_time
20+
21+
- name: Set CSR condition fact
22+
ansible.builtin.set_fact:
23+
csr_approval_condition:
24+
- lastUpdateTime: "{{ ansible_date_time.iso8601 }}"
25+
lastTransitionTime: "{{ ansible_date_time.iso8601 }}"
26+
message: Approval testing
27+
reason: Approved
28+
status: "True"
29+
type: Approved
30+
31+
- name: Approve the CSR
32+
kubernetes.core.k8s:
33+
subresource: approval
34+
definition:
35+
apiVersion: certificates.k8s.io/v1
36+
kind: certificatesigningrequests
37+
metadata:
38+
name: testuser
39+
status:
40+
conditions: "{{ csr_approval_condition }}"
41+
wait: yes
42+
43+
- name: Get the CSR info
44+
kubernetes.core.k8s_info:
45+
api_version: certificates.k8s.io/v1
46+
kind: certificatesigningrequests
47+
name: testuser
48+
register: csr_check
49+
50+
- name: assert that the CSR is approved
51+
ansible.builtin.assert:
52+
that:
53+
- csr_check.resources.0.status.conditions.0 == csr_approval_condition.0
54+
55+
always:
56+
- name: Remove the CSR
57+
kubernetes.core.k8s:
58+
api_version: certificates.k8s.io/v1
59+
kind: certificatesigningrequests
60+
name: testuser
61+
state: absent

0 commit comments

Comments
 (0)