1
0
mirror of synced 2026-03-02 03:26:57 +00:00

Compare commits

...

14 Commits

Author SHA1 Message Date
Stefan Prodan
4b4e6b1be3 Merge pull request #2382 from SomtochiAma/commit-sha
Use `client.Patch` for suspend/resume operations
2022-02-04 13:39:52 +02:00
Somtochi Onyekwere
d3d271defe use client.Patch for suspend/resume operations
Signed-off-by: Somtochi Onyekwere <somtochionyekwere@gmail.com>
2022-02-04 12:06:39 +01:00
Stefan Prodan
9bddabf4ff Merge pull request #2380 from souleb/fix-panic-orgref-var
Fix panic on bootstrap when orgRef is not retrieved
2022-02-04 10:29:26 +02:00
Soule BA
959ea6875a Fix panic on bootstrap when orgRef is not retrieved
If implemented, not retrieving an orgRef will always return an error

Signed-off-by: Soule BA <soule@weave.works>
2022-02-04 09:08:38 +01:00
Stefan Prodan
7b7eb011b0 Merge pull request #2377 from souleb/issue-2363
Fix `flux build/diff` when parsing SOPS encrypted secrets
2022-02-04 10:06:14 +02:00
Soule BA
997e6be3a2 Make sure to trim all sops data
If implemented this fixes #2363 and make sure we can build with sops
encrypted data

Signed-off-by: Soule BA <soule@weave.works>
2022-02-04 08:38:29 +01:00
Stefan Prodan
51af4bbf52 Merge pull request #2364 from robwittman/rwittman/add-github-gpg-signing
Add GPG signing to Github/Gitlab/Bitbucket bootstrap
2022-02-04 09:26:50 +02:00
Robert Wittman
e33198e750 Replace github boostrap GPG options
Signed-off-by: Robert Wittman <robkwittman@gmail.com>
2022-02-03 11:09:10 -05:00
Robert Wittman
e3f5a8fee3 Add GPG options to Gitlab and BitBucket bootstraps
Signed-off-by: Robert Wittman <robkwittman@gmail.com>
2022-02-03 11:07:55 -05:00
Robert Wittman
f8b58f8be9 Add GPG signing to Github bootstrap
Signed-off-by: Robert Wittman <robkwittman@gmail.com>
2022-02-03 11:03:35 -05:00
Stefan Prodan
55542a8086 Merge pull request #2376 from fluxcd/fix-azure-test
e2e: Fix Azure image update automation test
2022-02-03 17:04:01 +02:00
Stefan Prodan
70c8c0445c e2e: Fix Azure image update automation test
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2022-02-03 16:38:25 +02:00
Stefan Prodan
29c0bb4ce2 Merge pull request #2375 from souleb/issue-2365
Add contextual error code for flux diff kustomization
2022-02-03 16:35:45 +02:00
Soule BA
b86b195450 Add contextual error code for flux diff kustomization
If implemented, calling the diff command on kustomization will return 0,
1(if changes are identified), >1 for errors.

Signed-off-by: Soule BA <soule@weave.works>
2022-02-03 13:41:57 +01:00
14 changed files with 137 additions and 32 deletions

View File

@@ -254,6 +254,7 @@ func bootstrapBServerCmdRun(cmd *cobra.Command, args []string) error {
bootstrap.WithKubeconfig(kubeconfigArgs),
bootstrap.WithLogger(logger),
bootstrap.WithCABundle(caBundle),
bootstrap.WithGitCommitSigning(bootstrapArgs.gpgKeyRingPath, bootstrapArgs.gpgPassphrase, bootstrapArgs.gpgKeyID),
}
if bootstrapArgs.sshHostname != "" {
bootstrapOpts = append(bootstrapOpts, bootstrap.WithSSHHostname(bootstrapArgs.sshHostname))

View File

@@ -243,6 +243,7 @@ func bootstrapGitHubCmdRun(cmd *cobra.Command, args []string) error {
bootstrap.WithKubeconfig(kubeconfigArgs),
bootstrap.WithLogger(logger),
bootstrap.WithCABundle(caBundle),
bootstrap.WithGitCommitSigning(bootstrapArgs.gpgKeyRingPath, bootstrapArgs.gpgPassphrase, bootstrapArgs.gpgKeyID),
}
if bootstrapArgs.sshHostname != "" {
bootstrapOpts = append(bootstrapOpts, bootstrap.WithSSHHostname(bootstrapArgs.sshHostname))

View File

@@ -257,6 +257,7 @@ func bootstrapGitLabCmdRun(cmd *cobra.Command, args []string) error {
bootstrap.WithKubeconfig(kubeconfigArgs),
bootstrap.WithLogger(logger),
bootstrap.WithCABundle(caBundle),
bootstrap.WithGitCommitSigning(bootstrapArgs.gpgKeyRingPath, bootstrapArgs.gpgPassphrase, bootstrapArgs.gpgKeyID),
}
if bootstrapArgs.sshHostname != "" {
bootstrapOpts = append(bootstrapOpts, bootstrap.WithSSHHostname(bootstrapArgs.sshHostname))

View File

@@ -23,7 +23,7 @@ import (
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.",
Long: "The diff command is used to do a server-side dry-run on flux resources, then prints the diff.",
}
func init() {

View File

@@ -31,8 +31,9 @@ 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: `# Preview changes local changes as they were applied on the cluster
Long: `The diff command does a build, then it performs a server-side dry-run and prints the diff.
Exit status: 0 No differences were found. 1 Differences were found. >1 diff failed with an error.`,
Example: `# Preview local changes as they were applied on the cluster
flux diff kustomization my-app --path ./path/to/local/manifests`,
ValidArgsFunction: resourceNamesCompletionFunc(kustomizev1.GroupVersion.WithKind(kustomizev1.KustomizationKind)),
RunE: diffKsCmdRun,
@@ -56,16 +57,16 @@ func diffKsCmdRun(cmd *cobra.Command, args []string) error {
name := args[0]
if diffKsArgs.path == "" {
return fmt.Errorf("invalid resource path %q", diffKsArgs.path)
return &RequestError{StatusCode: 2, Err: 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)
return &RequestError{StatusCode: 2, Err: fmt.Errorf("invalid resource path %q", diffKsArgs.path)}
}
builder, err := build.NewBuilder(kubeconfigArgs, name, diffKsArgs.path, build.WithTimeout(rootArgs.timeout))
if err != nil {
return err
return &RequestError{StatusCode: 2, Err: err}
}
// create a signal channel
@@ -74,13 +75,18 @@ func diffKsCmdRun(cmd *cobra.Command, args []string) error {
errChan := make(chan error)
go func() {
output, err := builder.Diff()
output, hasChanged, err := builder.Diff()
if err != nil {
errChan <- err
errChan <- &RequestError{StatusCode: 2, Err: err}
}
cmd.Print(output)
errChan <- nil
if hasChanged {
errChan <- &RequestError{StatusCode: 1, Err: fmt.Errorf("identified at least one change, exiting with non-zero exit code")}
} else {
errChan <- nil
}
}()
select {

View File

@@ -105,6 +105,16 @@ type rootFlags struct {
defaults install.Options
}
// RequestError is a custom error type that wraps an error returned by the flux api.
type RequestError struct {
StatusCode int
Err error
}
func (r *RequestError) Error() string {
return r.Err.Error()
}
var rootArgs = NewRootFlags()
var kubeconfigArgs = genericclioptions.NewConfigFlags(false)
@@ -144,6 +154,11 @@ func main() {
log.SetFlags(0)
if err := rootCmd.Execute(); err != nil {
logger.Failuref("%v", err)
if err, ok := err.(*RequestError); ok {
os.Exit(err.StatusCode)
}
os.Exit(1)
}
}

View File

@@ -325,6 +325,12 @@ type cmdTestCase struct {
func (cmd *cmdTestCase) runTestCmd(t *testing.T) {
actual, testErr := executeCommand(cmd.args)
// If the cmd error is a change, discard it
if isChangeError(testErr) {
testErr = nil
}
if assertErr := cmd.assert(actual, testErr); assertErr != nil {
t.Error(assertErr)
}
@@ -366,3 +372,12 @@ func resetCmdArgs() {
getArgs = GetFlags{}
secretGitArgs = NewSecretGitFlags()
}
func isChangeError(err error) bool {
if reqErr, ok := err.(*RequestError); ok {
if strings.Contains(err.Error(), "identified at least one change, exiting with non-zero exit code") && reqErr.StatusCode == 1 {
return true
}
}
return false
}

View File

@@ -48,6 +48,7 @@ func init() {
type resumable interface {
adapter
copyable
statusable
setUnsuspended()
successMessage() string
@@ -97,10 +98,13 @@ func (resume resumeCommand) run(cmd *cobra.Command, args []string) error {
for i := 0; i < resume.list.len(); i++ {
logger.Actionf("resuming %s %s in %s namespace", resume.humanKind, resume.list.resumeItem(i).asClientObject().GetName(), *kubeconfigArgs.Namespace)
resume.list.resumeItem(i).setUnsuspended()
if err := kubeClient.Update(ctx, resume.list.resumeItem(i).asClientObject()); err != nil {
obj := resume.list.resumeItem(i)
patch := client.MergeFrom(obj.deepCopyClientObject())
obj.setUnsuspended()
if err := kubeClient.Patch(ctx, obj.asClientObject(), patch); err != nil {
return err
}
logger.Successf("%s resumed", resume.humanKind)
namespacedName := types.NamespacedName{

View File

@@ -46,6 +46,7 @@ func init() {
type suspendable interface {
adapter
copyable
isSuspended() bool
setSuspended()
}
@@ -94,8 +95,11 @@ func (suspend suspendCommand) run(cmd *cobra.Command, args []string) error {
for i := 0; i < suspend.list.len(); i++ {
logger.Actionf("suspending %s %s in %s namespace", suspend.humanKind, suspend.list.item(i).asClientObject().GetName(), *kubeconfigArgs.Namespace)
suspend.list.item(i).setSuspended()
if err := kubeClient.Update(ctx, suspend.list.item(i).asClientObject()); err != nil {
obj := suspend.list.item(i)
patch := client.MergeFrom(obj.deepCopyClientObject())
obj.setSuspended()
if err := kubeClient.Patch(ctx, obj.asClientObject(), patch); err != nil {
return err
}
logger.Successf("%s suspended", suspend.humanKind)

View File

@@ -275,7 +275,7 @@ func (b *GitProviderBootstrapper) reconcileOrgRepository(ctx context.Context) (g
subOrgs, repoName := splitSubOrganizationsFromRepositoryName(b.repositoryName)
orgRef, err := b.getOrganization(ctx, subOrgs)
if err != nil {
return nil, fmt.Errorf("failed to create new Git repository for the organization %q: %w", orgRef.String(), err)
return nil, fmt.Errorf("failed to create new Git repository %q: %w", b.repositoryName, err)
}
repoRef := newOrgRepositoryRef(*orgRef, repoName)
repoInfo := newRepositoryInfo(b.description, b.defaultBranch, b.visibility)

View File

@@ -36,6 +36,7 @@ import (
"sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/resource"
"sigs.k8s.io/kustomize/kyaml/filesys"
"sigs.k8s.io/kustomize/kyaml/yaml"
)
const (
@@ -262,16 +263,30 @@ func trimSopsData(res *resource.Resource) error {
if res.GetKind() == "Secret" {
dataMap := res.GetDataMap()
for k, v := range dataMap {
data, err := base64.StdEncoding.DecodeString(v)
if err != nil {
if _, ok := err.(base64.CorruptInputError); ok {
return fmt.Errorf("failed to decode secret data: %w", err)
}
asYaml, err := res.AsYAML()
if err != nil {
return fmt.Errorf("failed to decode secret %s data: %w", res.GetName(), err)
}
//delete any sops data as we don't want to expose it
if bytes.Contains(asYaml, []byte("sops:")) && bytes.Contains(asYaml, []byte("mac: ENC[")) {
res.PipeE(yaml.FieldClearer{Name: "sops"})
for k := range dataMap {
dataMap[k] = sopsMess
}
if bytes.Contains(data, []byte("sops")) && bytes.Contains(data, []byte("ENC[")) {
dataMap[k] = sopsMess
} else {
for k, v := range dataMap {
data, err := base64.StdEncoding.DecodeString(v)
if err != nil {
if _, ok := err.(base64.CorruptInputError); ok {
return fmt.Errorf("failed to decode secret %s data: %w", res.GetName(), err)
}
}
if bytes.Contains(data, []byte("sops")) && bytes.Contains(data, []byte("ENC[")) {
dataMap[k] = sopsMess
}
}
}

View File

@@ -91,6 +91,45 @@ kind: Secret
metadata:
name: secret-basic-auth
type: kubernetes.io/basic-auth
`,
},
{
name: "secret sops secret",
yamlStr: `apiVersion: v1
data:
.dockercfg: ENC[AES256_GCM,data:KHCFH3hNnc+PMfWLFEPjebf3W4z4WXbGFAANRZyZC+07z7wlrTALJM6rn8YslW4tMAWCoAYxblC5WRCszTy0h9rw0U/RGOv5H0qCgnNg/FILFUqhwo9pNfrUH+MEP4M9qxxbLKZwObpHUE7DUsKx1JYAxsI=,iv:q48lqUbUQD+0cbYcjNMZMJLRdGHi78ZmDhNAT2th9tg=,tag:QRI2SZZXQrAcdql3R5AH2g==,type:str]
kind: Secret
metadata:
name: secret
type: kubernetes.io/dockerconfigjson
sops:
kms: []
gcp_kms: []
azure_kv: []
hc_vault: []
age:
- recipient: age10la2ge0wtvx3qr7datqf7rs4yngxszdal927fs9rukamr8u2pshsvtz7ce
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA3eU1CTEJhVXZ4eEVYYkVV
OU90TEcrR2pYckttN0pBanJoSUZWSW1RQXlRCkUydFJ3V1NZUTBuVFF0aC9GUEcw
bUdhNjJWTkoyL1FUVi9Dc1dxUDBkM0UKLS0tIE1sQXkwcWdGaEFuY0RHQTVXM0J6
dWpJcThEbW15V3dXYXpPZklBdW1Hd1kKoIAdmGNPrEctV8h1w8KuvQ5S+BGmgqN9
MgpNmUhJjWhgcQpb5BRYpQesBOgU5TBGK7j58A6DMDKlSiYZsdQchQ==
-----END AGE ENCRYPTED FILE-----
lastmodified: "2022-02-03T16:03:17Z"
mac: ENC[AES256_GCM,data:AHdYSawajwgAFwlmDN1IPNmT9vWaYKzyVIra2d6sPcjTbZ8/p+VRSRpVm4XZFFsaNnW5AUJaouwXnKYDTmJDXKlr/rQcu9kXqsssQgdzcXaA6l5uJlgsnml8ba7J3OK+iEKMax23mwQEx2EUskCd9ENOwFDkunP02sxqDNOz20k=,iv:8F5OamHt3fAVorf6p+SoIrWoqkcATSGWVoM0EK87S4M=,tag:E1mxXnc7wWkEX5BxhpLtng==,type:str]
pgp: []
encrypted_regex: ^(data|stringData)$
version: 3.7.1
`,
expected: `apiVersion: v1
data:
.dockercfg: KipTT1BTKio=
kind: Secret
metadata:
name: secret
type: kubernetes.io/dockerconfigjson
`,
},
}

View File

@@ -51,28 +51,29 @@ func (b *Builder) Manager() (*ssa.ResourceManager, error) {
return ssa.NewResourceManager(b.client, statusPoller, owner), nil
}
func (b *Builder) Diff() (string, error) {
func (b *Builder) Diff() (string, bool, error) {
output := strings.Builder{}
createdOrDrifted := false
res, err := b.Build()
if err != nil {
return "", err
return "", createdOrDrifted, err
}
// convert the build result into Kubernetes unstructured objects
objects, err := ssa.ReadObjects(bytes.NewReader(res))
if err != nil {
return "", err
return "", createdOrDrifted, err
}
resourceManager, err := b.Manager()
if err != nil {
return "", err
return "", createdOrDrifted, err
}
ctx, cancel := context.WithTimeout(context.Background(), b.timeout)
defer cancel()
if err := ssa.SetNativeKindsDefaults(objects); err != nil {
return "", err
return "", createdOrDrifted, err
}
// create an inventory of objects to be reconciled
@@ -101,20 +102,23 @@ func (b *Builder) Diff() (string, error) {
if change.Action == string(ssa.CreatedAction) {
output.WriteString(writeString(fmt.Sprintf("► %s created\n", change.Subject), bunt.Green))
createdOrDrifted = true
}
if change.Action == string(ssa.ConfiguredAction) {
output.WriteString(writeString(fmt.Sprintf("► %s drifted\n", change.Subject), bunt.WhiteSmoke))
liveFile, mergedFile, tmpDir, err := writeYamls(liveObject, mergedObject)
if err != nil {
return "", err
return "", createdOrDrifted, err
}
defer cleanupDir(tmpDir)
err = diff(liveFile, mergedFile, &output)
if err != nil {
return "", err
return "", createdOrDrifted, err
}
createdOrDrifted = true
}
addObjectsToInventory(newInventory, change)
@@ -125,7 +129,7 @@ func (b *Builder) Diff() (string, error) {
if oldStatus.Inventory != nil {
diffObjects, err := diffInventory(oldStatus.Inventory, newInventory)
if err != nil {
return "", err
return "", createdOrDrifted, err
}
for _, object := range diffObjects {
output.WriteString(writeString(fmt.Sprintf("► %s deleted\n", ssa.FmtUnstructured(object)), bunt.OrangeRed))
@@ -133,7 +137,7 @@ func (b *Builder) Diff() (string, error) {
}
}
return output.String(), nil
return output.String(), createdOrDrifted, nil
}
func writeYamls(liveObject, mergedObject *unstructured.Unstructured) (string, string, string, error) {

View File

@@ -483,7 +483,7 @@ func TestImageRepositoryACR(t *testing.T) {
Interval: metav1.Duration{
Duration: 1 * time.Minute,
},
SourceRef: automationv1beta1.SourceReference{
SourceRef: automationv1beta1.CrossNamespaceSourceReference{
Kind: "GitRepository",
Name: name,
},