mirror of
https://github.com/FairwindsOps/polaris.git
synced 2026-08-29 22:17:16 +00:00
Compare commits
8
Commits
8.5.6
...
rb/updates
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
59945a4860 | ||
|
|
c6befdb3fc | ||
|
|
0bcc48ee2c | ||
|
|
4a0713c754 | ||
|
|
9da23c19c8 | ||
|
|
53cbc832e0 | ||
|
|
cdf4cb26a2 | ||
|
|
5a404c7106 |
@@ -120,7 +120,7 @@ jobs:
|
||||
|
||||
test:
|
||||
docker:
|
||||
- image: cimg/go:1.19
|
||||
- image: cimg/go:1.22
|
||||
steps:
|
||||
- checkout
|
||||
- *set_environment_variables
|
||||
@@ -136,7 +136,9 @@ jobs:
|
||||
# The goreleaser image tag determins the version of Go.
|
||||
# Manually check goreleaser images for their version of Go.
|
||||
# Ref: https://hub.docker.com/r/goreleaser/goreleaser/tags
|
||||
- image: goreleaser/goreleaser:v1.18.2
|
||||
- image: goreleaser/goreleaser:v1.25.0-nightly # Go 1.22.0
|
||||
environment:
|
||||
GOLANG_VERSION: "1.22.0"
|
||||
steps:
|
||||
- checkout
|
||||
- setup_remote_docker:
|
||||
|
||||
@@ -36,7 +36,7 @@ archives:
|
||||
name_template: "{{ .ProjectName }}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}{{ if .Mips }}_{{ .Mips }}{{ end }}"
|
||||
signs:
|
||||
- cmd: cosign
|
||||
args: ["sign-blob", "--key=hashivault://cosign", "-output-signature=${signature}", "${artifact}"]
|
||||
args: ["sign-blob", "--yes", "--key=hashivault://cosign", "--output-signature=${signature}", "${artifact}"]
|
||||
artifacts: checksum
|
||||
release:
|
||||
# This is replaced using `envsubst`, depending on the git branch.
|
||||
|
||||
+7
-147
@@ -15,26 +15,17 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"errors"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/fairwindsops/polaris/pkg/kube"
|
||||
"github.com/fairwindsops/polaris/pkg/mutation"
|
||||
"github.com/fairwindsops/polaris/pkg/validator"
|
||||
"github.com/fairwindsops/polaris/pkg/fix"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
const templateLineMarker = "# POLARIS_FIX_TMPL"
|
||||
const templateOpenMarker = "POLARIS_OPEN_TMPL"
|
||||
const templateCloseMarker = "POLARIS_CLOSE_TMPL"
|
||||
|
||||
var (
|
||||
filesPath string
|
||||
checksToFix []string
|
||||
fixAll bool
|
||||
isTemplate bool
|
||||
)
|
||||
|
||||
@@ -52,145 +43,14 @@ var fixCommand = &cobra.Command{
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
logrus.Debug("Setting up controller manager")
|
||||
|
||||
if filesPath == "" {
|
||||
logrus.Error("Please specify a files-path flag")
|
||||
cmd.Help()
|
||||
os.Exit(1)
|
||||
}
|
||||
var yamlFiles []string
|
||||
fileInfo, err := os.Stat(filesPath)
|
||||
err := fix.Execute(config, filesPath, isTemplate, checksToFix...)
|
||||
if err != nil {
|
||||
logrus.Error(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
if fileInfo.IsDir() {
|
||||
baseDir := filesPath
|
||||
if !strings.HasSuffix(filesPath, "/") {
|
||||
baseDir = baseDir + "/"
|
||||
}
|
||||
yamlFiles, err = getYamlFiles(baseDir)
|
||||
if err != nil {
|
||||
logrus.Error(err)
|
||||
if errors.Is(err, fix.ErrFilesPathRequired) {
|
||||
logrus.Error("Please specify a files-path flag")
|
||||
cmd.Help()
|
||||
os.Exit(1)
|
||||
}
|
||||
} else {
|
||||
yamlFiles = append(yamlFiles, filesPath)
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
|
||||
if len(checksToFix) > 0 {
|
||||
if len(checksToFix) == 1 && checksToFix[0] == "all" {
|
||||
allchecks := []string{}
|
||||
for key := range config.Checks {
|
||||
allchecks = append(allchecks, key)
|
||||
}
|
||||
config.Mutations = allchecks
|
||||
} else if len(checksToFix) == 0 && checksToFix[0] == "none" {
|
||||
config.Mutations = nil
|
||||
} else {
|
||||
config.Mutations = checksToFix
|
||||
}
|
||||
}
|
||||
|
||||
for _, fullFilePath := range yamlFiles {
|
||||
yamlContent, err := os.ReadFile(fullFilePath)
|
||||
if err != nil {
|
||||
logrus.Fatalf("Error reading file with file path %s: %v", fullFilePath, err)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
logrus.Fatalf("Error marshalling %s: %v", fullFilePath, err)
|
||||
}
|
||||
|
||||
if isTemplate {
|
||||
yamlContent = []byte(detemplate(string(yamlContent)))
|
||||
}
|
||||
kubeResources := kube.CreateResourceProviderFromYaml(string(yamlContent))
|
||||
results, err := validator.ApplyAllSchemaChecksToResourceProvider(&config, kubeResources)
|
||||
if err != nil {
|
||||
logrus.Fatalf("Error applying schema check to the resources %s: %v", fullFilePath, err)
|
||||
}
|
||||
allMutations := mutation.GetMutationsFromResults(results)
|
||||
|
||||
updatedYamlContent := ""
|
||||
if len(allMutations) > 0 {
|
||||
for _, resources := range kubeResources.Resources {
|
||||
for _, resource := range resources {
|
||||
key := fmt.Sprintf("%s/%s/%s", resource.Kind, resource.Resource.GetName(), resource.Resource.GetNamespace())
|
||||
mutations := allMutations[key]
|
||||
mutatedYamlContent, err := mutation.ApplyAllMutations(string(resource.OriginalObjectYAML), mutations)
|
||||
if err != nil {
|
||||
logrus.Errorf("Error applying schema mutations to the resource %s: %v", key, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
if updatedYamlContent != "" {
|
||||
updatedYamlContent += "\n---\n"
|
||||
}
|
||||
updatedYamlContent += mutatedYamlContent
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if isTemplate {
|
||||
updatedYamlContent = retemplate(updatedYamlContent)
|
||||
}
|
||||
|
||||
if updatedYamlContent != "" {
|
||||
err = os.WriteFile(fullFilePath, []byte(updatedYamlContent), 0644)
|
||||
if err != nil {
|
||||
logrus.Fatalf("Error writing output to file: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
}
|
||||
|
||||
func detemplate(content string) string {
|
||||
lines := strings.Split(content, "\n")
|
||||
for idx, line := range lines {
|
||||
lines[idx] = detemplateLine(line)
|
||||
}
|
||||
return strings.Join(lines, "\n")
|
||||
}
|
||||
|
||||
func retemplate(content string) string {
|
||||
lines := strings.Split(content, "\n")
|
||||
for idx, line := range lines {
|
||||
lines[idx] = retemplateLine(line)
|
||||
}
|
||||
return strings.Join(lines, "\n")
|
||||
}
|
||||
|
||||
func detemplateLine(line string) string {
|
||||
if !strings.HasPrefix(strings.TrimSpace(line), "{{") {
|
||||
line = strings.ReplaceAll(line, "{", templateOpenMarker)
|
||||
line = strings.ReplaceAll(line, "}", templateCloseMarker)
|
||||
return line
|
||||
}
|
||||
tmplStart := strings.Index(line, "{{")
|
||||
newLine := line[:tmplStart] + templateLineMarker + line[tmplStart:]
|
||||
return newLine
|
||||
}
|
||||
|
||||
func retemplateLine(line string) string {
|
||||
if !strings.Contains(line, templateLineMarker) {
|
||||
line = strings.ReplaceAll(line, templateOpenMarker, "{")
|
||||
line = strings.ReplaceAll(line, templateCloseMarker, "}")
|
||||
return line
|
||||
}
|
||||
return strings.Replace(line, templateLineMarker, "", 1)
|
||||
}
|
||||
|
||||
func getYamlFiles(rootpath string) ([]string, error) {
|
||||
var list []string
|
||||
err := filepath.Walk(rootpath, func(path string, info os.FileInfo, err error) error {
|
||||
if info.IsDir() {
|
||||
return nil
|
||||
}
|
||||
if filepath.Ext(path) == ".yaml" || filepath.Ext(path) == ".yml" {
|
||||
list = append(list, path)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
return list, err
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
module github.com/fairwindsops/polaris
|
||||
|
||||
go 1.20
|
||||
go 1.22
|
||||
|
||||
require (
|
||||
github.com/AlecAivazis/survey/v2 v2.3.7
|
||||
|
||||
@@ -101,6 +101,7 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2
|
||||
github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY=
|
||||
github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/zapr v1.2.4 h1:QHVo+6stLbfJmYGkQ7uGHUCu5hnAFAj6mDe6Ea0SeOo=
|
||||
github.com/go-logr/zapr v1.2.4/go.mod h1:FyHWQIzQORZ0QVE1BtVHv3cKtNLuXsbNLtpuhNapBOA=
|
||||
github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE=
|
||||
github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=
|
||||
github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE=
|
||||
@@ -108,6 +109,7 @@ github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En
|
||||
github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g=
|
||||
github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
|
||||
github.com/gobuffalo/logger v1.0.6 h1:nnZNpxYo0zx+Aj9RfMPBm+x9zAU2OayFh/xrAWi34HU=
|
||||
github.com/gobuffalo/logger v1.0.6/go.mod h1:J31TBEHR1QLV2683OXTAItYIg8pv2JMHnF/quuAbMjs=
|
||||
github.com/gobuffalo/packd v1.0.1 h1:U2wXfRr4E9DH8IdsDLlRFwTZTK7hLfq9qT/QHXGVe/0=
|
||||
@@ -186,6 +188,7 @@ github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLe
|
||||
github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec=
|
||||
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||
@@ -244,6 +247,7 @@ github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
@@ -289,7 +293,9 @@ github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjY
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||
github.com/onsi/ginkgo/v2 v2.13.0 h1:0jY9lJquiL8fcf3M4LAXN5aMlS/b2BV86HFFPCPMgE4=
|
||||
github.com/onsi/ginkgo/v2 v2.13.0/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xlT/ETL/o=
|
||||
github.com/onsi/gomega v1.29.0 h1:KIA/t2t5UBzoirT4H9tsML45GEbo3ouUnBHsCfD2tVg=
|
||||
github.com/onsi/gomega v1.29.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ=
|
||||
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||
github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
|
||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||
@@ -318,6 +324,7 @@ github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6L
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
|
||||
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
|
||||
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||
@@ -376,10 +383,12 @@ go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
|
||||
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
|
||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A=
|
||||
go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4=
|
||||
go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=
|
||||
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
|
||||
go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
|
||||
go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60=
|
||||
go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg=
|
||||
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
@@ -491,6 +500,7 @@ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJ
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@@ -619,6 +629,7 @@ golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.12.0 h1:YW6HUoUmYBpwSgyaGaZq1fHjrBjX1rlpZ54T6mu2kss=
|
||||
golang.org/x/tools v0.12.0/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
@@ -758,6 +769,7 @@ honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9
|
||||
k8s.io/api v0.29.0 h1:NiCdQMY1QOp1H8lfRyeEf8eOwV6+0xA6XEE44ohDX2A=
|
||||
k8s.io/api v0.29.0/go.mod h1:sdVmXoz2Bo/cb77Pxi71IPTSErEW32xa4aXwKH7gfBA=
|
||||
k8s.io/apiextensions-apiserver v0.27.2 h1:iwhyoeS4xj9Y7v8YExhUwbVuBhMr3Q4bd/laClBV6Bo=
|
||||
k8s.io/apiextensions-apiserver v0.27.2/go.mod h1:Oz9UdvGguL3ULgRdY9QMUzL2RZImotgxvGjdWRq6ZXQ=
|
||||
k8s.io/apimachinery v0.29.0 h1:+ACVktwyicPz0oc6MTMLwa2Pw3ouLAfAon1wPLtG48o=
|
||||
k8s.io/apimachinery v0.29.0/go.mod h1:eVBxQ/cwiJxH58eK/jd/vAk4mrxmVlnpBH5J2GbMeis=
|
||||
k8s.io/client-go v0.29.0 h1:KmlDtFcrdUzOYrBhXHgKw5ycWzc3ryPX5mQe0SkG3y8=
|
||||
|
||||
+159
@@ -0,0 +1,159 @@
|
||||
package fix
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/fairwindsops/polaris/pkg/config"
|
||||
"github.com/fairwindsops/polaris/pkg/kube"
|
||||
"github.com/fairwindsops/polaris/pkg/mutation"
|
||||
"github.com/fairwindsops/polaris/pkg/validator"
|
||||
)
|
||||
|
||||
const templateLineMarker = "# POLARIS_FIX_TMPL"
|
||||
const templateOpenMarker = "POLARIS_OPEN_TMPL"
|
||||
const templateCloseMarker = "POLARIS_CLOSE_TMPL"
|
||||
|
||||
var ErrFilesPathRequired = errors.New("files-path flag is required")
|
||||
|
||||
func Execute(config config.Configuration, filesPath string, isTemplate bool, checksToFix ...string) error {
|
||||
if filesPath == "" {
|
||||
return ErrFilesPathRequired
|
||||
}
|
||||
|
||||
var yamlFiles []string
|
||||
fileInfo, err := os.Stat(filesPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error getting file info: %v", err)
|
||||
}
|
||||
if fileInfo.IsDir() {
|
||||
baseDir := filesPath
|
||||
if !strings.HasSuffix(filesPath, "/") {
|
||||
baseDir = baseDir + "/"
|
||||
}
|
||||
yamlFiles, err = getYamlFiles(baseDir)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error getting yaml files from directory: %v", err)
|
||||
}
|
||||
} else {
|
||||
yamlFiles = append(yamlFiles, filesPath)
|
||||
}
|
||||
|
||||
if len(checksToFix) > 0 {
|
||||
if len(checksToFix) == 1 && checksToFix[0] == "all" {
|
||||
allchecks := []string{}
|
||||
for key := range config.Checks {
|
||||
allchecks = append(allchecks, key)
|
||||
}
|
||||
config.Mutations = allchecks
|
||||
} else if len(checksToFix) == 0 && checksToFix[0] == "none" {
|
||||
config.Mutations = nil
|
||||
} else {
|
||||
config.Mutations = checksToFix
|
||||
}
|
||||
}
|
||||
|
||||
for _, fullFilePath := range yamlFiles {
|
||||
yamlContent, err := os.ReadFile(fullFilePath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error reading file with file path %s: %v", fullFilePath, err)
|
||||
}
|
||||
|
||||
if isTemplate {
|
||||
yamlContent = []byte(detemplate(string(yamlContent)))
|
||||
}
|
||||
kubeResources, err := kube.CreateResourceProviderFromYaml(string(yamlContent))
|
||||
if err != nil {
|
||||
return fmt.Errorf("error creating resource provider from yaml: %v", err)
|
||||
}
|
||||
results, err := validator.ApplyAllSchemaChecksToResourceProvider(&config, kubeResources)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error applying schema check to the resources %s: %v", fullFilePath, err)
|
||||
}
|
||||
allMutations := mutation.GetMutationsFromResults(results)
|
||||
|
||||
updatedYamlContent := ""
|
||||
if len(allMutations) > 0 {
|
||||
for _, resources := range kubeResources.Resources {
|
||||
for _, resource := range resources {
|
||||
key := fmt.Sprintf("%s/%s/%s", resource.Kind, resource.Resource.GetName(), resource.Resource.GetNamespace())
|
||||
mutations := allMutations[key]
|
||||
mutatedYamlContent, err := mutation.ApplyAllMutations(string(resource.OriginalObjectYAML), mutations)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error applying schema mutations to the resource %s: %v", key, err)
|
||||
}
|
||||
if updatedYamlContent != "" {
|
||||
updatedYamlContent += "\n---\n"
|
||||
}
|
||||
updatedYamlContent += mutatedYamlContent
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if isTemplate {
|
||||
updatedYamlContent = retemplate(updatedYamlContent)
|
||||
}
|
||||
|
||||
if updatedYamlContent != "" {
|
||||
err = os.WriteFile(fullFilePath, []byte(updatedYamlContent), 0644)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error writing output to file: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func detemplate(content string) string {
|
||||
lines := strings.Split(content, "\n")
|
||||
for idx, line := range lines {
|
||||
lines[idx] = detemplateLine(line)
|
||||
}
|
||||
return strings.Join(lines, "\n")
|
||||
}
|
||||
|
||||
func retemplate(content string) string {
|
||||
lines := strings.Split(content, "\n")
|
||||
for idx, line := range lines {
|
||||
lines[idx] = retemplateLine(line)
|
||||
}
|
||||
return strings.Join(lines, "\n")
|
||||
}
|
||||
|
||||
func detemplateLine(line string) string {
|
||||
if !strings.HasPrefix(strings.TrimSpace(line), "{{") {
|
||||
line = strings.ReplaceAll(line, "{", templateOpenMarker)
|
||||
line = strings.ReplaceAll(line, "}", templateCloseMarker)
|
||||
return line
|
||||
}
|
||||
tmplStart := strings.Index(line, "{{")
|
||||
newLine := line[:tmplStart] + templateLineMarker + line[tmplStart:]
|
||||
return newLine
|
||||
}
|
||||
|
||||
func retemplateLine(line string) string {
|
||||
if !strings.Contains(line, templateLineMarker) {
|
||||
line = strings.ReplaceAll(line, templateOpenMarker, "{")
|
||||
line = strings.ReplaceAll(line, templateCloseMarker, "}")
|
||||
return line
|
||||
}
|
||||
return strings.Replace(line, templateLineMarker, "", 1)
|
||||
}
|
||||
|
||||
func getYamlFiles(rootpath string) ([]string, error) {
|
||||
var list []string
|
||||
err := filepath.Walk(rootpath, func(path string, info os.FileInfo, err error) error {
|
||||
if info.IsDir() {
|
||||
return nil
|
||||
}
|
||||
if filepath.Ext(path) == ".yaml" || filepath.Ext(path) == ".yml" {
|
||||
list = append(list, path)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
return list, err
|
||||
}
|
||||
@@ -215,10 +215,13 @@ func CreateResourceProviderFromPath(directory string) (*ResourceProvider, error)
|
||||
}
|
||||
|
||||
// CreateResourceProviderFromYaml returns a new ResourceProvider using the yaml
|
||||
func CreateResourceProviderFromYaml(yamlContent string) *ResourceProvider {
|
||||
func CreateResourceProviderFromYaml(yamlContent string) (*ResourceProvider, error) {
|
||||
resources := newResourceProvider("unknown", "Content", "unknown")
|
||||
resources.addResourcesFromYaml(string(yamlContent))
|
||||
return &resources
|
||||
err := resources.addResourcesFromYaml(string(yamlContent))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &resources, nil
|
||||
}
|
||||
|
||||
// CreateResourceProviderFromCluster creates a new ResourceProvider using live data from a cluster
|
||||
|
||||
+84
-62
@@ -25,14 +25,15 @@ var testCases = []struct {
|
||||
mutated string
|
||||
patch config.Mutation
|
||||
message string
|
||||
}{{
|
||||
original: oldYaml,
|
||||
patch: config.Mutation{
|
||||
Op: "add",
|
||||
Value: "Denver",
|
||||
Path: "/pets/0/owners/*/location",
|
||||
},
|
||||
mutated: `pets:
|
||||
}{
|
||||
{
|
||||
original: oldYaml,
|
||||
patch: config.Mutation{
|
||||
Op: "add",
|
||||
Value: "Denver",
|
||||
Path: "/pets/0/owners/*/location",
|
||||
},
|
||||
mutated: `pets:
|
||||
- name: fido
|
||||
owners:
|
||||
- name: Alice
|
||||
@@ -43,27 +44,27 @@ var testCases = []struct {
|
||||
location: Denver
|
||||
- name: scooby
|
||||
`,
|
||||
}, {
|
||||
original: oldYaml,
|
||||
patch: config.Mutation{
|
||||
Op: "remove",
|
||||
Path: "/pets/0/owners/*/aliases",
|
||||
},
|
||||
mutated: `pets:
|
||||
}, {
|
||||
original: oldYaml,
|
||||
patch: config.Mutation{
|
||||
Op: "remove",
|
||||
Path: "/pets/0/owners/*/aliases",
|
||||
},
|
||||
mutated: `pets:
|
||||
- name: fido
|
||||
owners:
|
||||
- name: Alice
|
||||
- name: Bob
|
||||
- name: scooby
|
||||
`,
|
||||
}, {
|
||||
original: oldYaml,
|
||||
patch: config.Mutation{
|
||||
Op: "add",
|
||||
Value: "rob",
|
||||
Path: "/pets/0/owners/*/aliases/-",
|
||||
},
|
||||
mutated: `pets:
|
||||
}, {
|
||||
original: oldYaml,
|
||||
patch: config.Mutation{
|
||||
Op: "add",
|
||||
Value: "rob",
|
||||
Path: "/pets/0/owners/*/aliases/-",
|
||||
},
|
||||
mutated: `pets:
|
||||
- name: fido
|
||||
owners:
|
||||
- name: Alice
|
||||
@@ -75,23 +76,23 @@ var testCases = []struct {
|
||||
- rob
|
||||
- name: scooby
|
||||
`,
|
||||
}, {
|
||||
original: `
|
||||
}, {
|
||||
original: `
|
||||
pets:
|
||||
- name: fido
|
||||
`,
|
||||
patch: config.Mutation{
|
||||
Op: "add",
|
||||
Value: "Alice",
|
||||
Path: "/pets/0/owners/0/name",
|
||||
},
|
||||
mutated: `pets:
|
||||
patch: config.Mutation{
|
||||
Op: "add",
|
||||
Value: "Alice",
|
||||
Path: "/pets/0/owners/0/name",
|
||||
},
|
||||
mutated: `pets:
|
||||
- name: fido
|
||||
owners:
|
||||
- name: Alice
|
||||
`,
|
||||
}, {
|
||||
original: `
|
||||
}, {
|
||||
original: `
|
||||
obj:
|
||||
foo:
|
||||
bar:
|
||||
@@ -99,54 +100,75 @@ obj:
|
||||
- b
|
||||
baz: quux
|
||||
`,
|
||||
patch: config.Mutation{
|
||||
Op: "replace",
|
||||
Value: map[string]interface{}{
|
||||
"bar": []string{"c", "d"},
|
||||
patch: config.Mutation{
|
||||
Op: "replace",
|
||||
Value: map[string]interface{}{
|
||||
"bar": []string{"c", "d"},
|
||||
},
|
||||
Path: "/obj/foo",
|
||||
},
|
||||
Path: "/obj/foo",
|
||||
},
|
||||
mutated: `obj:
|
||||
mutated: `obj:
|
||||
foo:
|
||||
bar:
|
||||
- c
|
||||
- d
|
||||
baz: quux
|
||||
`,
|
||||
}, {
|
||||
original: `
|
||||
}, {
|
||||
original: `
|
||||
foo: bar
|
||||
`,
|
||||
patch: config.Mutation{
|
||||
Op: "replace",
|
||||
Value: "baz",
|
||||
Path: "/foo",
|
||||
Comment: "# We set this to baz",
|
||||
},
|
||||
mutated: `
|
||||
patch: config.Mutation{
|
||||
Op: "replace",
|
||||
Value: "baz",
|
||||
Path: "/foo",
|
||||
Comment: "# We set this to baz",
|
||||
},
|
||||
mutated: `
|
||||
foo: baz # We set this to baz
|
||||
`,
|
||||
message: "Expected a comment to appear",
|
||||
}, {
|
||||
original: `
|
||||
message: "Expected a comment to appear",
|
||||
}, {
|
||||
original: `
|
||||
foo: bar
|
||||
`,
|
||||
patch: config.Mutation{
|
||||
Op: "add",
|
||||
Value: map[string]interface{}{
|
||||
"baz": "quux",
|
||||
patch: config.Mutation{
|
||||
Op: "add",
|
||||
Value: map[string]interface{}{
|
||||
"baz": "quux",
|
||||
},
|
||||
Path: "/extra",
|
||||
Comment: "# These are extra things",
|
||||
},
|
||||
Path: "/extra",
|
||||
Comment: "# These are extra things",
|
||||
},
|
||||
mutated: `
|
||||
mutated: `
|
||||
foo: bar
|
||||
extra:
|
||||
# These are extra things
|
||||
baz: quux
|
||||
`,
|
||||
message: "Expected a comment to appear next to an object",
|
||||
}}
|
||||
message: "Expected a comment to appear next to an object",
|
||||
},
|
||||
{
|
||||
original: `
|
||||
foo: bar
|
||||
`,
|
||||
patch: config.Mutation{
|
||||
Op: "replace",
|
||||
Value: map[string]interface{}{
|
||||
"baz": "quux",
|
||||
},
|
||||
Path: "/extra",
|
||||
Comment: "# These are extra things",
|
||||
},
|
||||
mutated: `
|
||||
foo: bar
|
||||
extra:
|
||||
# These are extra things
|
||||
baz: quux
|
||||
`,
|
||||
message: "Expected a comment to appear next to an object",
|
||||
},
|
||||
}
|
||||
|
||||
func TestApplyAllMutations(t *testing.T) {
|
||||
for _, tc := range testCases {
|
||||
|
||||
+10
-12
@@ -35,7 +35,7 @@ import (
|
||||
type schemaTestCase struct {
|
||||
Target config.TargetKind
|
||||
Resource kube.GenericResource
|
||||
IsInitContianer bool
|
||||
IsInitContainer bool
|
||||
Container *corev1.Container
|
||||
ResourceProvider *kube.ResourceProvider
|
||||
}
|
||||
@@ -80,7 +80,7 @@ func resolveCheck(conf *config.Configuration, checkID string, test schemaTestCas
|
||||
if !conf.IsActionable(check.ID, test.Resource.ObjectMeta, containerName) {
|
||||
return nil, nil
|
||||
}
|
||||
if !check.IsActionable(test.Target, test.Resource.Kind, test.IsInitContianer) {
|
||||
if !check.IsActionable(test.Target, test.Resource.Kind, test.IsInitContainer) {
|
||||
return nil, nil
|
||||
}
|
||||
templateInput, err := getTemplateInput(test)
|
||||
@@ -306,7 +306,7 @@ func applyContainerSchemaChecks(conf *config.Configuration, resources *kube.Reso
|
||||
ResourceProvider: resources,
|
||||
Resource: controller,
|
||||
Container: container,
|
||||
IsInitContianer: isInit,
|
||||
IsInitContainer: isInit,
|
||||
}
|
||||
return applySchemaChecks(conf, test)
|
||||
}
|
||||
@@ -408,15 +408,13 @@ func applySchemaCheck(conf *config.Configuration, checkID string, test schemaTes
|
||||
|
||||
}
|
||||
result := makeResult(conf, check, passes, issues)
|
||||
if !passes {
|
||||
if funk.Contains(conf.Mutations, checkID) && len(check.Mutations) > 0 {
|
||||
mutations := funk.Map(check.Mutations, func(mutation config.Mutation) config.Mutation {
|
||||
mutationCopy := deepCopyMutation(mutation)
|
||||
mutationCopy.Path = prefix + mutationCopy.Path
|
||||
return mutationCopy
|
||||
}).([]config.Mutation)
|
||||
result.Mutations = mutations
|
||||
}
|
||||
if funk.Contains(conf.Mutations, checkID) && len(check.Mutations) > 0 {
|
||||
mutations := funk.Map(check.Mutations, func(mutation config.Mutation) config.Mutation {
|
||||
mutationCopy := deepCopyMutation(mutation)
|
||||
mutationCopy.Path = prefix + mutationCopy.Path
|
||||
return mutationCopy
|
||||
}).([]config.Mutation)
|
||||
result.Mutations = mutations
|
||||
}
|
||||
return &result, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user