Skip to content
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Custom gitignore rules

.vscode/
bin/
coverage.txt

Expand Down
4 changes: 4 additions & 0 deletions .goreleaser.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
version: 2
dist: bin

before:
hooks:
- "{{ if and (not .IsSnapshot) (not .Prerelease) }}sed -i -E 's/v[0-9]+\\.[0-9]+\\.[0-9]+(-(rc|alpha|beta)[.0-9]*)?/v{{ .Version }}/g' README.md docs/*.md{{ else }}true{{ end }}"

builds:
- main: "{{ .Env.BUILD_PATH }}"
binary: >-
Expand Down
40 changes: 39 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# syntax=docker/dockerfile:1
FROM docker.io/library/alpine:3.23.3@sha256:25109184c71bdad752c8312a8623239686a9a2071e8825f20acb8f2198c3f659
FROM docker.io/library/alpine:3.23.4@sha256:5b10f432ef3da1b8d4c7eb6c487f2f5a8f096bc91145e68878dd4a5019afde11 AS base

ARG TARGETPLATFORM
ARG CMD_NAME
Expand All @@ -8,3 +8,41 @@ ENV COMMAND_NAME=${CMD_NAME}
COPY ${TARGETPLATFORM}/${CMD_NAME} /usr/local/bin/

CMD ["/bin/sh", "-c", "${COMMAND_NAME}"]

FROM base AS helm3

ARG TARGETPLATFORM
ARG HELM3_VERSION=3.20.0
RUN <<'EOF'
set -eu
case "${TARGETPLATFORM}" in
linux/amd64) ARCH=amd64 ;;
linux/arm64) ARCH=arm64 ;;
linux/arm/v6) ARCH=arm ;;
linux/arm/v7) ARCH=arm ;;
linux/386) ARCH=386 ;;
*) echo "unsupported platform: ${TARGETPLATFORM}" >&2; exit 1 ;;
esac
wget -qO- "https://get.helm.sh/helm-v${HELM3_VERSION}-linux-${ARCH}.tar.gz" \
| tar xz --strip-components=1 -C /usr/local/bin "linux-${ARCH}/helm"
helm version
EOF

FROM base AS helm4

ARG TARGETPLATFORM
ARG HELM4_VERSION=4.1.1
RUN <<'EOF'
set -eu
case "${TARGETPLATFORM}" in
linux/amd64) ARCH=amd64 ;;
linux/arm64) ARCH=arm64 ;;
linux/arm/v6) ARCH=arm ;;
linux/arm/v7) ARCH=arm ;;
linux/386) ARCH=386 ;;
*) echo "unsupported platform: ${TARGETPLATFORM}" >&2; exit 1 ;;
esac
wget -qO- "https://get.helm.sh/helm-v${HELM4_VERSION}-linux-${ARCH}.tar.gz" \
| tar xz --strip-components=1 -C /usr/local/bin "linux-${ARCH}/helm"
helm version
EOF
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ VERSION_MODULE_NAME:= github.com/mia-platform/mlp/v2/pkg/cmd
SUPPORTED_PLATFORMS:= linux/386 linux/amd64 linux/arm64 linux/arm/v6 linux/arm/v7
# Default platform for which building the docker image (darwin can run linux images for the same arch)
# as SUPPORTED_PLATFORMS it highly depends on which platform are supported by the base image
DEFAULT_DOCKER_PLATFORM:= linux/$(GOARCH)/$(GOARM)
DEFAULT_DOCKER_PLATFORM:= linux/$(GOARCH)$(if $(GOARM),/$(GOARM))
# List of one or more container registries for tagging the resulting docker images
CONTAINER_REGISTRIES:= docker.io/miaplatform ghcr.io/mia-platform
# The description used on the org.opencontainers.description label of the container
Expand Down
10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ The main subcommands that the tool has are:
- `interpolate`: fill placeholders in kubernetes files with the values of ENV variables
- `generate`: create files for kubernetes `ConfigMap` and `Secret` based on files and/or ENV values
- `deploy`: create and/or update resources in a kubernetes namespace with the intepolated/generated files
- `kustomize`: run kustomize build
- `kustomize`: run kustomize build with optional Helm chart inflation support
- `hydrate`: helper to fill kustomization.yml with resources and patches
- `completion`: generate the autocompletion

Expand Down Expand Up @@ -45,6 +45,14 @@ To build the docker image locally run:
make docker-build
```

To build Docker images with Helm included:

```sh
make docker-build-helm3 # image tagged with -helm3
make docker-build-helm4 # image tagged with -helm4 and -helm
make docker-build-helm # alias for docker-build-helm4
```

## Testing `mlp`

To run the tests use the command:
Expand Down
7 changes: 5 additions & 2 deletions docs/10_overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,10 @@ the ability to use different configuration for different runtime environments.
with all the files and patches found
- `interpolate`: will run through all the files passed and run through a templating function for render the final
manifests
- `kustomize`: is the same command of `kustomize build` and can be used if you project is using the kustomize structure
to render the resources to pass to the `interpolate` command
- `kustomize`: is the same command of `kustomize build` and can be used if your project is using the kustomize structure
to render the resources to pass to the `interpolate` command. It supports Helm chart inflation via the
`--enable-helm` flag, along with `--helm-command`, `--helm-api-versions`, `--helm-kube-version`, and
`--load-restrictor` options

For more information about the various options available to the various commands you can always run
`mlp <command> --help` to see the helpers.
Expand All @@ -40,3 +42,4 @@ Below, you can find additional documentation for `mlp`:
- [Hydration Logic](./40_hydrate.md)
- [Interpolatation Template](./50_interpolate.md)
- [Filtered Jobs](./60_filtered_job.md)
- [Kustomize](./70_kustomize.md)
8 changes: 8 additions & 0 deletions docs/20_setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,14 @@ If you want to run the cli in its environment or you want to test the cli you ca
docker run ghcr.io/mia-platform/mlp:v2.6.0
```

If you need Helm support (e.g. for `mlp kustomize --enable-helm`), use one of the Helm-enabled image variants:

```sh
docker run ghcr.io/mia-platform/mlp:v2.6.0-helm3 # includes Helm 3
docker run ghcr.io/mia-platform/mlp:v2.6.0-helm4 # includes Helm 4
docker run ghcr.io/mia-platform/mlp:v2.6.0-helm # alias for -helm4
```

### Windows

`mlp` is not directly compatible with Windows, even if you have Go installed compilation on this OS
Expand Down
54 changes: 54 additions & 0 deletions docs/70_kustomize.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# Kustomize

The `kustomize` subcommand builds a set of KRM resources using a `kustomization.yaml` file, equivalent to
running `kustomize build`. It can optionally inflate Helm charts as part of the build.

## Usage

```sh
mlp kustomize [DIR] [flags]
```

If `DIR` is omitted, the current directory is used.

## Flags

| Flag | Default | Description |
|------|---------|-------------|
| `-o`, `--output` | | Write output to the specified file path instead of stdout |
| `--load-restrictor` | `rootOnly` | Set the file loading restrictor: `rootOnly` or `none` |
| `--enable-helm` | `false` | Enable Helm chart inflation |
| `--helm-command` | `helm` | Path or name of the helm binary |
| `--helm-api-versions` | | Kubernetes API versions used for Helm `Capabilities.APIVersions` |
| `--helm-kube-version` | | Kubernetes version used for Helm `Capabilities.KubeVersion` |

## Examples

```sh
# Build the current working directory
mlp kustomize

# Build a specific path
mlp kustomize /home/config/project

# Save output to a file
mlp kustomize --output /home/config/build-results.yaml

# Build with Helm chart inflation
mlp kustomize --enable-helm

# Build with Helm using a specific binary and Kubernetes version
mlp kustomize --enable-helm --helm-command /usr/local/bin/helm --helm-kube-version 1.30.0
```

## Helm Support

When `--enable-helm` is set, `mlp kustomize` will inflate any Helm charts referenced in your
`kustomization.yaml` using the [Helm chart inflation generator](https://kubectl.docs.kubernetes.io/references/kustomize/builtins/#_helmchartinflationgenerator_).

The `helm` binary must be available in `PATH` or specified via `--helm-command`. When using the
Docker image, use one of the Helm-enabled variants:

- `ghcr.io/mia-platform/mlp:v2.6.0-helm3` — includes Helm 3
- `ghcr.io/mia-platform/mlp:v2.6.0-helm4` — includes Helm 4
- `ghcr.io/mia-platform/mlp:v2.6.0-helm` — alias for `-helm4`
7 changes: 3 additions & 4 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ require (
k8s.io/client-go v0.34.3
k8s.io/utils v0.0.0-20260108192941-914a6e750570
sigs.k8s.io/e2e-framework v0.6.0
sigs.k8s.io/kustomize/api v0.21.0
sigs.k8s.io/kustomize/kyaml v0.21.0
sigs.k8s.io/kustomize/api v0.21.1
sigs.k8s.io/kustomize/kyaml v0.21.1
sigs.k8s.io/yaml v1.6.0
)

Expand Down Expand Up @@ -60,7 +60,6 @@ require (
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/prometheus/client_golang v1.22.0 // indirect
github.com/prometheus/client_model v0.6.2 // indirect
Expand All @@ -82,7 +81,7 @@ require (
golang.org/x/time v0.12.0 // indirect
gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect
google.golang.org/protobuf v1.36.6 // indirect
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/apiextensions-apiserver v0.34.3 // indirect
Expand Down
12 changes: 6 additions & 6 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -214,8 +214,8 @@ google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/evanphx/json-patch.v4 v4.12.0 h1:n6jtcsulIzXPJaxegRbvFNNrZDjbij7ny3gmSPG+6V4=
gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M=
gopkg.in/evanphx/json-patch.v4 v4.13.0 h1:czT3CmqEaQ1aanPc5SdlgQrrEIb8w/wwCvWWnfEbYzo=
gopkg.in/evanphx/json-patch.v4 v4.13.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M=
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
Expand Down Expand Up @@ -245,10 +245,10 @@ sigs.k8s.io/e2e-framework v0.6.0 h1:p7hFzHnLKO7eNsWGI2AbC1Mo2IYxidg49BiT4njxkrM=
sigs.k8s.io/e2e-framework v0.6.0/go.mod h1:IREnCHnKgRCioLRmNi0hxSJ1kJ+aAdjEKK/gokcZu4k=
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 h1:gBQPwqORJ8d8/YNZWEjoZs7npUVDpVXUUOFfW6CgAqE=
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg=
sigs.k8s.io/kustomize/api v0.21.0 h1:I7nry5p8iDJbuRdYS7ez8MUvw7XVNPcIP5GkzzuXIIQ=
sigs.k8s.io/kustomize/api v0.21.0/go.mod h1:XGVQuR5n2pXKWbzXHweZU683pALGw/AMVO4zU4iS8SE=
sigs.k8s.io/kustomize/kyaml v0.21.0 h1:7mQAf3dUwf0wBerWJd8rXhVcnkk5Tvn/q91cGkaP6HQ=
sigs.k8s.io/kustomize/kyaml v0.21.0/go.mod h1:hmxADesM3yUN2vbA5z1/YTBnzLJ1dajdqpQonwBL1FQ=
sigs.k8s.io/kustomize/api v0.21.1 h1:lzqbzvz2CSvsjIUZUBNFKtIMsEw7hVLJp0JeSIVmuJs=
sigs.k8s.io/kustomize/api v0.21.1/go.mod h1:f3wkKByTrgpgltLgySCntrYoq5d3q7aaxveSagwTlwI=
sigs.k8s.io/kustomize/kyaml v0.21.1 h1:IVlbmhC076nf6foyL6Taw4BkrLuEsXUXNpsE+ScX7fI=
sigs.k8s.io/kustomize/kyaml v0.21.1/go.mod h1:hmxADesM3yUN2vbA5z1/YTBnzLJ1dajdqpQonwBL1FQ=
sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU=
sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
sigs.k8s.io/structured-merge-diff/v6 v6.3.0 h1:jTijUJbW353oVOd9oTlifJqOGEkUw2jB/fXCbTiQEco=
Expand Down
70 changes: 60 additions & 10 deletions pkg/cmd/kustomize/kustomize.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,15 @@ package kustomize
import (
"context"
"errors"
"fmt"
"io"

"github.com/MakeNowJust/heredoc/v2"
"github.com/go-logr/logr"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
"sigs.k8s.io/kustomize/api/krusty"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/kyaml/filesys"
)

Expand All @@ -50,20 +52,36 @@ const (
outputFlagShort = "o"
outputFlagUsage = "If specified, write output to the file at this path"
outputIsADirectoryError = "output path is a directory instead of a file"

enableHelmFlagName = "enable-helm"
helmCommandFlagName = "helm-command"
helmAPIVersionsName = "helm-api-versions"
helmKubeVersionName = "helm-kube-version"
loadRestrictorName = "load-restrictor"
)

// Flags contains all the flags for the `kustomize` command. They will be converted to Options
// that contains all runtime options for the command.
type Flags struct {
outputPath string
outputPath string
enableHelm bool
helmCommand string
helmAPIVersions []string
helmKubeVersion string
loadRestrictor string
}

// Options have the data required to perform the kustomize operation
type Options struct {
inputPath string
outputPath string
fSys filesys.FileSystem
writer io.Writer
inputPath string
outputPath string
fSys filesys.FileSystem
enableHelm bool
helmCommand string
helmAPIVersions []string
helmKubeVersion string
loadRestrictor string
writer io.Writer
}

// NewCommand return the command for build a kustomization target from a directory
Expand Down Expand Up @@ -92,6 +110,11 @@ func NewCommand() *cobra.Command {
// AddFlags set the connection between Flags property to command line flags
func (f *Flags) AddFlags(set *pflag.FlagSet) {
set.StringVarP(&f.outputPath, outputFlagName, outputFlagShort, "", outputFlagUsage)
set.BoolVar(&f.enableHelm, enableHelmFlagName, false, "enable Helm chart inflation")
set.StringVar(&f.helmCommand, helmCommandFlagName, "helm", "path or name of the helm binary")
set.StringSliceVar(&f.helmAPIVersions, helmAPIVersionsName, nil, "Kubernetes api versions used for Helm Capabilities.APIVersions")
set.StringVar(&f.helmKubeVersion, helmKubeVersionName, "", "Kubernetes version used for Helm Capabilities.KubeVersion")
set.StringVar(&f.loadRestrictor, loadRestrictorName, "rootOnly", `set the file loading restrictor: "rootOnly" or "none"`)
}

// ToOptions transform the command flags in command runtime arguments
Expand All @@ -109,10 +132,15 @@ func (f *Flags) ToOptions(args []string, fSys filesys.FileSystem, writer io.Writ
}

return &Options{
inputPath: inputPath,
outputPath: f.outputPath,
fSys: fSys,
writer: writer,
inputPath: inputPath,
outputPath: f.outputPath,
fSys: fSys,
enableHelm: f.enableHelm,
helmCommand: f.helmCommand,
helmAPIVersions: f.helmAPIVersions,
helmKubeVersion: f.helmKubeVersion,
loadRestrictor: f.loadRestrictor,
writer: writer,
}, nil
}

Expand All @@ -121,7 +149,29 @@ func (o *Options) Run(ctx context.Context) error {
logger := logr.FromContextOrDiscard(ctx)

logger.V(5).Info("reading kustomize files", "path", o.inputPath)
kustomizer := krusty.MakeKustomizer(krusty.MakeDefaultOptions())
opts := krusty.MakeDefaultOptions()

if o.enableHelm {
opts.PluginConfig.HelmConfig.Enabled = true
opts.PluginConfig.HelmConfig.Command = o.helmCommand
if len(o.helmAPIVersions) > 0 {
opts.PluginConfig.HelmConfig.ApiVersions = o.helmAPIVersions
}
if o.helmKubeVersion != "" {
opts.PluginConfig.HelmConfig.KubeVersion = o.helmKubeVersion
}
}

switch o.loadRestrictor {
case "none":
opts.LoadRestrictions = types.LoadRestrictionsNone
case "rootOnly":
opts.LoadRestrictions = types.LoadRestrictionsRootOnly
default:
return fmt.Errorf("invalid load-restrictor value %q: must be \"rootOnly\" or \"none\"", o.loadRestrictor)
}

kustomizer := krusty.MakeKustomizer(opts)
resourceMap, err := kustomizer.Run(o.fSys, o.inputPath)
if err != nil {
return err
Expand Down
Loading
Loading