Skip to content

Commit

Permalink
Add support for HelmRepository type oci (#190)
Browse files Browse the repository at this point in the history
Add support for HelmRepository type oci.

See
https://fluxcd.io/blog/2022/11/verify-the-integrity-of-the-helm-charts-stored-as-oci-artifacts-before-reconciling-them-with-flux/
for an example on how to set up.

This was added following the pattern in
onedr0p/home-ops@5ca73a5
  • Loading branch information
allenporter authored May 24, 2023
1 parent cbdcb08 commit 32acaa2
Show file tree
Hide file tree
Showing 7 changed files with 61 additions and 12 deletions.
25 changes: 22 additions & 3 deletions flux_local/helm.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@

from . import command
from .kustomize import Kustomize
from .manifest import HelmRelease, HelmRepository, CRD_KIND, SECRET_KIND
from .manifest import HelmRelease, HelmRepository, CRD_KIND, SECRET_KIND, REPO_TYPE_OCI
from .exceptions import HelmException

__all__ = [
Expand All @@ -57,6 +57,13 @@
HELM_BIN = "helm"


def _chart_name(repo: HelmRepository, release: HelmRelease) -> str:
"""Return the helm chart name used for the helm template command."""
if repo.repo_type == REPO_TYPE_OCI:
return f"{repo.url}/{release.chart.name}"
return release.chart.chart_name


class RepositoryConfig:
"""Generates a helm repository configuration from flux HelmRepository objects."""

Expand Down Expand Up @@ -113,7 +120,10 @@ async def update(self) -> None:
Typically the repository must be updated before doing any chart templating.
"""
_LOGGER.debug("Updating %d repositories", len(self._repos))
content = yaml.dump(RepositoryConfig(self._repos).config, sort_keys=False)
repos = [repo for repo in self._repos if repo.repo_type != REPO_TYPE_OCI]
if not repos:
return
content = yaml.dump(RepositoryConfig(repos).config, sort_keys=False)
async with aiofiles.open(str(self._repo_config_file), mode="w") as config_file:
await config_file.write(content)
await command.run(
Expand All @@ -138,11 +148,20 @@ async def template(
also specify values directory if not present in cluster manifest
e.g. it came from a truncated yaml.
"""
repo = next(
iter([repo for repo in self._repos if repo.repo_name == release.repo_name]),
None,
)
if not repo:
raise HelmException(
f"Unable to find HelmRepository for {release.chart.chart_name} for "
f"HelmRelease {release.name}"
)
args: list[str] = [
HELM_BIN,
"template",
release.name,
release.chart.chart_name,
_chart_name(repo, release),
"--namespace",
release.namespace,
]
Expand Down
18 changes: 17 additions & 1 deletion flux_local/manifest.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@
CRD_KIND = "CustomResourceDefinition"
SECRET_KIND = "Secret"

REPO_TYPE_DEFAULT = "default"
REPO_TYPE_OCI = "oci"


def _check_version(doc: dict[str, Any], version: str) -> None:
"""Assert that the resource has the specified version."""
Expand Down Expand Up @@ -159,6 +162,11 @@ def release_name(self) -> str:
"""Identifier for the HelmRelease."""
return f"{self.namespace}-{self.name}"

@property
def repo_name(self) -> str:
"""Identifier for the HelmRepository identified in the HelmChart."""
return f"{self.chart.repo_namespace}-{self.chart.repo_name}"

_COMPACT_EXCLUDE_FIELDS = {
"values": True,
"chart": HelmChart._COMPACT_EXCLUDE_FIELDS,
Expand All @@ -177,6 +185,9 @@ class HelmRepository(BaseManifest):
url: str
"""The URL to the repository of helm charts."""

repo_type: str | None = None
"""The type of the HelmRepository."""

@classmethod
def parse_doc(cls, doc: dict[str, Any]) -> "HelmRepository":
"""Parse a HelmRepository from a kubernetes resource."""
Expand All @@ -191,7 +202,12 @@ def parse_doc(cls, doc: dict[str, Any]) -> "HelmRepository":
raise InputException(f"Invalid {cls} missing spec: {doc}")
if not (url := spec.get("url")):
raise InputException(f"Invalid {cls} missing spec.url: {doc}")
return cls(name=name, namespace=namespace, url=url)
return cls(
name=name,
namespace=namespace,
url=url,
repo_type=spec.get("type", REPO_TYPE_DEFAULT),
)

@property
def repo_name(self) -> str:
Expand Down
17 changes: 13 additions & 4 deletions tests/test_manifest.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,14 +60,23 @@ def test_compact_helm_release() -> None:
def test_parse_helm_repository() -> None:
"""Test parsing a helm repository doc."""

docs = yaml.load_all(
(TESTDATA_DIR / "configs/helm-repositories.yaml").read_text(),
Loader=yaml.CLoader,
docs = list(
yaml.load_all(
(TESTDATA_DIR / "configs/helm-repositories.yaml").read_text(),
Loader=yaml.CLoader,
)
)
repo = HelmRepository.parse_doc(next(iter(docs)))
assert len(docs) == 2
repo = HelmRepository.parse_doc(docs[0])
assert repo.name == "bitnami"
assert repo.namespace == "flux-system"
assert repo.url == "https://charts.bitnami.com/bitnami"
assert repo.repo_type == "default"
repo = HelmRepository.parse_doc(docs[1])
assert repo.name == "podinfo"
assert repo.namespace == "flux-system"
assert repo.url == "oci://ghcr.io/stefanprodan/charts"
assert repo.repo_type == "oci"


async def test_write_manifest_file() -> None:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,5 @@ metadata:
namespace: flux-system
spec:
interval: 5m
url: https://stefanprodan.github.io/podinfo
type: oci
url: oci://ghcr.io/stefanprodan/charts
3 changes: 2 additions & 1 deletion tests/tool/testdata/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,8 @@ stdout: |+
internal.config.kubernetes.io/index: '2'
spec:
interval: 5m
url: https://stefanprodan.github.io/podinfo
type: oci
url: oci://ghcr.io/stefanprodan/charts
---
apiVersion: helm.toolkit.fluxcd.io/v2beta1
Expand Down
3 changes: 2 additions & 1 deletion tests/tool/testdata/build_helm.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,8 @@ stdout: |+
internal.config.kubernetes.io/index: '2'
spec:
interval: 5m
url: https://stefanprodan.github.io/podinfo
type: oci
url: oci://ghcr.io/stefanprodan/charts
---
apiVersion: helm.toolkit.fluxcd.io/v2beta1
Expand Down
4 changes: 3 additions & 1 deletion tests/tool/testdata/get_cluster_yaml.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,11 @@ stdout: |
- name: bitnami
namespace: flux-system
url: https://charts.bitnami.com/bitnami
repo_type: default
- name: podinfo
namespace: flux-system
url: https://stefanprodan.github.io/podinfo
url: oci://ghcr.io/stefanprodan/charts
repo_type: oci
helm_releases: []
cluster_policies:
- name: test-allow-policy
Expand Down

0 comments on commit 32acaa2

Please sign in to comment.