mirror of
https://github.com/fluxcd/flux2.git
synced 2026-02-11 02:07:30 +00:00
Add a diff kustomization feature
If implemented it will permit queriying the Kubernetes API to fetch the specified Flux Kustomization, then uses the specified path to build the overlay. It will then ssa-dry-run apply and output the diff using homeport/dyff Signed-off-by: Soule BA <soule@weave.works>
This commit is contained in:
parent
70fb87bc93
commit
9376c9a946
8 changed files with 517 additions and 29 deletions
|
|
@ -30,22 +30,23 @@ var buildKsCmd = &cobra.Command{
|
|||
Use: "kustomization",
|
||||
Aliases: []string{"ks"},
|
||||
Short: "Build Kustomization",
|
||||
Long: `The build command queries the Kubernetes API and fetches the specified Flux Kustomization,
|
||||
then it uses the specified files or path to build the overlay to write the resulting multi-doc YAML to stdout.`,
|
||||
Long: `The build command queries the Kubernetes API and fetches the specified Flux Kustomization.
|
||||
It then uses the fetched in cluster flux kustomization to perform needed transformation on the local kustomization.yaml
|
||||
pointed at by --path. The local kustomization.yaml is generated if it does not exist. Finally it builds the overlays using the local kustomization.yaml, and write the resulting multi-doc YAML to stdout.`,
|
||||
Example: `# Create a new overlay.
|
||||
flux build kustomization my-app --resources ./path/to/local/manifests`,
|
||||
flux build kustomization my-app --path ./path/to/local/manifests`,
|
||||
ValidArgsFunction: resourceNamesCompletionFunc(kustomizev1.GroupVersion.WithKind(kustomizev1.KustomizationKind)),
|
||||
RunE: buildKsCmdRun,
|
||||
}
|
||||
|
||||
type buildKsFlags struct {
|
||||
resources string
|
||||
path string
|
||||
}
|
||||
|
||||
var buildKsArgs buildKsFlags
|
||||
|
||||
func init() {
|
||||
buildKsCmd.Flags().StringVar(&buildKsArgs.resources, "resources", "", "Name of a file containing a file to add to the kustomization file.)")
|
||||
buildKsCmd.Flags().StringVar(&buildKsArgs.path, "path", "", "Path to the manifests location.)")
|
||||
buildCmd.AddCommand(buildKsCmd)
|
||||
}
|
||||
|
||||
|
|
@ -55,15 +56,15 @@ func buildKsCmdRun(cmd *cobra.Command, args []string) error {
|
|||
}
|
||||
name := args[0]
|
||||
|
||||
if buildKsArgs.resources == "" {
|
||||
return fmt.Errorf("invalid resource path %q", buildKsArgs.resources)
|
||||
if buildKsArgs.path == "" {
|
||||
return fmt.Errorf("invalid resource path %q", buildKsArgs.path)
|
||||
}
|
||||
|
||||
if fs, err := os.Stat(buildKsArgs.resources); err != nil || !fs.IsDir() {
|
||||
return fmt.Errorf("invalid resource path %q", buildKsArgs.resources)
|
||||
if fs, err := os.Stat(buildKsArgs.path); err != nil || !fs.IsDir() {
|
||||
return fmt.Errorf("invalid resource path %q", buildKsArgs.path)
|
||||
}
|
||||
|
||||
builder, err := kustomization.NewBuilder(rootArgs.kubeconfig, rootArgs.kubecontext, rootArgs.namespace, name, buildKsArgs.resources, kustomization.WithTimeout(rootArgs.timeout))
|
||||
builder, err := kustomization.NewBuilder(rootArgs.kubeconfig, rootArgs.kubecontext, rootArgs.namespace, name, buildKsArgs.path, kustomization.WithTimeout(rootArgs.timeout))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
31
cmd/flux/diff.go
Normal file
31
cmd/flux/diff.go
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
Copyright 2021 The Flux authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var diffCmd = &cobra.Command{
|
||||
Use: "diff",
|
||||
Short: "Diff a flux resource",
|
||||
Long: "The diff command is used to do a server-side dry-run on flux resources, then output the diff.",
|
||||
}
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(diffCmd)
|
||||
}
|
||||
77
cmd/flux/diff_kustomization.go
Normal file
77
cmd/flux/diff_kustomization.go
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
Copyright 2021 The Flux authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/fluxcd/flux2/internal/kustomization"
|
||||
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta2"
|
||||
)
|
||||
|
||||
var diffKsCmd = &cobra.Command{
|
||||
Use: "kustomization",
|
||||
Aliases: []string{"ks"},
|
||||
Short: "Diff Kustomization",
|
||||
Long: `The diff command does a build, then it performs a server-side dry-run and output the diff.`,
|
||||
Example: `# Create a new overlay.
|
||||
flux diff kustomization my-app --path ./path/to/local/manifests`,
|
||||
ValidArgsFunction: resourceNamesCompletionFunc(kustomizev1.GroupVersion.WithKind(kustomizev1.KustomizationKind)),
|
||||
RunE: diffKsCmdRun,
|
||||
}
|
||||
|
||||
type diffKsFlags struct {
|
||||
path string
|
||||
}
|
||||
|
||||
var diffKsArgs diffKsFlags
|
||||
|
||||
func init() {
|
||||
diffKsCmd.Flags().StringVar(&diffKsArgs.path, "path", "", "Name of a file containing a file to add to the kustomization file.)")
|
||||
diffCmd.AddCommand(diffKsCmd)
|
||||
}
|
||||
|
||||
func diffKsCmdRun(cmd *cobra.Command, args []string) error {
|
||||
if len(args) < 1 {
|
||||
return fmt.Errorf("%s name is required", kustomizationType.humanKind)
|
||||
}
|
||||
name := args[0]
|
||||
|
||||
if diffKsArgs.path == "" {
|
||||
return fmt.Errorf("invalid resource path %q", diffKsArgs.path)
|
||||
}
|
||||
|
||||
if fs, err := os.Stat(diffKsArgs.path); err != nil || !fs.IsDir() {
|
||||
return fmt.Errorf("invalid resource path %q", diffKsArgs.path)
|
||||
}
|
||||
|
||||
builder, err := kustomization.NewBuilder(rootArgs.kubeconfig, rootArgs.kubecontext, rootArgs.namespace, name, diffKsArgs.path, kustomization.WithTimeout(rootArgs.timeout))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = builder.Diff()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
}
|
||||
27
go.mod
27
go.mod
|
|
@ -12,6 +12,7 @@ require (
|
|||
github.com/fluxcd/image-reflector-controller/api v0.15.0
|
||||
github.com/fluxcd/kustomize-controller/api v0.19.1
|
||||
github.com/fluxcd/notification-controller/api v0.20.1
|
||||
github.com/fluxcd/pkg/apis/kustomize v0.3.1
|
||||
github.com/fluxcd/pkg/apis/meta v0.10.2
|
||||
github.com/fluxcd/pkg/runtime v0.12.3
|
||||
github.com/fluxcd/pkg/ssa v0.10.0
|
||||
|
|
@ -20,9 +21,13 @@ require (
|
|||
github.com/fluxcd/pkg/version v0.0.1
|
||||
github.com/fluxcd/source-controller/api v0.20.1
|
||||
github.com/go-git/go-git/v5 v5.4.2
|
||||
github.com/gonvenience/bunt v1.3.2
|
||||
github.com/gonvenience/ytbx v1.4.2
|
||||
github.com/google/go-cmp v0.5.6
|
||||
github.com/google/go-containerregistry v0.2.0
|
||||
github.com/hashicorp/go-retryablehttp v0.7.0 // indirect
|
||||
github.com/homeport/dyff v1.4.6
|
||||
github.com/lucasb-eyer/go-colorful v1.2.0
|
||||
github.com/manifoldco/promptui v0.9.0
|
||||
github.com/mattn/go-shellwords v1.0.12
|
||||
github.com/olekukonko/tablewriter v0.0.4
|
||||
|
|
@ -42,6 +47,11 @@ require (
|
|||
sigs.k8s.io/yaml v1.3.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/drone/envsubst v1.0.3
|
||||
sigs.k8s.io/kustomize/kyaml v0.13.0
|
||||
)
|
||||
|
||||
require (
|
||||
cloud.google.com/go v0.81.0 // indirect
|
||||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
|
||||
|
|
@ -51,6 +61,7 @@ require (
|
|||
github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect
|
||||
github.com/Azure/go-autorest/logger v0.2.1 // indirect
|
||||
github.com/Azure/go-autorest/tracing v0.6.0 // indirect
|
||||
github.com/BurntSushi/toml v0.4.1 // indirect
|
||||
github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd // indirect
|
||||
github.com/Microsoft/go-winio v0.4.16 // indirect
|
||||
github.com/PuerkitoBio/purell v1.1.1 // indirect
|
||||
|
|
@ -64,7 +75,6 @@ require (
|
|||
github.com/evanphx/json-patch v4.12.0+incompatible // indirect
|
||||
github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d // indirect
|
||||
github.com/fluxcd/pkg/apis/acl v0.0.3 // indirect
|
||||
github.com/fluxcd/pkg/apis/kustomize v0.3.1 // indirect
|
||||
github.com/form3tech-oss/jwt-go v3.2.3+incompatible // indirect
|
||||
github.com/fvbommel/sortorder v1.0.1 // indirect
|
||||
github.com/go-errors/errors v1.0.1 // indirect
|
||||
|
|
@ -76,6 +86,10 @@ require (
|
|||
github.com/go-openapi/swag v0.19.14 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
github.com/gonvenience/neat v1.3.7 // indirect
|
||||
github.com/gonvenience/term v1.0.1 // indirect
|
||||
github.com/gonvenience/text v1.0.6 // indirect
|
||||
github.com/gonvenience/wrap v1.1.0 // indirect
|
||||
github.com/google/btree v1.0.1 // indirect
|
||||
github.com/google/go-github/v41 v41.0.0 // indirect
|
||||
github.com/google/go-querystring v1.1.0 // indirect
|
||||
|
|
@ -87,7 +101,6 @@ require (
|
|||
github.com/hashicorp/errwrap v1.0.0 // indirect
|
||||
github.com/hashicorp/go-cleanhttp v0.5.1 // indirect
|
||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||
github.com/hashicorp/go-retryablehttp v0.6.8 // indirect
|
||||
github.com/imdario/mergo v0.3.12 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.0.0 // indirect
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
|
||||
|
|
@ -96,9 +109,13 @@ require (
|
|||
github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 // indirect
|
||||
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect
|
||||
github.com/mailru/easyjson v0.7.6 // indirect
|
||||
github.com/mattn/go-ciede2000 v0.0.0-20170301095244-782e8c62fec3 // indirect
|
||||
github.com/mattn/go-isatty v0.0.14 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.7 // indirect
|
||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||
github.com/mitchellh/go-ps v1.0.0 // indirect
|
||||
github.com/mitchellh/go-wordwrap v1.0.0 // indirect
|
||||
github.com/mitchellh/hashstructure v1.1.0 // indirect
|
||||
github.com/moby/spdystream v0.2.0 // indirect
|
||||
github.com/moby/term v0.0.0-20210610120745-9d4ed1856297 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
|
|
@ -109,15 +126,18 @@ require (
|
|||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/russross/blackfriday v1.5.2 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.0.1 // indirect
|
||||
github.com/sergi/go-diff v1.1.0 // indirect
|
||||
github.com/sergi/go-diff v1.2.0 // indirect
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect
|
||||
github.com/stretchr/testify v1.7.0 // indirect
|
||||
github.com/texttheater/golang-levenshtein v1.0.1 // indirect
|
||||
github.com/virtuald/go-ordered-json v0.0.0-20170621173500-b18e6e673d74 // indirect
|
||||
github.com/xanzy/go-gitlab v0.54.3 // indirect
|
||||
github.com/xanzy/ssh-agent v0.3.0 // indirect
|
||||
github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca // indirect
|
||||
go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 // indirect
|
||||
golang.org/x/net v0.0.0-20211216030914-fe4d6282115f // indirect
|
||||
golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f // indirect
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
|
||||
golang.org/x/sys v0.0.0-20211029165221-6e7872819dc8 // indirect
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect
|
||||
|
|
@ -132,7 +152,6 @@ require (
|
|||
k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65 // indirect
|
||||
k8s.io/utils v0.0.0-20211208161948-7d6a63dca704 // indirect
|
||||
sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2 // indirect
|
||||
sigs.k8s.io/kustomize/kyaml v0.13.0 // indirect
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.2.0 // indirect
|
||||
)
|
||||
|
||||
|
|
|
|||
63
go.sum
63
go.sum
|
|
@ -78,6 +78,8 @@ github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbt
|
|||
github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo=
|
||||
github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/toml v0.4.1 h1:GaI7EiDXDRfa8VshkTj7Fym7ha+y8/XxIgD2okUIjLw=
|
||||
github.com/BurntSushi/toml v0.4.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/GoogleCloudPlatform/k8s-cloud-provider v0.0.0-20190822182118-27a4ced34534/go.mod h1:iroGtC8B3tQiqtds1l+mgk/BBOrxbqjH+eUfFQYRc14=
|
||||
github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd h1:sjQovDkwrZp8u+gxLtPgKGjk5hCxuy2hrRejBTA9xFU=
|
||||
|
|
@ -192,8 +194,8 @@ github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5Xh
|
|||
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||
github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM=
|
||||
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
|
||||
github.com/drone/envsubst v1.0.3-0.20200804185402-58bc65f69603 h1:PMzPM0wCHDrXlO7TlEq5lqlhGKHEgSnUR4YMSEVKrQ0=
|
||||
github.com/drone/envsubst v1.0.3-0.20200804185402-58bc65f69603/go.mod h1:N2jZmlMufstn1KEqvbHjw40h1KyTmnVzHcSc9bFiJ2g=
|
||||
github.com/drone/envsubst v1.0.3 h1:PCIBwNDYjs50AsLZPYdfhSATKaRg/FJmDc2D6+C2x8g=
|
||||
github.com/drone/envsubst v1.0.3/go.mod h1:N2jZmlMufstn1KEqvbHjw40h1KyTmnVzHcSc9bFiJ2g=
|
||||
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153 h1:yUdfgN0XgIJw7foRItutHYUIhlcKzcSf5vDpdhQAKTc=
|
||||
|
|
@ -361,6 +363,22 @@ github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx
|
|||
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/golangplus/testing v0.0.0-20180327235837-af21d9c3145e/go.mod h1:0AA//k/eakGydO4jKRoRL2j92ZKSzTgj9tclaCrvXHk=
|
||||
github.com/gonvenience/bunt v1.1.3/go.mod h1:hZ898ZprNWgaVlq4s1ivsJu3AY+3wrlJadF5Gp7Yq2c=
|
||||
github.com/gonvenience/bunt v1.3.1/go.mod h1:G+d3dJBxxOqV2oca96psgAnPABVC9QptEifjVqPu+mo=
|
||||
github.com/gonvenience/bunt v1.3.2 h1:gDiyTDfPf87fCtIbFzvENrmlnDZYbENdhhRW2kun/tw=
|
||||
github.com/gonvenience/bunt v1.3.2/go.mod h1:oTOZqb1TVL1KqZm57zUCJCiwUliNfY8+d3QndOVqxpg=
|
||||
github.com/gonvenience/neat v1.3.6/go.mod h1:wv0eXmvwFfpuS5bpf2fIofXQvf8W7HTdSzKfGCYbIe8=
|
||||
github.com/gonvenience/neat v1.3.7 h1:k4shy3sgSBfUk9LTN51naxVIkB6BlGaxH0ReERO92zw=
|
||||
github.com/gonvenience/neat v1.3.7/go.mod h1:Y4eeQH3GEBvjmLoMiu4oWGyOopGDaI2/y2jwcVfvlvs=
|
||||
github.com/gonvenience/term v1.0.0/go.mod h1:wohD4Iqso9Eol7qc2VnNhSFFhZxok5PvO7pZhdrAn4E=
|
||||
github.com/gonvenience/term v1.0.1 h1:8bg2O0ox0Ss64nnUxW5AXlSHhllc8dTOSKuKu6uoGpw=
|
||||
github.com/gonvenience/term v1.0.1/go.mod h1:TrQEhxBNE/ng5kTV+S0OvQowTDJSfhlBeZbcOmTR6qI=
|
||||
github.com/gonvenience/text v1.0.6 h1:9JH9fz0BL0NX4uKmjLuVcsBKiniPa+XLpf8KH9so44U=
|
||||
github.com/gonvenience/text v1.0.6/go.mod h1:9U5WbkT/5wR5+aNMR4HucamY+HgVMEn+UbF78XHmUio=
|
||||
github.com/gonvenience/wrap v1.1.0 h1:d8gEZrXS/zg4BC1q0U4nHpPIh5k6muKpQ1+rQFBwpYc=
|
||||
github.com/gonvenience/wrap v1.1.0/go.mod h1:L47Cm1sK1G8QmFAYQfkHcF/sQ1IBJUa0u4sjqiLqPdM=
|
||||
github.com/gonvenience/ytbx v1.4.2 h1:fpgOpsQ+gwTPqiatki0aY7q3BEjt7EcwiI5b+D0Qjvg=
|
||||
github.com/gonvenience/ytbx v1.4.2/go.mod h1:GkUMPGH5qZSg1S8L6u9XNI9hJ4L1yKSQFIA4J8vaPdY=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4=
|
||||
|
|
@ -424,6 +442,7 @@ github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97Dwqy
|
|||
github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
|
||||
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
||||
github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||
|
|
@ -468,6 +487,8 @@ github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO
|
|||
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
|
||||
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
|
||||
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
|
||||
github.com/homeport/dyff v1.4.6 h1:ReC8Hi1I6SkmPmNOqGl9EUlZctx+6AloCzSulqwHge8=
|
||||
github.com/homeport/dyff v1.4.6/go.mod h1:DBCaTwJUIQLNQxNOKTce/OgRxCwwa8erBdN88bBfb9Y=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
|
|
@ -526,6 +547,9 @@ github.com/ktrysmt/go-bitbucket v0.9.34/go.mod h1:FWxy2UK7GlK5b0NSJGc5hPqnssVlkN
|
|||
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0=
|
||||
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE=
|
||||
github.com/lithammer/dedent v1.1.0/go.mod h1:jrXYCQtgg0nJiN+StA2KgR7w6CiQNv9Fd/Z9BP0jIOc=
|
||||
github.com/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
|
||||
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
|
||||
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
|
||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
|
||||
|
|
@ -539,9 +563,15 @@ github.com/manifoldco/promptui v0.9.0 h1:3V4HzJk1TtXW1MTZMP7mdlwbBpIinw3HztaIlYt
|
|||
github.com/manifoldco/promptui v0.9.0/go.mod h1:ka04sppxSGFAtxX0qhlYQjISsg9mR4GWtQEhdbn6Pgg=
|
||||
github.com/matryer/is v1.2.0 h1:92UTHpy8CDwaJ08GqLDzhhuixiBUUD1p3AU6PHddz4A=
|
||||
github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA=
|
||||
github.com/mattn/go-ciede2000 v0.0.0-20170301095244-782e8c62fec3 h1:BXxTozrOU8zgC5dkpn3J6NTRdoP+hjok/e+ACr4Hibk=
|
||||
github.com/mattn/go-ciede2000 v0.0.0-20170301095244-782e8c62fec3/go.mod h1:x1uk6vxTiVuNt6S5R2UYgdhpj3oKojXvOXauHZ7dEnI=
|
||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
|
||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||
github.com/mattn/go-runewidth v0.0.7 h1:Ei8KR0497xHyKJPAv59M1dkC+rOZCMBJ+t3fZ+twI54=
|
||||
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
|
|
@ -556,10 +586,15 @@ github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceT
|
|||
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/go-ps v0.0.0-20170309133038-4fdf99ab2936/go.mod h1:r1VsdOzOPt1ZSrGZWFoNhsAedKnEd6r9Np1+5blZCWk=
|
||||
github.com/mitchellh/go-ps v1.0.0 h1:i6ampVEEF4wQFF+bkYfwYgY+F/uYJDktmvLPf7qIgjc=
|
||||
github.com/mitchellh/go-ps v1.0.0/go.mod h1:J4lOc8z8yJs6vUwklHw2XEIiT4z4C40KtWVN3nvg8Pg=
|
||||
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
|
||||
github.com/mitchellh/go-wordwrap v1.0.0 h1:6GlHJ/LTGMrIJbwgdqdl2eEH8o+Exx/0m8ir9Gns0u4=
|
||||
github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
|
||||
github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
|
||||
github.com/mitchellh/hashstructure v1.1.0 h1:P6P1hdjqAAknpY/M1CGipelZgp+4y9ja9kmUZPXP+H0=
|
||||
github.com/mitchellh/hashstructure v1.1.0/go.mod h1:xUDAozZz0Wmdiufv0uyhnHkUTN6/6d8ulp4AwfLKrmA=
|
||||
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
|
||||
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mitchellh/mapstructure v0.0.0-20180220230111-00c29f56e238/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
|
|
@ -600,6 +635,11 @@ github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+
|
|||
github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg=
|
||||
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
|
||||
github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
|
||||
github.com/onsi/ginkgo v1.14.2/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
|
||||
github.com/onsi/ginkgo v1.15.0/go.mod h1:hF8qUzuuC8DJGygJH3726JnCZX4MYbRB8yFfISqnKUg=
|
||||
github.com/onsi/ginkgo v1.15.1/go.mod h1:Dd6YFfwBW84ETqqtL0CPyPXillHgY6XhQH3uuCCTr/o=
|
||||
github.com/onsi/ginkgo v1.15.2/go.mod h1:Dd6YFfwBW84ETqqtL0CPyPXillHgY6XhQH3uuCCTr/o=
|
||||
github.com/onsi/ginkgo v1.16.2/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E=
|
||||
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
|
||||
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
|
||||
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
|
||||
|
|
@ -609,6 +649,10 @@ github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1Cpa
|
|||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||
github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA=
|
||||
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
||||
github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc=
|
||||
github.com/onsi/gomega v1.10.5/go.mod h1:gza4q3jKQJijlu05nKWRCW/GavJumGt8aNRxWg7mt48=
|
||||
github.com/onsi/gomega v1.11.0/go.mod h1:azGKhqFUon9Vuj0YmTfLSmx0FUwqXYSTl5re8lQLTUg=
|
||||
github.com/onsi/gomega v1.12.0/go.mod h1:lRk9szgn8TxENtWd0Tp4c3wjlRfMTMH27I+3Je41yGY=
|
||||
github.com/onsi/gomega v1.15.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+tEHG0=
|
||||
github.com/onsi/gomega v1.16.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
|
||||
github.com/onsi/gomega v1.17.0 h1:9Luw4uT5HTjHTN8+aNcSThgH1vdXnmdJ8xIfZ4wyTRE=
|
||||
|
|
@ -670,8 +714,9 @@ github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb
|
|||
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
||||
github.com/sclevine/spec v1.2.0/go.mod h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24q7p+U=
|
||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
||||
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
|
||||
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
||||
github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ=
|
||||
github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
|
|
@ -720,12 +765,16 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
|
|||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
||||
github.com/texttheater/golang-levenshtein v1.0.1 h1:+cRNoVrfiwufQPhoMzB6N0Yf/Mqajr6t1lOv8GyGE2U=
|
||||
github.com/texttheater/golang-levenshtein v1.0.1/go.mod h1:PYAKrbF5sAiq9wd+H82hs7gNaen0CplQ9uvm6+enD/8=
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
|
||||
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
|
||||
github.com/vdemeester/k8s-pkg-credentialprovider v1.18.1-0.20201019120933-f1d16962a4db/go.mod h1:grWy0bkr1XO6hqbaaCKaPXqkBVlMGHYG6PGykktwbJc=
|
||||
github.com/virtuald/go-ordered-json v0.0.0-20170621173500-b18e6e673d74 h1:JwtAtbp7r/7QSyGz8mKUbYJBg2+6Cd7OjM8o/GNOcVo=
|
||||
github.com/virtuald/go-ordered-json v0.0.0-20170621173500-b18e6e673d74/go.mod h1:RmMWU37GKR2s6pgrIEB4ixgpVCt/cf7dnJv3fuH1J1c=
|
||||
github.com/vmware/govmomi v0.20.3/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU=
|
||||
github.com/xanzy/go-gitlab v0.54.3 h1:fPfZ3Jcu5dPc3xyIYtAALZsEgoyKNFNuULD+TdJ7Zvk=
|
||||
github.com/xanzy/go-gitlab v0.54.3/go.mod h1:F0QEXwmqiBUxCgJm8fE9S+1veX4XC9Z4cfaAbqwk4YM=
|
||||
|
|
@ -865,6 +914,7 @@ golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/
|
|||
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
|
|
@ -880,6 +930,7 @@ golang.org/x/net v0.0.0-20210520170846-37e1c6afe023/go.mod h1:9nx3DQGgdP8bBQD5qx
|
|||
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210825183410-e898025ed96a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210917163549-3c21e5b27794/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211215060638-4ddde0e984e9/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
|
|
@ -912,6 +963,7 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ
|
|||
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180224232135-f6cff0780e54/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
|
|
@ -925,6 +977,7 @@ golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5h
|
|||
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
|
|
@ -948,6 +1001,7 @@ golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
|
|
@ -990,11 +1044,14 @@ golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210817190340-bfb29a6856f2/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210917161153-d61c044b1678/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211029165221-6e7872819dc8 h1:M69LAlWZCshgp0QSzyDcSsSIejIEeuaCVpmwcKwyLMk=
|
||||
golang.org/x/sys v0.0.0-20211029165221-6e7872819dc8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.0.0-20210916214954-140adaaadfaf/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
|
|
|
|||
|
|
@ -27,8 +27,10 @@ import (
|
|||
|
||||
"github.com/fluxcd/flux2/internal/utils"
|
||||
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta2"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client/apiutil"
|
||||
"sigs.k8s.io/kustomize/api/konfig"
|
||||
"sigs.k8s.io/kustomize/api/resmap"
|
||||
"sigs.k8s.io/kustomize/api/resource"
|
||||
|
|
@ -44,6 +46,7 @@ var defaultTimeout = 80 * time.Second
|
|||
// and overlays the manifests with the resources specified in the resourcesPath
|
||||
type Builder struct {
|
||||
client client.WithWatch
|
||||
restMapper meta.RESTMapper
|
||||
name string
|
||||
namespace string
|
||||
resourcesPath string
|
||||
|
|
@ -68,8 +71,18 @@ func NewBuilder(kubeconfig string, kubecontext string, namespace, name, resource
|
|||
return nil, err
|
||||
}
|
||||
|
||||
cfg, err := utils.KubeConfig(kubeconfig, kubecontext)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
restMapper, err := apiutil.NewDynamicRESTMapper(cfg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
b := &Builder{
|
||||
client: kubeClient,
|
||||
restMapper: restMapper,
|
||||
name: name,
|
||||
namespace: namespace,
|
||||
resourcesPath: resources,
|
||||
|
|
@ -154,8 +167,8 @@ func (b *Builder) build() (resmap.ResMap, error) {
|
|||
// store the kustomization object
|
||||
b.kustomization = k
|
||||
|
||||
// restore the kustomization.yaml
|
||||
err = restore(saved, b.resourcesPath)
|
||||
// overwrite the kustomization.yaml to make sure it's clean
|
||||
err = overwrite(saved, b.resourcesPath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to restore kustomization.yaml: %w", err)
|
||||
}
|
||||
|
|
@ -205,24 +218,27 @@ func trimSopsData(res *resource.Resource) error {
|
|||
for k, v := range dataMap {
|
||||
data, err := base64.StdEncoding.DecodeString(v)
|
||||
if err != nil {
|
||||
fmt.Println(fmt.Errorf("failed to decode secret data: %w", err))
|
||||
if _, ok := err.(base64.CorruptInputError); ok {
|
||||
return fmt.Errorf("failed to decode secret data: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
if bytes.Contains(data, []byte("sops")) {
|
||||
if bytes.Contains(data, []byte("sops")) && bytes.Contains(data, []byte("ENC[")) {
|
||||
dataMap[k] = sopsMess
|
||||
}
|
||||
}
|
||||
|
||||
res.SetDataMap(dataMap)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func restore(saved []byte, dirPath string) error {
|
||||
func overwrite(saved []byte, dirPath string) error {
|
||||
kfile := filepath.Join(dirPath, konfig.DefaultKustomizationFileName())
|
||||
err := os.WriteFile(kfile, saved, 0644)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to restore kustomization.yaml: %w", err)
|
||||
return fmt.Errorf("failed to overwrite kustomization.yaml: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ import (
|
|||
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||
)
|
||||
|
||||
func TestSanitizeResources(t *testing.T) {
|
||||
func TestTrimSopsData(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
yamlStr string
|
||||
|
|
@ -75,18 +75,18 @@ type: Opaque
|
|||
{
|
||||
name: "secret with basic auth",
|
||||
yamlStr: `apiVersion: v1
|
||||
data:
|
||||
password: cGFzc3dvcmQK
|
||||
username: YWRtaW4K
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: secret-basic-auth
|
||||
type: kubernetes.io/basic-auth
|
||||
data:
|
||||
username: admin
|
||||
password: password
|
||||
`,
|
||||
expected: `apiVersion: v1
|
||||
data:
|
||||
password: password
|
||||
username: admin
|
||||
password: cGFzc3dvcmQK
|
||||
username: YWRtaW4K
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: secret-basic-auth
|
||||
|
|
|
|||
287
internal/kustomization/diff.go
Normal file
287
internal/kustomization/diff.go
Normal file
|
|
@ -0,0 +1,287 @@
|
|||
package kustomization
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta2"
|
||||
"github.com/fluxcd/pkg/ssa"
|
||||
"github.com/gonvenience/bunt"
|
||||
"github.com/gonvenience/ytbx"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/homeport/dyff/pkg/dyff"
|
||||
"github.com/lucasb-eyer/go-colorful"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"sigs.k8s.io/cli-utils/pkg/kstatus/polling"
|
||||
"sigs.k8s.io/cli-utils/pkg/object"
|
||||
"sigs.k8s.io/yaml"
|
||||
)
|
||||
|
||||
const (
|
||||
controllerName = "kustomize-controller"
|
||||
controllerGroup = "kustomize.toolkit.fluxcd.io"
|
||||
)
|
||||
|
||||
func (b *Builder) manager() (*ssa.ResourceManager, error) {
|
||||
statusPoller := polling.NewStatusPoller(b.client, b.restMapper)
|
||||
owner := ssa.Owner{
|
||||
Field: controllerName,
|
||||
Group: controllerGroup,
|
||||
}
|
||||
|
||||
return ssa.NewResourceManager(b.client, statusPoller, owner), nil
|
||||
}
|
||||
|
||||
func (b *Builder) Diff() error {
|
||||
res, err := b.Build()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// convert the build result into Kubernetes unstructured objects
|
||||
objects, err := ssa.ReadObjects(bytes.NewReader(res))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
resourceManager, err := b.manager()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
resourceManager.SetOwnerLabels(objects, b.kustomization.GetName(), b.kustomization.GetNamespace())
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), b.timeout)
|
||||
defer cancel()
|
||||
|
||||
if err := ssa.SetNativeKindsDefaults(objects); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// create an inventory of objects to be reconciled
|
||||
newInventory := newInventory()
|
||||
for _, obj := range objects {
|
||||
change, liveObject, mergedObject, err := resourceManager.Diff(ctx, obj)
|
||||
if err != nil {
|
||||
if b.kustomization.Spec.Force && strings.Contains(err.Error(), "immutable") {
|
||||
writeString(fmt.Sprintf("► %s created", obj.GetName()), bunt.Green)
|
||||
} else {
|
||||
writeString(fmt.Sprint(`✗`, err), bunt.Red)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// if the object is a sops secret, we need to
|
||||
// make sure we diff only if the keys are different
|
||||
if obj.GetKind() == "Secret" && change.Action == string(ssa.ConfiguredAction) {
|
||||
diffSopsSecret(obj, liveObject, mergedObject, change)
|
||||
}
|
||||
|
||||
if change.Action == string(ssa.CreatedAction) {
|
||||
writeString(fmt.Sprintf("► %s created", change.Subject), bunt.Green)
|
||||
}
|
||||
|
||||
if change.Action == string(ssa.ConfiguredAction) {
|
||||
writeString(fmt.Sprintf("► %s drifted", change.Subject), bunt.WhiteSmoke)
|
||||
liveFile, mergedFile, tmpDir, err := writeYamls(liveObject, mergedObject)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cleanupDir(tmpDir)
|
||||
|
||||
err = diff(liveFile, mergedFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
addObjectsToInventory(newInventory, change)
|
||||
}
|
||||
|
||||
if b.kustomization.Spec.Prune {
|
||||
oldStatus := b.kustomization.Status.DeepCopy()
|
||||
if oldStatus.Inventory != nil {
|
||||
diffObjects, err := diffInventory(oldStatus.Inventory, newInventory)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, object := range diffObjects {
|
||||
writeString(fmt.Sprintf("► %s deleted", ssa.FmtUnstructured(object)), bunt.OrangeRed)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func writeYamls(liveObject, mergedObject *unstructured.Unstructured) (string, string, string, error) {
|
||||
tmpDir, err := os.MkdirTemp("", "")
|
||||
if err != nil {
|
||||
return "", "", "", err
|
||||
}
|
||||
|
||||
liveYAML, _ := yaml.Marshal(liveObject)
|
||||
liveFile := filepath.Join(tmpDir, "live.yaml")
|
||||
if err := os.WriteFile(liveFile, liveYAML, 0644); err != nil {
|
||||
return "", "", "", err
|
||||
}
|
||||
|
||||
mergedYAML, _ := yaml.Marshal(mergedObject)
|
||||
mergedFile := filepath.Join(tmpDir, "merged.yaml")
|
||||
if err := os.WriteFile(mergedFile, mergedYAML, 0644); err != nil {
|
||||
return "", "", "", err
|
||||
}
|
||||
|
||||
return liveFile, mergedFile, tmpDir, nil
|
||||
}
|
||||
|
||||
func writeString(t string, color colorful.Color) {
|
||||
fmt.Println(bunt.Style(
|
||||
t,
|
||||
bunt.EachLine(),
|
||||
bunt.Foreground(color),
|
||||
))
|
||||
}
|
||||
|
||||
func cleanupDir(dir string) error {
|
||||
return os.RemoveAll(dir)
|
||||
}
|
||||
|
||||
func diff(liveFile, mergedFile string) error {
|
||||
from, to, err := ytbx.LoadFiles(liveFile, mergedFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to load input files: %w", err)
|
||||
}
|
||||
|
||||
report, err := dyff.CompareInputFiles(from, to,
|
||||
dyff.IgnoreOrderChanges(false),
|
||||
dyff.KubernetesEntityDetection(true),
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to compare input files: %w", err)
|
||||
}
|
||||
|
||||
reportWriter := &dyff.HumanReport{
|
||||
Report: report,
|
||||
OmitHeader: true,
|
||||
}
|
||||
|
||||
if err := reportWriter.WriteReport(os.Stdout); err != nil {
|
||||
return fmt.Errorf("failed to print report: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func diffSopsSecret(obj, liveObject, mergedObject *unstructured.Unstructured, change *ssa.ChangeSetEntry) {
|
||||
data := obj.Object["data"]
|
||||
for _, v := range data.(map[string]interface{}) {
|
||||
v, err := base64.StdEncoding.DecodeString(v.(string))
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
if bytes.Contains(v, []byte(mask)) {
|
||||
if liveObject != nil && mergedObject != nil {
|
||||
change.Action = string(ssa.UnchangedAction)
|
||||
dataLive := liveObject.Object["data"].(map[string]interface{})
|
||||
dataMerged := mergedObject.Object["data"].(map[string]interface{})
|
||||
if cmp.Diff(keys(dataLive), keys(dataMerged)) != "" {
|
||||
change.Action = string(ssa.ConfiguredAction)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func keys(m map[string]interface{}) []string {
|
||||
keys := make([]string, len(m))
|
||||
i := 0
|
||||
for k := range m {
|
||||
keys[i] = k
|
||||
i++
|
||||
}
|
||||
return keys
|
||||
}
|
||||
|
||||
// diffInventory returns the slice of objects that do not exist in the target inventory.
|
||||
func diffInventory(inv *kustomizev1.ResourceInventory, target *kustomizev1.ResourceInventory) ([]*unstructured.Unstructured, error) {
|
||||
versionOf := func(i *kustomizev1.ResourceInventory, objMetadata object.ObjMetadata) string {
|
||||
for _, entry := range i.Entries {
|
||||
if entry.ID == objMetadata.String() {
|
||||
return entry.Version
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
objects := make([]*unstructured.Unstructured, 0)
|
||||
aList, err := listMetaInInventory(inv)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
bList, err := listMetaInInventory(target)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
list := aList.Diff(bList)
|
||||
if len(list) == 0 {
|
||||
return objects, nil
|
||||
}
|
||||
|
||||
for _, metadata := range list {
|
||||
u := &unstructured.Unstructured{}
|
||||
u.SetGroupVersionKind(schema.GroupVersionKind{
|
||||
Group: metadata.GroupKind.Group,
|
||||
Kind: metadata.GroupKind.Kind,
|
||||
Version: versionOf(inv, metadata),
|
||||
})
|
||||
u.SetName(metadata.Name)
|
||||
u.SetNamespace(metadata.Namespace)
|
||||
objects = append(objects, u)
|
||||
}
|
||||
|
||||
sort.Sort(ssa.SortableUnstructureds(objects))
|
||||
return objects, nil
|
||||
}
|
||||
|
||||
// listMetaInInventory returns the inventory entries as object.ObjMetadata objects.
|
||||
func listMetaInInventory(inv *kustomizev1.ResourceInventory) (object.ObjMetadataSet, error) {
|
||||
var metas []object.ObjMetadata
|
||||
for _, e := range inv.Entries {
|
||||
m, err := object.ParseObjMetadata(e.ID)
|
||||
if err != nil {
|
||||
return metas, err
|
||||
}
|
||||
metas = append(metas, m)
|
||||
}
|
||||
|
||||
return metas, nil
|
||||
}
|
||||
|
||||
func newInventory() *kustomizev1.ResourceInventory {
|
||||
return &kustomizev1.ResourceInventory{
|
||||
Entries: []kustomizev1.ResourceRef{},
|
||||
}
|
||||
}
|
||||
|
||||
// addObjectsToInventory extracts the metadata from the given objects and adds it to the inventory.
|
||||
func addObjectsToInventory(inv *kustomizev1.ResourceInventory, entry *ssa.ChangeSetEntry) error {
|
||||
if entry == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
inv.Entries = append(inv.Entries, kustomizev1.ResourceRef{
|
||||
ID: entry.ObjMetadata.String(),
|
||||
Version: entry.GroupVersion,
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
Loading…
Reference in a new issue