Add helmfile state validate policy (#592)
This commit is contained in:
parent
8ec51c2826
commit
d8d0bf830a
2
go.mod
2
go.mod
|
|
@ -32,6 +32,8 @@ require (
|
||||||
k8s.io/apimachinery v0.26.0
|
k8s.io/apimachinery v0.26.0
|
||||||
)
|
)
|
||||||
|
|
||||||
|
replace gopkg.in/yaml.v3 => github.com/colega/go-yaml-yaml v0.0.0-20220720070545-aaba007ebc22
|
||||||
|
|
||||||
require (
|
require (
|
||||||
cloud.google.com/go v0.102.1 // indirect
|
cloud.google.com/go v0.102.1 // indirect
|
||||||
cloud.google.com/go/compute v1.7.0 // indirect
|
cloud.google.com/go/compute v1.7.0 // indirect
|
||||||
|
|
|
||||||
9
go.sum
9
go.sum
|
|
@ -223,6 +223,8 @@ github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWH
|
||||||
github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||||
github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||||
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||||
|
github.com/colega/go-yaml-yaml v0.0.0-20220720070545-aaba007ebc22 h1:uVG5v+c6ndz9seCorYjQmlVlPbh3OMcMWJzAJZWdM/g=
|
||||||
|
github.com/colega/go-yaml-yaml v0.0.0-20220720070545-aaba007ebc22/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
github.com/containerd/cgroups v1.0.3 h1:ADZftAkglvCiD44c77s5YmMqaP2pzVCFZvBmAlBdAP4=
|
github.com/containerd/cgroups v1.0.3 h1:ADZftAkglvCiD44c77s5YmMqaP2pzVCFZvBmAlBdAP4=
|
||||||
github.com/containerd/containerd v1.6.6 h1:xJNPhbrmz8xAMDNoVjHy9YHtWwEQNS+CDkcIRh7t8Y0=
|
github.com/containerd/containerd v1.6.6 h1:xJNPhbrmz8xAMDNoVjHy9YHtWwEQNS+CDkcIRh7t8Y0=
|
||||||
github.com/containerd/containerd v1.6.6/go.mod h1:ZoP1geJldzCVY3Tonoz7b1IXk8rIX0Nltt5QE4OMNk0=
|
github.com/containerd/containerd v1.6.6/go.mod h1:ZoP1geJldzCVY3Tonoz7b1IXk8rIX0Nltt5QE4OMNk0=
|
||||||
|
|
@ -1391,13 +1393,6 @@ gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200121175148-a6ecf24a6d71/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
|
||||||
gopkg.in/yaml.v3 v3.0.0-20210107172259-749611fa9fcc/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
|
||||||
gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
|
||||||
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
|
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
|
||||||
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
|
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
|
||||||
gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
|
gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
// Package policy provides a policy checker for the helmfile state.
|
||||||
|
package policy
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
EnvironmentsAndReleasesWithinSameYamlPartErr = errors.New("environments and releases cannot be defined within the same YAML part. Use --- to extract the environments into a dedicated part")
|
||||||
|
)
|
||||||
|
|
||||||
|
// checkerFunc is a function that checks the helmState.
|
||||||
|
type checkerFunc func(map[string]interface{}) (bool, error)
|
||||||
|
|
||||||
|
func forbidEnvironmentsWithReleases(releaseState map[string]interface{}) (bool, error) {
|
||||||
|
// forbid environments and releases to be defined at the same yaml part
|
||||||
|
_, hasEnvironments := releaseState["environments"]
|
||||||
|
_, hasReleases := releaseState["releases"]
|
||||||
|
if hasEnvironments && hasReleases {
|
||||||
|
return false, EnvironmentsAndReleasesWithinSameYamlPartErr
|
||||||
|
}
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var checkerFuncs = []checkerFunc{
|
||||||
|
forbidEnvironmentsWithReleases,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Checker is a policy checker for the helmfile state.
|
||||||
|
func Checker(helmState map[string]interface{}) (bool, error) {
|
||||||
|
for _, fn := range checkerFuncs {
|
||||||
|
if isStrict, err := fn(helmState); err != nil {
|
||||||
|
return isStrict, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,54 @@
|
||||||
|
package policy
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestForbidEnvironmentsWithReleases(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
helmState map[string]interface{}
|
||||||
|
expectedErr bool
|
||||||
|
isStrict bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "no error when only releases",
|
||||||
|
helmState: map[string]interface{}{
|
||||||
|
"releases": interface{}(nil),
|
||||||
|
},
|
||||||
|
expectedErr: false,
|
||||||
|
isStrict: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "no error when only environments",
|
||||||
|
helmState: map[string]interface{}{
|
||||||
|
"environments": map[string]interface{}{},
|
||||||
|
},
|
||||||
|
expectedErr: false,
|
||||||
|
isStrict: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "error when both releases and environments",
|
||||||
|
helmState: map[string]interface{}{
|
||||||
|
"environments": interface{}(nil),
|
||||||
|
"releases": interface{}(nil),
|
||||||
|
},
|
||||||
|
expectedErr: true,
|
||||||
|
isStrict: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
isStrict, err := forbidEnvironmentsWithReleases(tc.helmState)
|
||||||
|
require.Equal(t, tc.isStrict, isStrict, "expected isStrict=%v, got=%v", tc.isStrict, isStrict)
|
||||||
|
if tc.expectedErr {
|
||||||
|
require.ErrorIsf(t, err, EnvironmentsAndReleasesWithinSameYamlPartErr, "expected error=%v, got=%v", EnvironmentsAndReleasesWithinSameYamlPartErr, err)
|
||||||
|
} else {
|
||||||
|
require.NoError(t, err, "expected no error but got error: %v", err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -29,6 +29,7 @@ import (
|
||||||
"github.com/helmfile/helmfile/pkg/filesystem"
|
"github.com/helmfile/helmfile/pkg/filesystem"
|
||||||
"github.com/helmfile/helmfile/pkg/helmexec"
|
"github.com/helmfile/helmfile/pkg/helmexec"
|
||||||
"github.com/helmfile/helmfile/pkg/maputil"
|
"github.com/helmfile/helmfile/pkg/maputil"
|
||||||
|
"github.com/helmfile/helmfile/pkg/policy"
|
||||||
"github.com/helmfile/helmfile/pkg/remote"
|
"github.com/helmfile/helmfile/pkg/remote"
|
||||||
"github.com/helmfile/helmfile/pkg/tmpl"
|
"github.com/helmfile/helmfile/pkg/tmpl"
|
||||||
)
|
)
|
||||||
|
|
@ -83,6 +84,30 @@ type ReleaseSetSpec struct {
|
||||||
LockFile string `yaml:"lockFilePath,omitempty"`
|
LockFile string `yaml:"lockFilePath,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// helmStateAlias is helm state alias
|
||||||
|
type helmStateAlias HelmState
|
||||||
|
|
||||||
|
func (hs HelmState) MarshalYAML() (interface{}, error) {
|
||||||
|
return helmStateAlias(hs), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hs *HelmState) UnmarshalYAML(value *yaml.Node) error {
|
||||||
|
helmStateInfo := make(map[string]interface{})
|
||||||
|
if err := value.DecodeWithOptions(&helmStateInfo, yaml.DecodeOptions{KnownFields: true}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
isStrict, err := policy.Checker(helmStateInfo)
|
||||||
|
if err != nil {
|
||||||
|
if isStrict {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fmt.Fprintf(os.Stderr, "Warning: %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return value.DecodeWithOptions((*helmStateAlias)(hs), yaml.DecodeOptions{KnownFields: true})
|
||||||
|
}
|
||||||
|
|
||||||
// HelmState structure for the helmfile
|
// HelmState structure for the helmfile
|
||||||
type HelmState struct {
|
type HelmState struct {
|
||||||
basePath string
|
basePath string
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
localChartRepoServer:
|
||||||
|
enabled: true
|
||||||
|
port: 18083
|
||||||
|
chartifyTempDir: envs_releases_within_same_yaml_part
|
||||||
|
helmfileArgs:
|
||||||
|
- --environment
|
||||||
|
- prod
|
||||||
|
- template
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
environments:
|
||||||
|
prod:
|
||||||
|
staging:
|
||||||
|
|
||||||
|
releases:
|
||||||
|
- name: raw
|
||||||
|
chart: ../../charts/raw-0.0.1
|
||||||
|
values:
|
||||||
|
- templates:
|
||||||
|
- |
|
||||||
|
chartVersion: {{`{{ .Chart.Version }}`}}
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
Warning: environments and releases cannot be defined within the same YAML part. Use --- to extract the environments into a dedicated part
|
||||||
|
Warning: environments and releases cannot be defined within the same YAML part. Use --- to extract the environments into a dedicated part
|
||||||
|
Building dependency release=raw, chart=../../charts/raw-0.0.1
|
||||||
|
Templating release=raw, chart=../../charts/raw-0.0.1
|
||||||
|
---
|
||||||
|
# Source: raw/templates/resources.yaml
|
||||||
|
chartVersion: 0.0.1
|
||||||
|
|
||||||
|
|
@ -5,7 +5,7 @@ repositories:
|
||||||
releases:
|
releases:
|
||||||
- name: elasticsearch
|
- name: elasticsearch
|
||||||
chart: bitnami/elasticsearch
|
chart: bitnami/elasticsearch
|
||||||
version: 17.5.7
|
version: 19.0.1
|
||||||
jsonPatches:
|
jsonPatches:
|
||||||
- target:
|
- target:
|
||||||
version: v1
|
version: v1
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue