Skip to content

Commit 9ed5119

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

File tree

9 files changed

+179
-2
lines changed

9 files changed

+179
-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: 14 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,19 @@ 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("The resource {resource} doesn't support the subresource {subresource}".format(
152+
resource=resource.kind,
153+
subresource=subresource,
154+
)
155+
)
156+
157+
existing = svc.retrieve(resource.subresources[subresource], definition)
158+
resource = resource.subresources[subresource]
159+
else:
160+
existing = svc.retrieve(resource, definition)
148161

149162
if state == "absent":
150163
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: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# python 3 headers, required if submitting to Ansible
2+
from __future__ import (absolute_import, division, print_function)
3+
__metaclass__ = type
4+
5+
DOCUMENTATION = r"""
6+
name: create_dummy_csr
7+
author: Yorick Gruijthuijzen (@yorick1989) <[email protected]>
8+
version_added: "1.0"
9+
short_description: Returns test csr content
10+
description:
11+
- Returns test csr content
12+
options:
13+
_term:
14+
description: The Common Name
15+
required: True
16+
type: string
17+
"""
18+
19+
from ansible.plugins.lookup import LookupBase
20+
from ansible.utils.display import Display
21+
22+
display = Display()
23+
24+
from cryptography.hazmat.primitives.asymmetric import rsa
25+
from cryptography import x509
26+
from cryptography.x509.oid import NameOID
27+
from cryptography.hazmat.primitives import hashes
28+
from cryptography.hazmat.primitives import serialization
29+
30+
class LookupModule(LookupBase):
31+
"""Main module implementation"""
32+
def run(self, terms, variables=None, **kwargs):
33+
34+
common_name=terms[0]
35+
36+
display.debug("Generating CSR with the Common Name: %s" % common_name)
37+
38+
key = rsa.generate_private_key(
39+
public_exponent=65537,
40+
key_size=int(kwargs.get('key_size', 2048)),
41+
)
42+
43+
return x509.CertificateSigningRequestBuilder().subject_name(
44+
x509.Name([
45+
x509.NameAttribute(NameOID.COMMON_NAME, common_name),
46+
])
47+
).sign(key, hashes.SHA256()).public_bytes(serialization.Encoding.PEM)
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: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
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
54+
| json_query("resources[?metadata.name == 'testuser'].status.conditions[0][?message == 'Approval testing']") == csr_approval_condition
55+
56+
always:
57+
- name: Remove the CSR
58+
kubernetes.core.k8s:
59+
api_version: certificates.k8s.io/v1
60+
kind: certificatesigningrequests
61+
name: testuser
62+
state: absent

0 commit comments

Comments
 (0)