Skip to content

Commit 09e0a30

Browse files
mnaserclaude
andauthored
feat: Add kustomize module for kubectl kustomize operations (#209)
* chore: add flake + fmt Signed-off-by: Mohammed Naser <[email protected]> * Add kustomize module for kubectl kustomize operations This commit introduces a new `kustomize` module that provides a clean, idempotent interface for running `kubectl kustomize` operations. Key features: - Runs kubectl kustomize against a source directory - Saves output to a destination file - Proper change detection using SHA256 checksums via Ansible's built-in module.sha256() method - Check mode (dry-run) support - Atomic file operations using module.atomic_move() - Clean temporary file handling with context managers Refactored the openstack_resource_controller role to use this new module instead of shell commands, improving idempotency and maintainability. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]> Signed-off-by: Mohammed Naser <[email protected]> --------- Signed-off-by: Mohammed Naser <[email protected]> Co-authored-by: Claude <[email protected]>
1 parent f7874c8 commit 09e0a30

File tree

6 files changed

+285
-4
lines changed

6 files changed

+285
-4
lines changed

.envrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
use flake

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
.ansible
2+
.direnv
23
__pycache__
34
tests/output

flake.lock

Lines changed: 103 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

flake.nix

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
{
2+
inputs = {
3+
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
4+
flake-parts.url = "github:hercules-ci/flake-parts";
5+
6+
treefmt-nix = {
7+
url = "github:numtide/treefmt-nix";
8+
inputs.nixpkgs.follows = "nixpkgs";
9+
};
10+
11+
devshell = {
12+
url = "github:numtide/devshell";
13+
inputs.nixpkgs.follows = "nixpkgs";
14+
};
15+
};
16+
17+
outputs =
18+
inputs@{ flake-parts, ... }:
19+
flake-parts.lib.mkFlake { inherit inputs; } {
20+
imports = [
21+
inputs.treefmt-nix.flakeModule
22+
inputs.devshell.flakeModule
23+
];
24+
25+
systems = [
26+
"x86_64-linux"
27+
"aarch64-linux"
28+
"aarch64-darwin"
29+
"x86_64-darwin"
30+
];
31+
perSystem =
32+
{
33+
config,
34+
self',
35+
inputs',
36+
pkgs,
37+
system,
38+
...
39+
}:
40+
{
41+
treefmt = {
42+
programs = {
43+
black.enable = true;
44+
nixfmt.enable = true;
45+
};
46+
};
47+
48+
devshells.default = {
49+
packages =
50+
with pkgs;
51+
[
52+
python3Packages.flake8
53+
]
54+
++ (builtins.attrValues config.treefmt.build.programs);
55+
};
56+
};
57+
};
58+
}

plugins/modules/kustomize.py

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
#!/usr/bin/python
2+
# -*- coding: utf-8 -*-
3+
4+
# Copyright (c) 2025 VEXXHOST, Inc.
5+
# SPDX-License-Identifier: Apache-2.0
6+
7+
from __future__ import absolute_import, division, print_function
8+
9+
__metaclass__ = type
10+
11+
import os
12+
import tempfile
13+
14+
from ansible.module_utils.basic import AnsibleModule
15+
16+
DOCUMENTATION = r"""
17+
---
18+
module: kustomize
19+
short_description: Run kubectl kustomize and save output to a file
20+
description:
21+
- Generates Kubernetes manifests using kubectl kustomize from a kustomization directory
22+
- Saves the output to a destination file
23+
- Supports check mode (dry-run)
24+
- Properly detects changes based on content checksum
25+
version_added: "2.5.0"
26+
options:
27+
src:
28+
description:
29+
- Path to the kustomization directory
30+
required: true
31+
type: path
32+
dest:
33+
description:
34+
- Path where the generated manifests should be saved
35+
required: true
36+
type: path
37+
kubectl_path:
38+
description:
39+
- Path to the kubectl binary
40+
type: path
41+
default: kubectl
42+
author:
43+
- Mohammed Naser <[email protected]>
44+
"""
45+
46+
EXAMPLES = r"""
47+
- name: Generate manifests using kubectl kustomize
48+
vexxhost.kubernetes.kustomize:
49+
src: /path/to/kustomization
50+
dest: /path/to/manifests.yaml
51+
52+
- name: Generate manifests with custom kubectl path
53+
vexxhost.kubernetes.kustomize:
54+
src: /path/to/kustomization
55+
dest: /path/to/manifests.yaml
56+
kubectl_path: /usr/local/bin/kubectl
57+
"""
58+
59+
RETURN = r"""
60+
changed:
61+
description: Whether the destination file was changed
62+
returned: always
63+
type: bool
64+
sample: true
65+
dest:
66+
description: Path to the destination file
67+
returned: always
68+
type: str
69+
sample: /path/to/manifests.yaml
70+
checksum:
71+
description: SHA256 checksum of the generated content
72+
returned: always
73+
type: str
74+
sample: 2aae6c35c94fcfb415dbe95f408b9ce91ee846ed
75+
"""
76+
77+
78+
def main():
79+
module = AnsibleModule(
80+
argument_spec=dict(
81+
src=dict(type="path", required=True),
82+
dest=dict(type="path", required=True),
83+
kubectl_path=dict(type="path", default="kubectl"),
84+
),
85+
supports_check_mode=True,
86+
)
87+
88+
_, stdout, _ = module.run_command(
89+
[module.params["kubectl_path"], "kustomize", module.params["src"]],
90+
check_rc=True,
91+
)
92+
93+
dest = module.params["dest"]
94+
with tempfile.NamedTemporaryFile(
95+
mode="w",
96+
dir=os.path.dirname(dest) or None,
97+
) as temp_file:
98+
temp_file.write(stdout)
99+
temp_file.flush()
100+
101+
new_checksum = module.sha256(temp_file.name)
102+
old_checksum = module.sha256(dest) if os.path.exists(dest) else None
103+
104+
changed = old_checksum != new_checksum
105+
106+
result = {
107+
"changed": changed,
108+
"dest": dest,
109+
"checksum": new_checksum,
110+
}
111+
112+
if changed and not module.check_mode:
113+
module.atomic_move(temp_file.name, dest)
114+
115+
module.exit_json(**result)
116+
117+
118+
if __name__ == "__main__":
119+
main()

roles/openstack_resource_controller/tasks/main.yml

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,9 @@
1818
group: root
1919

2020
- name: Generate manifests
21-
ansible.builtin.shell:
22-
cmd: "kubectl kustomize {{ openstack_resource_controller_build_directory }} > {{ openstack_resource_controller_build_file }}"
23-
chdir: "{{ openstack_resource_controller_build_directory }}"
24-
creates: "{{ openstack_resource_controller_build_file }}"
21+
vexxhost.kubernetes.kustomize:
22+
src: "{{ openstack_resource_controller_build_directory }}"
23+
dest: "{{ openstack_resource_controller_build_file }}"
2524

2625
- name: Apply manifest to cluster
2726
kubernetes.core.k8s:

0 commit comments

Comments
 (0)