Skip to content

Commit

Permalink
Add support for targetNamespace in Fluxtomization (#388)
Browse files Browse the repository at this point in the history
Test a cluster using targetNamespace without a namespace in the
HelmRelease

Issue #387
  • Loading branch information
allenporter authored Nov 20, 2023
1 parent 9e2e056 commit 491df3e
Show file tree
Hide file tree
Showing 7 changed files with 58 additions and 6 deletions.
2 changes: 1 addition & 1 deletion flux_local/git_repo.py
Original file line number Diff line number Diff line change
Expand Up @@ -559,7 +559,7 @@ async def build_kustomization(

docs = await cmd.grep(
f"kind=^({HELM_REPO_KIND}|{HELM_RELEASE_KIND}|{CLUSTER_POLICY_KIND})$"
).objects()
).objects(target_namespace=kustomization.target_namespace)
return (
filter(
helm_repo_selector.predicate,
Expand Down
22 changes: 19 additions & 3 deletions flux_local/kustomize.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,15 +113,21 @@ async def run(self) -> str:
"""Run the kustomize command and return the output as a string."""
return await run_piped(self._cmds)

async def _docs(self) -> AsyncGenerator[dict[str, Any], None]:
async def _docs(
self, target_namespace: str | None = None
) -> AsyncGenerator[dict[str, Any], None]:
"""Run the kustomize command and return the result documents."""
out = await self.run()
for doc in yaml.safe_load_all(out):
if target_namespace is not None:
doc = update_namespace(doc, target_namespace)
yield doc

async def objects(self) -> list[dict[str, Any]]:
async def objects(
self, target_namespace: str | None = None
) -> list[dict[str, Any]]:
"""Run the kustomize command and return the result cluster objects as a list."""
return [doc async for doc in self._docs()]
return [doc async for doc in self._docs(target_namespace=target_namespace)]

def skip_resources(self, kinds: list[str]) -> "Kustomize":
"""Skip resources kinds of the specified types."""
Expand Down Expand Up @@ -283,3 +289,13 @@ def grep(expr: str, path: Path, invert: bool = False) -> Kustomize:
else:
args.append(str(path))
return Kustomize([Command(args, cwd=cwd, exc=KustomizeException)])


def update_namespace(doc: dict[str, Any], namespace: str) -> dict[str, Any]:
"""Update the namespace of the specified document.
Will only update the namespace if the doc appears to have a metadata/name.
"""
if (metadata := doc.get("metadata")) is not None and "name" in metadata:
doc["metadata"]["namespace"] = namespace
return doc
5 changes: 5 additions & 0 deletions flux_local/manifest.py
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,9 @@ class Kustomization(BaseManifest):
source_namespace: str | None = None
"""The namespace of the sourceRef that provides this Kustomization."""

target_namespace: str | None = None
"""The namespace to target when performing the operation."""

@classmethod
def parse_doc(cls, doc: dict[str, Any]) -> "Kustomization":
"""Parse a partial Kustomization from a kubernetes resource."""
Expand All @@ -310,6 +313,7 @@ def parse_doc(cls, doc: dict[str, Any]) -> "Kustomization":
source_kind=source_ref.get("kind"),
source_name=source_ref.get("name"),
source_namespace=source_ref.get("namespace", namespace),
target_namespace=spec.get("targetNamespace"),
)

@property
Expand All @@ -333,6 +337,7 @@ def namespaced_name(self, sep: str = "/") -> str:
"source_name": True,
"source_namespace": True,
"source_kind": True,
"target_namespace": True,
}


Expand Down
32 changes: 32 additions & 0 deletions tests/test_kustomize.py
Original file line number Diff line number Diff line change
Expand Up @@ -187,3 +187,35 @@ async def test_build_flags() -> None:
assert "Secret" in result
assert "ConfigMap" in result
assert result == (TESTDATA_DIR / "repo/all.golden").read_text()


async def test_target_namespace() -> None:
"""Test a kustomization with a target namespace."""
ks = kustomize.build(TESTDATA_DIR / "repo").grep("kind=ConfigMap")

result = await ks.objects()
assert len(result) == 1
config_map = result[0]
assert "metadata" in config_map
assert config_map["metadata"] == {
"name": "cluster-settings",
"namespace": "flux-system",
"annotations": {
"config.kubernetes.io/index": "0",
"internal.config.kubernetes.io/index": "0",
},
}

result = await ks.objects(target_namespace="configs")
assert len(result) == 1
config_map = result[0]
assert "metadata" in config_map
assert config_map["metadata"] == {
"name": "cluster-settings",
# Verify updated namespace
"namespace": "configs",
"annotations": {
"config.kubernetes.io/index": "0",
"internal.config.kubernetes.io/index": "0",
},
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
name: ingress-nginx
namespace: networking
spec:
interval: 15m
chart:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
---
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: networking
resources:
- ./helmrelease.yaml
labels:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ metadata:
name: cluster-apps-ingress-nginx
namespace: flux-system
spec:
targetNamespace: networking
dependsOn:
- name: cluster-apps-ingress-nginx-certificates
path: ./tests/testdata/cluster2/apps/networking/ingress-nginx/app
Expand Down

0 comments on commit 491df3e

Please sign in to comment.