Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update flux build to have parity with other flux commands #798

Merged
merged 3 commits into from
Oct 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 15 additions & 27 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,45 +52,33 @@ metallb 4.1.14 metallb-metallb bitnami

### flux-local build

You can use the `flux-local` cli to build all objects in a cluster, similar to how you
You can use the `flux-local` cli to build objects in a cluster, similar to how you
use `kustomize build`, which is used underneath. Here is an example to build all flux
`Kustomization` objects within a git repository, using `kustomize cfg count` to parse
the yaml output:

```bash
$ flux-local build tests/testdata/cluster/ | kustomize cfg count
$ flux-local build ks --path tests/testdata/cluster/ | kustomize cfg count
Certificate: 2
ClusterPolicy: 1
ConfigMap: 1
HelmRelease: 2
HelmRepository: 2
ConfigMap: 2
GitRepository: 1
HelmRelease: 3
HelmRepository: 3
Kustomization: 4
Namespace: 1
```

You can also specify the root to build all clusters.

Additionally, you can inflate `HelmRelease` objects inside each `Kustomization` by adding
the `--enable-helm` command line flag. This example again shows `kustomize cfg count`
to parse the yaml output which now includes the resources from `HelmRelease` objects
defined in the cluster:
Additionally, you can inflate `HelmRelease` objects inside a `Kustomization`. This example
again shows `kustomize cfg count` to parse the yaml output of an inflated `HelmRelease`
objects defined in the cluster:

```bash
$ flux-local build tests/testdata/cluster/ --enable-helm --skip-crds | kustomize cfg count
ClusterPolicy: 1
ClusterRole: 2
ClusterRoleBinding: 2
ConfigMap: 3
DaemonSet: 1
Deployment: 3
HelmRelease: 2
HelmRepository: 2
$ flux-local build hr podinfo -n podinfo --path tests/testdata/cluster/ | kustomize cfg count
ConfigMap: 1
Deployment: 2
Ingress: 1
Namespace: 1
Role: 3
RoleBinding: 3
Secret: 1
Service: 3
ServiceAccount: 2
ValidatingWebhookConfiguration: 1
Service: 2
```

### flux-local diff
Expand Down
160 changes: 154 additions & 6 deletions flux_local/tool/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
_SubParsersAction as SubParsersAction,
BooleanOptionalAction,
)
import logging
import pathlib
import tempfile
import pathlib
import logging
from typing import cast


Expand All @@ -20,8 +20,8 @@
_LOGGER = logging.getLogger(__name__)


class BuildAction:
"""Flux-local build action."""
class BuildAllAction:
"""Flux-local build all action."""

@classmethod
def register(
Expand All @@ -31,8 +31,8 @@ def register(
args = cast(
ArgumentParser,
subparsers.add_parser(
"build",
help="Build local flux Kustomization target from a local directory",
"all",
help="Build all local flux Kustomization target from a local directory",
description="""You can use the flux-local cli to build all
objects in a cluster, similar to how you use kustomize build.
This uses kustomize build internally.""",
Expand Down Expand Up @@ -117,3 +117,151 @@ async def run( # type: ignore[no-untyped-def]
for key in keys:
for line in helm_content.content[key]:
print(line, file=file)


class BuildKustomizationAction:
"""Flux-local build for Kustomizations."""

@classmethod
def register(
cls, subparsers: SubParsersAction # type: ignore[type-arg]
) -> ArgumentParser:
"""Register the subparser commands."""
args: ArgumentParser = cast(
ArgumentParser,
subparsers.add_parser(
"kustomizations",
aliases=["ks", "kustomization"],
help="Build Kustomization objects",
description=("The build command does a local kustomize build."),
),
)
args.add_argument(
"--output-file",
type=str,
default="/dev/stdout",
help="Output file for the results of the command",
)
selector.add_ks_selector_flags(args)
args.set_defaults(cls=cls)
return args

async def run( # type: ignore[no-untyped-def]
self,
output_file: str,
**kwargs, # pylint: disable=unused-argument
) -> None:
"""Async Action implementation."""
query = selector.build_ks_selector(**kwargs)
query.helm_release.enabled = False

content = ContentOutput()
query.kustomization.visitor = content.visitor()
await git_repo.build_manifest(
selector=query, options=selector.options(**kwargs)
)

with open(output_file, "w") as file:
keys = list(content.content)
keys.sort()
for key in keys:
for line in content.content[key]:
print(line, file=file)


class BuildHelmReleaseAction:
"""Flux-local diff for HelmRelease."""

@classmethod
def register(
cls, subparsers: SubParsersAction # type: ignore[type-arg]
) -> ArgumentParser:
"""Register the subparser commands."""
args: ArgumentParser = cast(
ArgumentParser,
subparsers.add_parser(
"helmreleases",
aliases=["hr", "helmrelease"],
help="Build HelmRelease objects",
description=(
"The build command does a local kustomize build, then inflates "
"the helm template."
),
),
)
args.add_argument(
"--output-file",
type=str,
default="/dev/stdout",
help="Output file for the results of the command",
)
selector.add_hr_selector_flags(args)
selector.add_helm_options_flags(args)
args.set_defaults(cls=cls)
return args

async def run( # type: ignore[no-untyped-def]
self,
output_file: str,
**kwargs, # pylint: disable=unused-argument
) -> None:
"""Async Action implementation."""
query = selector.build_hr_selector(**kwargs)
content = ContentOutput()
helm_visitor = HelmVisitor()
query.kustomization.visitor = content.visitor()
query.helm_repo.visitor = helm_visitor.repo_visitor()
query.oci_repo.visitor = helm_visitor.repo_visitor()
query.helm_release.visitor = helm_visitor.release_visitor()
helm_options = selector.build_helm_options(**kwargs)
await git_repo.build_manifest(
selector=query, options=selector.options(**kwargs)
)

helm_content = ContentOutput()
with tempfile.TemporaryDirectory() as helm_cache_dir:
await helm_visitor.inflate(
pathlib.Path(helm_cache_dir),
helm_content.visitor(),
helm_options,
)

with open(output_file, "w") as file:
keys = list(helm_content.content)
keys.sort()
for key in keys:
for line in helm_content.content[key]:
print(line, file=file)


class BuildAction:
"""Flux-local build action."""

@classmethod
def register(
cls, subparsers: SubParsersAction # type: ignore[type-arg]
) -> ArgumentParser:
"""Register the subparser commands."""
args: ArgumentParser = subparsers.add_parser(
"build",
help="Build a local flux resource",
description="""You can use the flux-local cli to build all
objects in a cluster, similar to how you use kustomize build.
This uses kustomize build internally.""",
)
subcmds = args.add_subparsers(
title="Available commands",
required=True,
)
BuildKustomizationAction.register(subcmds)
BuildHelmReleaseAction.register(subcmds)
BuildAllAction.register(subcmds)
args.set_defaults(cls=cls)
return args

async def run( # type: ignore[no-untyped-def]
self,
**kwargs, # pylint: disable=unused-argument
) -> None:
"""Async Action implementation."""
# No-op given subcommands are dispatched
2 changes: 1 addition & 1 deletion tests/testdata/cluster9/apps/podinfo/repository.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@ spec:
operation: copy
url: oci://ghcr.io/stefanprodan/charts/podinfo
ref:
semver: ">= 6.0.0"
semver: "== 6.7.1"
Loading
Loading