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
|
||||
)
|
||||
|
||||
replace gopkg.in/yaml.v3 => github.com/colega/go-yaml-yaml v0.0.0-20220720070545-aaba007ebc22
|
||||
|
||||
require (
|
||||
cloud.google.com/go v0.102.1 // 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-20211001041855-01bcc9b48dfe/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/containerd v1.6.6 h1:xJNPhbrmz8xAMDNoVjHy9YHtWwEQNS+CDkcIRh7t8Y0=
|
||||
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.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
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/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
|
||||
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/helmexec"
|
||||
"github.com/helmfile/helmfile/pkg/maputil"
|
||||
"github.com/helmfile/helmfile/pkg/policy"
|
||||
"github.com/helmfile/helmfile/pkg/remote"
|
||||
"github.com/helmfile/helmfile/pkg/tmpl"
|
||||
)
|
||||
|
|
@ -83,6 +84,30 @@ type ReleaseSetSpec struct {
|
|||
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
|
||||
type HelmState struct {
|
||||
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:
|
||||
- name: elasticsearch
|
||||
chart: bitnami/elasticsearch
|
||||
version: 17.5.7
|
||||
version: 19.0.1
|
||||
jsonPatches:
|
||||
- target:
|
||||
version: v1
|
||||
|
|
|
|||
Loading…
Reference in New Issue