1
0
mirror of synced 2026-03-01 11:16:56 +00:00

Compare commits

..

4 Commits

Author SHA1 Message Date
Stefan Prodan
c312816858 Add --no-cross-namespace-ref to implementation history
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2022-02-03 10:26:11 +02:00
Stefan Prodan
e5635d0ae2 Explain how the proposed solution compares to alternatives
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2022-02-03 10:17:49 +02:00
Stefan Prodan
43372a9ac7 Add network policies reference
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2022-02-03 10:17:46 +02:00
Stefan Prodan
a46f4e36cf [RFC-0002] Access control for cross-namespace source refs
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2022-02-03 10:17:46 +02:00
180 changed files with 1206 additions and 3129 deletions

View File

@@ -42,7 +42,8 @@ jobs:
if [[ "${MOD_VERSION}" != "${LATEST_VERSION}" ]]; then if [[ "${MOD_VERSION}" != "${LATEST_VERSION}" ]]; then
go mod edit -require="github.com/fluxcd/$1/api@${LATEST_VERSION}" go mod edit -require="github.com/fluxcd/$1/api@${LATEST_VERSION}"
make tidy rm go.sum
go mod tidy
changed=true changed=true
fi fi

View File

@@ -70,7 +70,6 @@ Prerequisites:
* go >= 1.17 * go >= 1.17
* kubectl >= 1.20 * kubectl >= 1.20
* kustomize >= 4.4 * kustomize >= 4.4
* coreutils (on Mac OS)
Install the [controller-runtime/envtest](https://github.com/kubernetes-sigs/controller-runtime/tree/master/tools/setup-envtest) binaries with: Install the [controller-runtime/envtest](https://github.com/kubernetes-sigs/controller-runtime/tree/master/tools/setup-envtest) binaries with:
@@ -97,25 +96,6 @@ Then you can run the end-to-end tests with:
make e2e make e2e
``` ```
When the output of the Flux CLI changes, to automatically update the golden
files used in the test, pass `-update` flag to the test as:
```bash
make e2e TEST_ARGS="-update"
```
Since not all packages use golden files for testing, `-update` argument must be
passed only for the packages that use golden files. Use the variables
`TEST_PKG_PATH` for unit tests and `E2E_TEST_PKG_PATH` for e2e tests, to set the
path of the target test package:
```bash
# Unit test
make test TEST_PKG_PATH="./cmd/flux" TEST_ARGS="-update"
# e2e test
make e2e E2E_TEST_PKG_PATH="./cmd/flux" TEST_ARGS="-update"
```
Teardown the e2e environment with: Teardown the e2e environment with:
```bash ```bash

View File

@@ -16,8 +16,8 @@ rwildcard=$(foreach d,$(wildcard $(addsuffix *,$(1))),$(call rwildcard,$(d)/,$(2
all: test build all: test build
tidy: tidy:
go mod tidy -compat=1.17 go mod tidy
cd tests/azure && go mod tidy -compat=1.17 cd tests/azure && go mod tidy
fmt: fmt:
go fmt ./... go fmt ./...
@@ -35,13 +35,11 @@ cleanup-kind:
rm $(TEST_KUBECONFIG) rm $(TEST_KUBECONFIG)
KUBEBUILDER_ASSETS?="$(shell $(ENVTEST) --arch=$(ENVTEST_ARCH) use -i $(ENVTEST_KUBERNETES_VERSION) --bin-dir=$(ENVTEST_ASSETS_DIR) -p path)" KUBEBUILDER_ASSETS?="$(shell $(ENVTEST) --arch=$(ENVTEST_ARCH) use -i $(ENVTEST_KUBERNETES_VERSION) --bin-dir=$(ENVTEST_ASSETS_DIR) -p path)"
TEST_PKG_PATH="./..."
test: $(EMBEDDED_MANIFESTS_TARGET) tidy fmt vet install-envtest test: $(EMBEDDED_MANIFESTS_TARGET) tidy fmt vet install-envtest
KUBEBUILDER_ASSETS="$(KUBEBUILDER_ASSETS)" go test $(TEST_PKG_PATH) -coverprofile cover.out --tags=unit $(TEST_ARGS) KUBEBUILDER_ASSETS="$(KUBEBUILDER_ASSETS)" go test ./... -coverprofile cover.out --tags=unit
E2E_TEST_PKG_PATH="./cmd/flux/..."
e2e: $(EMBEDDED_MANIFESTS_TARGET) tidy fmt vet e2e: $(EMBEDDED_MANIFESTS_TARGET) tidy fmt vet
TEST_KUBECONFIG=$(TEST_KUBECONFIG) go test $(E2E_TEST_PKG_PATH) -coverprofile e2e.cover.out --tags=e2e -v -failfast $(TEST_ARGS) TEST_KUBECONFIG=$(TEST_KUBECONFIG) go test ./cmd/flux/... -coverprofile e2e.cover.out --tags=e2e -v -failfast
test-with-kind: install-envtest test-with-kind: install-envtest
make setup-kind make setup-kind

Binary file not shown.

View File

@@ -25,9 +25,8 @@ import (
// notificationv1.Alert // notificationv1.Alert
var alertType = apiType{ var alertType = apiType{
kind: notificationv1.AlertKind, kind: notificationv1.AlertKind,
humanKind: "alert", humanKind: "alert",
groupVersion: notificationv1.GroupVersion,
} }
type alertAdapter struct { type alertAdapter struct {

View File

@@ -25,9 +25,8 @@ import (
// notificationv1.Provider // notificationv1.Provider
var alertProviderType = apiType{ var alertProviderType = apiType{
kind: notificationv1.ProviderKind, kind: notificationv1.ProviderKind,
humanKind: "alert provider", humanKind: "alert provider",
groupVersion: notificationv1.GroupVersion,
} }
type alertProviderAdapter struct { type alertProviderAdapter struct {

View File

@@ -88,7 +88,7 @@ func init() {
bootstrapCmd.PersistentFlags().StringSliceVar(&bootstrapArgs.defaultComponents, "components", rootArgs.defaults.Components, bootstrapCmd.PersistentFlags().StringSliceVar(&bootstrapArgs.defaultComponents, "components", rootArgs.defaults.Components,
"list of components, accepts comma-separated values") "list of components, accepts comma-separated values")
bootstrapCmd.PersistentFlags().StringSliceVar(&bootstrapArgs.extraComponents, "components-extra", nil, bootstrapCmd.PersistentFlags().StringSliceVar(&bootstrapArgs.extraComponents, "components-extra", nil,
"list of components in addition to those supplied or defaulted, accepts values such as 'image-reflector-controller,image-automation-controller'") "list of components in addition to those supplied or defaulted, accepts comma-separated values")
bootstrapCmd.PersistentFlags().StringVar(&bootstrapArgs.registry, "registry", "ghcr.io/fluxcd", bootstrapCmd.PersistentFlags().StringVar(&bootstrapArgs.registry, "registry", "ghcr.io/fluxcd",
"container registry where the toolkit images are published") "container registry where the toolkit images are published")

View File

@@ -121,7 +121,7 @@ func bootstrapBServerCmdRun(cmd *cobra.Command, args []string) error {
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel() defer cancel()
kubeClient, err := utils.KubeClient(kubeconfigArgs, kubeclientOptions) kubeClient, err := utils.KubeClient(kubeconfigArgs)
if err != nil { if err != nil {
return err return err
} }
@@ -251,10 +251,9 @@ func bootstrapBServerCmdRun(cmd *cobra.Command, args []string) error {
bootstrap.WithCommitMessageAppendix(bootstrapArgs.commitMessageAppendix), bootstrap.WithCommitMessageAppendix(bootstrapArgs.commitMessageAppendix),
bootstrap.WithProviderTeamPermissions(mapTeamSlice(bServerArgs.teams, bServerDefaultPermission)), bootstrap.WithProviderTeamPermissions(mapTeamSlice(bServerArgs.teams, bServerDefaultPermission)),
bootstrap.WithReadWriteKeyPermissions(bServerArgs.readWriteKey), bootstrap.WithReadWriteKeyPermissions(bServerArgs.readWriteKey),
bootstrap.WithKubeconfig(kubeconfigArgs, kubeclientOptions), bootstrap.WithKubeconfig(kubeconfigArgs),
bootstrap.WithLogger(logger), bootstrap.WithLogger(logger),
bootstrap.WithCABundle(caBundle), bootstrap.WithCABundle(caBundle),
bootstrap.WithGitCommitSigning(bootstrapArgs.gpgKeyRingPath, bootstrapArgs.gpgPassphrase, bootstrapArgs.gpgKeyID),
} }
if bootstrapArgs.sshHostname != "" { if bootstrapArgs.sshHostname != "" {
bootstrapOpts = append(bootstrapOpts, bootstrap.WithSSHHostname(bootstrapArgs.sshHostname)) bootstrapOpts = append(bootstrapOpts, bootstrap.WithSSHHostname(bootstrapArgs.sshHostname))

View File

@@ -53,9 +53,6 @@ command will perform an upgrade if needed.`,
# Run bootstrap for a Git repository and authenticate using a password # Run bootstrap for a Git repository and authenticate using a password
flux bootstrap git --url=https://example.com/repository.git --password=<password> flux bootstrap git --url=https://example.com/repository.git --password=<password>
# Run bootstrap for a Git repository and authenticate using a password from environment variable
GIT_PASSWORD=<password> && flux bootstrap git --url=https://example.com/repository.git
# Run bootstrap for a Git repository with a passwordless private key # Run bootstrap for a Git repository with a passwordless private key
flux bootstrap git --url=ssh://git@example.com/repository.git --private-key-file=<path/to/private.key> flux bootstrap git --url=ssh://git@example.com/repository.git --private-key-file=<path/to/private.key>
@@ -74,10 +71,6 @@ type gitFlags struct {
silent bool silent bool
} }
const (
gitPasswordEnvVar = "GIT_PASSWORD"
)
var gitArgs gitFlags var gitArgs gitFlags
func init() { func init() {
@@ -92,19 +85,6 @@ func init() {
} }
func bootstrapGitCmdRun(cmd *cobra.Command, args []string) error { func bootstrapGitCmdRun(cmd *cobra.Command, args []string) error {
gitPassword := os.Getenv(gitPasswordEnvVar)
if gitPassword != "" && gitArgs.password == "" {
gitArgs.password = gitPassword
}
if bootstrapArgs.tokenAuth && gitArgs.password == "" {
var err error
gitPassword, err = readPasswordFromStdin("Please enter your Git repository password: ")
if err != nil {
return fmt.Errorf("could not read token: %w", err)
}
gitArgs.password = gitPassword
}
if err := bootstrapValidate(); err != nil { if err := bootstrapValidate(); err != nil {
return err return err
} }
@@ -121,7 +101,7 @@ func bootstrapGitCmdRun(cmd *cobra.Command, args []string) error {
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel() defer cancel()
kubeClient, err := utils.KubeClient(kubeconfigArgs, kubeclientOptions) kubeClient, err := utils.KubeClient(kubeconfigArgs)
if err != nil { if err != nil {
return err return err
} }
@@ -245,7 +225,7 @@ func bootstrapGitCmdRun(cmd *cobra.Command, args []string) error {
bootstrap.WithBranch(bootstrapArgs.branch), bootstrap.WithBranch(bootstrapArgs.branch),
bootstrap.WithAuthor(bootstrapArgs.authorName, bootstrapArgs.authorEmail), bootstrap.WithAuthor(bootstrapArgs.authorName, bootstrapArgs.authorEmail),
bootstrap.WithCommitMessageAppendix(bootstrapArgs.commitMessageAppendix), bootstrap.WithCommitMessageAppendix(bootstrapArgs.commitMessageAppendix),
bootstrap.WithKubeconfig(kubeconfigArgs, kubeclientOptions), bootstrap.WithKubeconfig(kubeconfigArgs),
bootstrap.WithPostGenerateSecretFunc(promptPublicKey), bootstrap.WithPostGenerateSecretFunc(promptPublicKey),
bootstrap.WithLogger(logger), bootstrap.WithLogger(logger),
bootstrap.WithCABundle(caBundle), bootstrap.WithCABundle(caBundle),

View File

@@ -125,7 +125,7 @@ func bootstrapGitHubCmdRun(cmd *cobra.Command, args []string) error {
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel() defer cancel()
kubeClient, err := utils.KubeClient(kubeconfigArgs, kubeclientOptions) kubeClient, err := utils.KubeClient(kubeconfigArgs)
if err != nil { if err != nil {
return err return err
} }
@@ -240,10 +240,9 @@ func bootstrapGitHubCmdRun(cmd *cobra.Command, args []string) error {
bootstrap.WithCommitMessageAppendix(bootstrapArgs.commitMessageAppendix), bootstrap.WithCommitMessageAppendix(bootstrapArgs.commitMessageAppendix),
bootstrap.WithProviderTeamPermissions(mapTeamSlice(githubArgs.teams, ghDefaultPermission)), bootstrap.WithProviderTeamPermissions(mapTeamSlice(githubArgs.teams, ghDefaultPermission)),
bootstrap.WithReadWriteKeyPermissions(githubArgs.readWriteKey), bootstrap.WithReadWriteKeyPermissions(githubArgs.readWriteKey),
bootstrap.WithKubeconfig(kubeconfigArgs, kubeclientOptions), bootstrap.WithKubeconfig(kubeconfigArgs),
bootstrap.WithLogger(logger), bootstrap.WithLogger(logger),
bootstrap.WithCABundle(caBundle), bootstrap.WithCABundle(caBundle),
bootstrap.WithGitCommitSigning(bootstrapArgs.gpgKeyRingPath, bootstrapArgs.gpgPassphrase, bootstrapArgs.gpgKeyID),
} }
if bootstrapArgs.sshHostname != "" { if bootstrapArgs.sshHostname != "" {
bootstrapOpts = append(bootstrapOpts, bootstrap.WithSSHHostname(bootstrapArgs.sshHostname)) bootstrapOpts = append(bootstrapOpts, bootstrap.WithSSHHostname(bootstrapArgs.sshHostname))

View File

@@ -129,7 +129,7 @@ func bootstrapGitLabCmdRun(cmd *cobra.Command, args []string) error {
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel() defer cancel()
kubeClient, err := utils.KubeClient(kubeconfigArgs, kubeclientOptions) kubeClient, err := utils.KubeClient(kubeconfigArgs)
if err != nil { if err != nil {
return err return err
} }
@@ -254,10 +254,9 @@ func bootstrapGitLabCmdRun(cmd *cobra.Command, args []string) error {
bootstrap.WithCommitMessageAppendix(bootstrapArgs.commitMessageAppendix), bootstrap.WithCommitMessageAppendix(bootstrapArgs.commitMessageAppendix),
bootstrap.WithProviderTeamPermissions(mapTeamSlice(gitlabArgs.teams, glDefaultPermission)), bootstrap.WithProviderTeamPermissions(mapTeamSlice(gitlabArgs.teams, glDefaultPermission)),
bootstrap.WithReadWriteKeyPermissions(gitlabArgs.readWriteKey), bootstrap.WithReadWriteKeyPermissions(gitlabArgs.readWriteKey),
bootstrap.WithKubeconfig(kubeconfigArgs, kubeclientOptions), bootstrap.WithKubeconfig(kubeconfigArgs),
bootstrap.WithLogger(logger), bootstrap.WithLogger(logger),
bootstrap.WithCABundle(caBundle), bootstrap.WithCABundle(caBundle),
bootstrap.WithGitCommitSigning(bootstrapArgs.gpgKeyRingPath, bootstrapArgs.gpgPassphrase, bootstrapArgs.gpgKeyID),
} }
if bootstrapArgs.sshHostname != "" { if bootstrapArgs.sshHostname != "" {
bootstrapOpts = append(bootstrapOpts, bootstrap.WithSSHHostname(bootstrapArgs.sshHostname)) bootstrapOpts = append(bootstrapOpts, bootstrap.WithSSHHostname(bootstrapArgs.sshHostname))

View File

@@ -33,28 +33,21 @@ var buildKsCmd = &cobra.Command{
Short: "Build Kustomization", Short: "Build Kustomization",
Long: `The build command queries the Kubernetes API and fetches the specified Flux Kustomization. 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 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. 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.`,
It is possible to specify a Flux kustomization file using --kustomization-file.`,
Example: `# Build the local manifests as they were built on the cluster Example: `# Build the local manifests as they were built on the cluster
flux build kustomization my-app --path ./path/to/local/manifests flux build kustomization my-app --path ./path/to/local/manifests`,
# Build using a local flux kustomization file
flux build kustomization my-app --path ./path/to/local/manifests --kustomization-file ./path/to/local/my-app.yaml`,
ValidArgsFunction: resourceNamesCompletionFunc(kustomizev1.GroupVersion.WithKind(kustomizev1.KustomizationKind)), ValidArgsFunction: resourceNamesCompletionFunc(kustomizev1.GroupVersion.WithKind(kustomizev1.KustomizationKind)),
RunE: buildKsCmdRun, RunE: buildKsCmdRun,
} }
type buildKsFlags struct { type buildKsFlags struct {
kustomizationFile string path string
path string
} }
var buildKsArgs buildKsFlags var buildKsArgs buildKsFlags
func init() { func init() {
buildKsCmd.Flags().StringVar(&buildKsArgs.path, "path", "", "Path to the manifests location.") buildKsCmd.Flags().StringVar(&buildKsArgs.path, "path", "", "Path to the manifests location.)")
buildKsCmd.Flags().StringVar(&buildKsArgs.kustomizationFile, "kustomization-file", "", "Path to the Flux Kustomization YAML file.")
buildCmd.AddCommand(buildKsCmd) buildCmd.AddCommand(buildKsCmd)
} }
@@ -72,13 +65,7 @@ func buildKsCmdRun(cmd *cobra.Command, args []string) error {
return fmt.Errorf("invalid resource path %q", buildKsArgs.path) return fmt.Errorf("invalid resource path %q", buildKsArgs.path)
} }
if buildKsArgs.kustomizationFile != "" { builder, err := build.NewBuilder(kubeconfigArgs, name, buildKsArgs.path, build.WithTimeout(rootArgs.timeout))
if fs, err := os.Stat(buildKsArgs.kustomizationFile); os.IsNotExist(err) || fs.IsDir() {
return fmt.Errorf("invalid kustomization file %q", buildKsArgs.kustomizationFile)
}
}
builder, err := build.NewBuilder(kubeconfigArgs, kubeclientOptions, name, buildKsArgs.path, build.WithTimeout(rootArgs.timeout), build.WithKustomizationFile(buildKsArgs.kustomizationFile))
if err != nil { if err != nil {
return err return err
} }

View File

@@ -20,10 +20,7 @@ limitations under the License.
package main package main
import ( import (
"bytes"
"os"
"testing" "testing"
"text/template"
) )
func setup(t *testing.T, tmpl map[string]string) { func setup(t *testing.T, tmpl map[string]string) {
@@ -57,12 +54,6 @@ func TestBuildKustomization(t *testing.T) {
resultFile: "./testdata/build-kustomization/podinfo-without-service-result.yaml", resultFile: "./testdata/build-kustomization/podinfo-without-service-result.yaml",
assertFunc: "assertGoldenTemplateFile", assertFunc: "assertGoldenTemplateFile",
}, },
{
name: "build deployment and configmap with var substitution",
args: "build kustomization podinfo --path ./testdata/build-kustomization/var-substitution",
resultFile: "./testdata/build-kustomization/podinfo-with-var-substitution-result.yaml",
assertFunc: "assertGoldenTemplateFile",
},
} }
tmpl := map[string]string{ tmpl := map[string]string{
@@ -90,101 +81,3 @@ func TestBuildKustomization(t *testing.T) {
}) })
} }
} }
func TestBuildLocalKustomization(t *testing.T) {
podinfo := `apiVersion: kustomize.toolkit.fluxcd.io/v1beta2
kind: Kustomization
metadata:
name: podinfo
namespace: {{ .fluxns }}
spec:
interval: 5m0s
path: ./kustomize
force: true
prune: true
sourceRef:
kind: GitRepository
name: podinfo
targetNamespace: default
postBuild:
substitute:
cluster_env: "prod"
cluster_region: "eu-central-1"
`
tests := []struct {
name string
args string
resultFile string
assertFunc string
}{
{
name: "no args",
args: "build kustomization podinfo --kustomization-file ./wrongfile/ --path ./testdata/build-kustomization/podinfo",
resultFile: "invalid kustomization file \"./wrongfile/\"",
assertFunc: "assertError",
},
{
name: "build podinfo",
args: "build kustomization podinfo --kustomization-file ./testdata/build-kustomization/podinfo.yaml --path ./testdata/build-kustomization/podinfo",
resultFile: "./testdata/build-kustomization/podinfo-result.yaml",
assertFunc: "assertGoldenTemplateFile",
},
{
name: "build podinfo without service",
args: "build kustomization podinfo --kustomization-file ./testdata/build-kustomization/podinfo.yaml --path ./testdata/build-kustomization/delete-service",
resultFile: "./testdata/build-kustomization/podinfo-without-service-result.yaml",
assertFunc: "assertGoldenTemplateFile",
},
{
name: "build deployment and configmap with var substitution",
args: "build kustomization podinfo --kustomization-file ./testdata/build-kustomization/podinfo.yaml --path ./testdata/build-kustomization/var-substitution",
resultFile: "./testdata/build-kustomization/podinfo-with-var-substitution-result.yaml",
assertFunc: "assertGoldenTemplateFile",
},
}
tmpl := map[string]string{
"fluxns": allocateNamespace("flux-system"),
}
testEnv.CreateObjectFile("./testdata/build-kustomization/podinfo-source.yaml", tmpl, t)
temp, err := template.New("podinfo").Parse(podinfo)
if err != nil {
t.Fatal(err)
}
var b bytes.Buffer
err = temp.Execute(&b, tmpl)
if err != nil {
t.Fatal(err)
}
err = os.WriteFile("./testdata/build-kustomization/podinfo.yaml", b.Bytes(), 0666)
if err != nil {
t.Fatal(err)
}
defer os.Remove("./testdata/build-kustomization/podinfo.yaml")
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
var assert assertFunc
switch tt.assertFunc {
case "assertGoldenTemplateFile":
assert = assertGoldenTemplateFile(tt.resultFile, tmpl)
case "assertError":
assert = assertError(tt.resultFile)
}
cmd := cmdTestCase{
args: tt.args + " -n " + tmpl["fluxns"],
assert: assert,
}
cmd.runTestCmd(t)
})
}
}

View File

@@ -125,7 +125,7 @@ func fluxCheck() {
} }
func kubernetesCheck(constraints []string) bool { func kubernetesCheck(constraints []string) bool {
cfg, err := utils.KubeConfig(kubeconfigArgs, kubeclientOptions) cfg, err := utils.KubeConfig(kubeconfigArgs)
if err != nil { if err != nil {
logger.Failuref("Kubernetes client initialization failed: %s", err.Error()) logger.Failuref("Kubernetes client initialization failed: %s", err.Error())
return false return false
@@ -173,7 +173,7 @@ func componentsCheck() bool {
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel() defer cancel()
kubeConfig, err := utils.KubeConfig(kubeconfigArgs, kubeclientOptions) kubeConfig, err := utils.KubeConfig(kubeconfigArgs)
if err != nil { if err != nil {
return false return false
} }
@@ -183,7 +183,7 @@ func componentsCheck() bool {
return false return false
} }
kubeClient, err := utils.KubeClient(kubeconfigArgs, kubeclientOptions) kubeClient, err := utils.KubeClient(kubeconfigArgs)
if err != nil { if err != nil {
return false return false
} }

View File

@@ -60,7 +60,7 @@ func resourceNamesCompletionFunc(gvk schema.GroupVersionKind) func(cmd *cobra.Co
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel() defer cancel()
cfg, err := utils.KubeConfig(kubeconfigArgs, kubeclientOptions) cfg, err := utils.KubeConfig(kubeconfigArgs)
if err != nil { if err != nil {
return completionError(err) return completionError(err)
} }

View File

@@ -19,7 +19,6 @@ package main
import ( import (
"context" "context"
"fmt" "fmt"
"regexp"
"strings" "strings"
"time" "time"
@@ -52,18 +51,6 @@ func init() {
createCmd.PersistentFlags().BoolVar(&createArgs.export, "export", false, "export in YAML format to stdout") createCmd.PersistentFlags().BoolVar(&createArgs.export, "export", false, "export in YAML format to stdout")
createCmd.PersistentFlags().StringSliceVar(&createArgs.labels, "label", nil, createCmd.PersistentFlags().StringSliceVar(&createArgs.labels, "label", nil,
"set labels on the resource (can specify multiple labels with commas: label1=value1,label2=value2)") "set labels on the resource (can specify multiple labels with commas: label1=value1,label2=value2)")
createCmd.PersistentPreRunE = func(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("name is required")
}
name := args[0]
if !validateObjectName(name) {
return fmt.Errorf("name '%s' is invalid, it should adhere to standard defined in RFC 1123, the name can only contain alphanumeric characters or '-'", name)
}
return nil
}
rootCmd.AddCommand(createCmd) rootCmd.AddCommand(createCmd)
} }
@@ -117,7 +104,7 @@ func (names apiType) upsertAndWait(object upsertWaitable, mutate func() error) e
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel() defer cancel()
kubeClient, err := utils.KubeClient(kubeconfigArgs, kubeclientOptions) // NB globals kubeClient, err := utils.KubeClient(kubeconfigArgs) // NB globals
if err != nil { if err != nil {
return err return err
} }
@@ -163,8 +150,3 @@ func parseLabels() (map[string]string, error) {
return result, nil return result, nil
} }
func validateObjectName(name string) bool {
r := regexp.MustCompile("^[a-z0-9]([a-z0-9\\-]){0,61}[a-z0-9]$")
return r.MatchString(name)
}

View File

@@ -63,6 +63,9 @@ func init() {
} }
func createAlertCmdRun(cmd *cobra.Command, args []string) error { func createAlertCmdRun(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("Alert name is required")
}
name := args[0] name := args[0]
if alertArgs.providerRef == "" { if alertArgs.providerRef == "" {
@@ -119,7 +122,7 @@ func createAlertCmdRun(cmd *cobra.Command, args []string) error {
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel() defer cancel()
kubeClient, err := utils.KubeClient(kubeconfigArgs, kubeclientOptions) kubeClient, err := utils.KubeClient(kubeconfigArgs)
if err != nil { if err != nil {
return err return err
} }

View File

@@ -73,6 +73,9 @@ func init() {
} }
func createAlertProviderCmdRun(cmd *cobra.Command, args []string) error { func createAlertProviderCmdRun(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("Provider name is required")
}
name := args[0] name := args[0]
if alertProviderArgs.alertType == "" { if alertProviderArgs.alertType == "" {
@@ -115,7 +118,7 @@ func createAlertProviderCmdRun(cmd *cobra.Command, args []string) error {
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel() defer cancel()
kubeClient, err := utils.KubeClient(kubeconfigArgs, kubeclientOptions) kubeClient, err := utils.KubeClient(kubeconfigArgs)
if err != nil { if err != nil {
return err return err
} }

View File

@@ -21,7 +21,6 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"os" "os"
"time"
"github.com/fluxcd/flux2/internal/flags" "github.com/fluxcd/flux2/internal/flags"
"github.com/fluxcd/flux2/internal/utils" "github.com/fluxcd/flux2/internal/utils"
@@ -109,19 +108,17 @@ var createHelmReleaseCmd = &cobra.Command{
} }
type helmReleaseFlags struct { type helmReleaseFlags struct {
name string name string
source flags.HelmChartSource source flags.HelmChartSource
dependsOn []string dependsOn []string
chart string chart string
chartVersion string chartVersion string
targetNamespace string targetNamespace string
createNamespace bool createNamespace bool
valuesFiles []string valuesFiles []string
valuesFrom flags.HelmReleaseValuesFrom valuesFrom flags.HelmReleaseValuesFrom
saName string saName string
crds flags.CRDsPolicy crds flags.CRDsPolicy
reconcileStrategy string
chartInterval time.Duration
} }
var helmReleaseArgs helmReleaseFlags var helmReleaseArgs helmReleaseFlags
@@ -135,8 +132,6 @@ func init() {
createHelmReleaseCmd.Flags().StringVar(&helmReleaseArgs.targetNamespace, "target-namespace", "", "namespace to install this release, defaults to the HelmRelease namespace") createHelmReleaseCmd.Flags().StringVar(&helmReleaseArgs.targetNamespace, "target-namespace", "", "namespace to install this release, defaults to the HelmRelease namespace")
createHelmReleaseCmd.Flags().BoolVar(&helmReleaseArgs.createNamespace, "create-target-namespace", false, "create the target namespace if it does not exist") createHelmReleaseCmd.Flags().BoolVar(&helmReleaseArgs.createNamespace, "create-target-namespace", false, "create the target namespace if it does not exist")
createHelmReleaseCmd.Flags().StringVar(&helmReleaseArgs.saName, "service-account", "", "the name of the service account to impersonate when reconciling this HelmRelease") createHelmReleaseCmd.Flags().StringVar(&helmReleaseArgs.saName, "service-account", "", "the name of the service account to impersonate when reconciling this HelmRelease")
createHelmReleaseCmd.Flags().StringVar(&helmReleaseArgs.reconcileStrategy, "reconcile-strategy", "ChartVersion", "the reconcile strategy for helm chart created by the helm release(accepted values: Revision and ChartRevision)")
createHelmReleaseCmd.Flags().DurationVarP(&helmReleaseArgs.chartInterval, "chart-interval", "", 0, "the interval of which to check for new chart versions")
createHelmReleaseCmd.Flags().StringSliceVar(&helmReleaseArgs.valuesFiles, "values", nil, "local path to values.yaml files, also accepts comma-separated values") createHelmReleaseCmd.Flags().StringSliceVar(&helmReleaseArgs.valuesFiles, "values", nil, "local path to values.yaml files, also accepts comma-separated values")
createHelmReleaseCmd.Flags().Var(&helmReleaseArgs.valuesFrom, "values-from", helmReleaseArgs.valuesFrom.Description()) createHelmReleaseCmd.Flags().Var(&helmReleaseArgs.valuesFrom, "values-from", helmReleaseArgs.valuesFrom.Description())
createHelmReleaseCmd.Flags().Var(&helmReleaseArgs.crds, "crds", helmReleaseArgs.crds.Description()) createHelmReleaseCmd.Flags().Var(&helmReleaseArgs.crds, "crds", helmReleaseArgs.crds.Description())
@@ -144,6 +139,9 @@ func init() {
} }
func createHelmReleaseCmdRun(cmd *cobra.Command, args []string) error { func createHelmReleaseCmdRun(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("HelmRelease name is required")
}
name := args[0] name := args[0]
if helmReleaseArgs.chart == "" { if helmReleaseArgs.chart == "" {
@@ -159,11 +157,6 @@ func createHelmReleaseCmdRun(cmd *cobra.Command, args []string) error {
logger.Generatef("generating HelmRelease") logger.Generatef("generating HelmRelease")
} }
if !validateStrategy(helmReleaseArgs.reconcileStrategy) {
return fmt.Errorf("'%s' is an invalid reconcile strategy(valid: Revision, ChartVersion)",
helmReleaseArgs.reconcileStrategy)
}
helmRelease := helmv2.HelmRelease{ helmRelease := helmv2.HelmRelease{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: name, Name: name,
@@ -187,19 +180,12 @@ func createHelmReleaseCmdRun(cmd *cobra.Command, args []string) error {
Name: helmReleaseArgs.source.Name, Name: helmReleaseArgs.source.Name,
Namespace: helmReleaseArgs.source.Namespace, Namespace: helmReleaseArgs.source.Namespace,
}, },
ReconcileStrategy: helmReleaseArgs.reconcileStrategy,
}, },
}, },
Suspend: false, Suspend: false,
}, },
} }
if helmReleaseArgs.chartInterval != 0 {
helmRelease.Spec.Chart.Spec.Interval = &metav1.Duration{
Duration: helmReleaseArgs.chartInterval,
}
}
if helmReleaseArgs.createNamespace { if helmReleaseArgs.createNamespace {
if helmRelease.Spec.Install == nil { if helmRelease.Spec.Install == nil {
helmRelease.Spec.Install = &helmv2.Install{} helmRelease.Spec.Install = &helmv2.Install{}
@@ -264,7 +250,7 @@ func createHelmReleaseCmdRun(cmd *cobra.Command, args []string) error {
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel() defer cancel()
kubeClient, err := utils.KubeClient(kubeconfigArgs, kubeclientOptions) kubeClient, err := utils.KubeClient(kubeconfigArgs)
if err != nil { if err != nil {
return err return err
} }
@@ -333,15 +319,3 @@ func isHelmReleaseReady(ctx context.Context, kubeClient client.Client,
return apimeta.IsStatusConditionTrue(helmRelease.Status.Conditions, meta.ReadyCondition), nil return apimeta.IsStatusConditionTrue(helmRelease.Status.Conditions, meta.ReadyCondition), nil
} }
} }
func validateStrategy(input string) bool {
allowedStrategy := []string{"Revision", "ChartVersion"}
for _, strategy := range allowedStrategy {
if strategy == input {
return true
}
}
return false
}

View File

@@ -84,6 +84,9 @@ func (obj imagePolicyAdapter) getObservedGeneration() int64 {
} }
func createImagePolicyRun(cmd *cobra.Command, args []string) error { func createImagePolicyRun(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("ImagePolicy name is required")
}
objectName := args[0] objectName := args[0]
if imagePolicyArgs.imageRef == "" { if imagePolicyArgs.imageRef == "" {

View File

@@ -83,6 +83,9 @@ func init() {
} }
func createImageRepositoryRun(cmd *cobra.Command, args []string) error { func createImageRepositoryRun(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("ImageRepository name is required")
}
objectName := args[0] objectName := args[0]
if imageRepoArgs.image == "" { if imageRepoArgs.image == "" {

View File

@@ -23,7 +23,7 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
autov1 "github.com/fluxcd/image-automation-controller/api/v1beta1" autov1 "github.com/fluxcd/image-automation-controller/api/v1beta1"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta2" sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
) )
var createImageUpdateCmd = &cobra.Command{ var createImageUpdateCmd = &cobra.Command{
@@ -49,40 +49,25 @@ mentioned in YAMLs in a git repository.`,
--push-branch=image-updates \ --push-branch=image-updates \
--author-name=flux \ --author-name=flux \
--author-email=flux@example.com \ --author-email=flux@example.com \
--commit-template="{{range .Updated.Images}}{{println .}}{{end}}" --commit-template="{{range .Updated.Images}}{{println .}}{{end}}"`,
# Configure image updates for a Git repository in a different namespace
flux create image update apps \
--namespace=apps \
--git-repo-ref=flux-system \
--git-repo-namespace=flux-system \
--git-repo-path="./clusters/my-cluster" \
--checkout-branch=main \
--push-branch=image-updates \
--author-name=flux \
--author-email=flux@example.com \
--commit-template="{{range .Updated.Images}}{{println .}}{{end}}"
`,
RunE: createImageUpdateRun, RunE: createImageUpdateRun,
} }
type imageUpdateFlags struct { type imageUpdateFlags struct {
gitRepoName string gitRepoRef string
gitRepoNamespace string gitRepoPath string
gitRepoPath string checkoutBranch string
checkoutBranch string pushBranch string
pushBranch string commitTemplate string
commitTemplate string authorName string
authorName string authorEmail string
authorEmail string
} }
var imageUpdateArgs = imageUpdateFlags{} var imageUpdateArgs = imageUpdateFlags{}
func init() { func init() {
flags := createImageUpdateCmd.Flags() flags := createImageUpdateCmd.Flags()
flags.StringVar(&imageUpdateArgs.gitRepoName, "git-repo-ref", "", "the name of a GitRepository resource with details of the upstream Git repository") flags.StringVar(&imageUpdateArgs.gitRepoRef, "git-repo-ref", "", "the name of a GitRepository resource with details of the upstream Git repository")
flags.StringVar(&imageUpdateArgs.gitRepoNamespace, "git-repo-namespace", "", "the namespace of the GitRepository resource, defaults to the ImageUpdateAutomation namespace")
flags.StringVar(&imageUpdateArgs.gitRepoPath, "git-repo-path", "", "path to the directory containing the manifests to be updated, defaults to the repository root") flags.StringVar(&imageUpdateArgs.gitRepoPath, "git-repo-path", "", "path to the directory containing the manifests to be updated, defaults to the repository root")
flags.StringVar(&imageUpdateArgs.checkoutBranch, "checkout-branch", "", "the branch to checkout") flags.StringVar(&imageUpdateArgs.checkoutBranch, "checkout-branch", "", "the branch to checkout")
flags.StringVar(&imageUpdateArgs.pushBranch, "push-branch", "", "the branch to push commits to, defaults to the checkout branch if not specified") flags.StringVar(&imageUpdateArgs.pushBranch, "push-branch", "", "the branch to push commits to, defaults to the checkout branch if not specified")
@@ -94,9 +79,12 @@ func init() {
} }
func createImageUpdateRun(cmd *cobra.Command, args []string) error { func createImageUpdateRun(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("ImageUpdateAutomation name is required")
}
objectName := args[0] objectName := args[0]
if imageUpdateArgs.gitRepoName == "" { if imageUpdateArgs.gitRepoRef == "" {
return fmt.Errorf("a reference to a GitRepository is required (--git-repo-ref)") return fmt.Errorf("a reference to a GitRepository is required (--git-repo-ref)")
} }
@@ -125,9 +113,8 @@ func createImageUpdateRun(cmd *cobra.Command, args []string) error {
}, },
Spec: autov1.ImageUpdateAutomationSpec{ Spec: autov1.ImageUpdateAutomationSpec{
SourceRef: autov1.CrossNamespaceSourceReference{ SourceRef: autov1.CrossNamespaceSourceReference{
Kind: sourcev1.GitRepositoryKind, Kind: sourcev1.GitRepositoryKind,
Name: imageUpdateArgs.gitRepoName, Name: imageUpdateArgs.gitRepoRef,
Namespace: imageUpdateArgs.gitRepoNamespace,
}, },
GitSpec: &autov1.GitSpec{ GitSpec: &autov1.GitSpec{

View File

@@ -119,6 +119,9 @@ func NewKustomizationFlags() kustomizationFlags {
} }
func createKsCmdRun(cmd *cobra.Command, args []string) error { func createKsCmdRun(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("Kustomization name is required")
}
name := args[0] name := args[0]
if kustomizationArgs.path == "" { if kustomizationArgs.path == "" {
@@ -229,7 +232,7 @@ func createKsCmdRun(cmd *cobra.Command, args []string) error {
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel() defer cancel()
kubeClient, err := utils.KubeClient(kubeconfigArgs, kubeclientOptions) kubeClient, err := utils.KubeClient(kubeconfigArgs)
if err != nil { if err != nil {
return err return err
} }

View File

@@ -67,6 +67,9 @@ func init() {
} }
func createReceiverCmdRun(cmd *cobra.Command, args []string) error { func createReceiverCmdRun(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("Receiver name is required")
}
name := args[0] name := args[0]
if receiverArgs.receiverType == "" { if receiverArgs.receiverType == "" {
@@ -127,7 +130,7 @@ func createReceiverCmdRun(cmd *cobra.Command, args []string) error {
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel() defer cancel()
kubeClient, err := utils.KubeClient(kubeconfigArgs, kubeclientOptions) kubeClient, err := utils.KubeClient(kubeconfigArgs)
if err != nil { if err != nil {
return err return err
} }

View File

@@ -112,6 +112,9 @@ func NewSecretGitFlags() secretGitFlags {
} }
func createSecretGitCmdRun(cmd *cobra.Command, args []string) error { func createSecretGitCmdRun(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("secret name is required")
}
name := args[0] name := args[0]
if secretGitArgs.url == "" { if secretGitArgs.url == "" {
return fmt.Errorf("url is required") return fmt.Errorf("url is required")
@@ -173,7 +176,7 @@ func createSecretGitCmdRun(cmd *cobra.Command, args []string) error {
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel() defer cancel()
kubeClient, err := utils.KubeClient(kubeconfigArgs, kubeclientOptions) kubeClient, err := utils.KubeClient(kubeconfigArgs)
if err != nil { if err != nil {
return err return err
} }

View File

@@ -13,7 +13,7 @@ func TestCreateGitSecret(t *testing.T) {
{ {
name: "no args", name: "no args",
args: "create secret git", args: "create secret git",
assert: assertError("name is required"), assert: assertError("secret name is required"),
}, },
{ {
name: "basic secret", name: "basic secret",

View File

@@ -18,6 +18,7 @@ package main
import ( import (
"context" "context"
"fmt"
"github.com/spf13/cobra" "github.com/spf13/cobra"
corev1 "k8s.io/api/core/v1" corev1 "k8s.io/api/core/v1"
@@ -67,6 +68,9 @@ func init() {
} }
func createSecretHelmCmdRun(cmd *cobra.Command, args []string) error { func createSecretHelmCmdRun(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("secret name is required")
}
name := args[0] name := args[0]
labels, err := parseLabels() labels, err := parseLabels()
@@ -96,7 +100,7 @@ func createSecretHelmCmdRun(cmd *cobra.Command, args []string) error {
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel() defer cancel()
kubeClient, err := utils.KubeClient(kubeconfigArgs, kubeclientOptions) kubeClient, err := utils.KubeClient(kubeconfigArgs)
if err != nil { if err != nil {
return err return err
} }

View File

@@ -12,7 +12,7 @@ func TestCreateHelmSecret(t *testing.T) {
}{ }{
{ {
args: "create secret helm", args: "create secret helm",
assert: assertError("name is required"), assert: assertError("secret name is required"),
}, },
{ {
args: "create secret helm helm-secret --username=my-username --password=my-password --namespace=my-namespace --export", args: "create secret helm helm-secret --username=my-username --password=my-password --namespace=my-namespace --export",

View File

@@ -18,6 +18,7 @@ package main
import ( import (
"context" "context"
"fmt"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/spf13/pflag" "github.com/spf13/pflag"
@@ -66,6 +67,9 @@ func init() {
} }
func createSecretTLSCmdRun(cmd *cobra.Command, args []string) error { func createSecretTLSCmdRun(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("secret name is required")
}
name := args[0] name := args[0]
labels, err := parseLabels() labels, err := parseLabels()
@@ -93,7 +97,7 @@ func createSecretTLSCmdRun(cmd *cobra.Command, args []string) error {
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel() defer cancel()
kubeClient, err := utils.KubeClient(kubeconfigArgs, kubeclientOptions) kubeClient, err := utils.KubeClient(kubeconfigArgs)
if err != nil { if err != nil {
return err return err
} }

View File

@@ -12,7 +12,7 @@ func TestCreateTlsSecretNoArgs(t *testing.T) {
}{ }{
{ {
args: "create secret tls", args: "create secret tls",
assert: assertError("name is required"), assert: assertError("secret name is required"),
}, },
{ {
args: "create secret tls certs --namespace=my-namespace --cert-file=./testdata/create_secret/tls/test-cert.pem --key-file=./testdata/create_secret/tls/test-key.pem --export", args: "create secret tls certs --namespace=my-namespace --cert-file=./testdata/create_secret/tls/test-cert.pem --key-file=./testdata/create_secret/tls/test-key.pem --export",

View File

@@ -30,9 +30,7 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client"
"github.com/fluxcd/pkg/apis/meta" "github.com/fluxcd/pkg/apis/meta"
"github.com/fluxcd/pkg/runtime/conditions" sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta2"
"github.com/fluxcd/flux2/internal/flags" "github.com/fluxcd/flux2/internal/flags"
"github.com/fluxcd/flux2/internal/utils" "github.com/fluxcd/flux2/internal/utils"
@@ -95,6 +93,9 @@ func NewSourceBucketFlags() sourceBucketFlags {
} }
func createSourceBucketCmdRun(cmd *cobra.Command, args []string) error { func createSourceBucketCmdRun(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("Bucket source name is required")
}
name := args[0] name := args[0]
if sourceBucketArgs.name == "" { if sourceBucketArgs.name == "" {
@@ -151,7 +152,7 @@ func createSourceBucketCmdRun(cmd *cobra.Command, args []string) error {
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel() defer cancel()
kubeClient, err := utils.KubeClient(kubeconfigArgs, kubeclientOptions) kubeClient, err := utils.KubeClient(kubeconfigArgs)
if err != nil { if err != nil {
return err return err
} }
@@ -237,30 +238,3 @@ func upsertBucket(ctx context.Context, kubeClient client.Client,
logger.Successf("Bucket source updated") logger.Successf("Bucket source updated")
return namespacedName, nil return namespacedName, nil
} }
func isBucketReady(ctx context.Context, kubeClient client.Client,
namespacedName types.NamespacedName, bucket *sourcev1.Bucket) wait.ConditionFunc {
return func() (bool, error) {
err := kubeClient.Get(ctx, namespacedName, bucket)
if err != nil {
return false, err
}
if c := conditions.Get(bucket, meta.ReadyCondition); c != nil {
// Confirm the Ready condition we are observing is for the
// current generation
if c.ObservedGeneration != bucket.GetGeneration() {
return false, nil
}
// Further check the Status
switch c.Status {
case metav1.ConditionTrue:
return true, nil
case metav1.ConditionFalse:
return false, fmt.Errorf(c.Message)
}
}
return false, nil
}
}

View File

@@ -23,21 +23,19 @@ import (
"net/url" "net/url"
"os" "os"
"github.com/fluxcd/pkg/apis/meta"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
"github.com/manifoldco/promptui" "github.com/manifoldco/promptui"
"github.com/spf13/cobra" "github.com/spf13/cobra"
corev1 "k8s.io/api/core/v1" corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/errors"
apimeta "k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/wait" "k8s.io/apimachinery/pkg/util/wait"
"sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/yaml" "sigs.k8s.io/yaml"
"github.com/fluxcd/pkg/apis/meta"
"github.com/fluxcd/pkg/runtime/conditions"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta2"
"github.com/fluxcd/flux2/internal/flags" "github.com/fluxcd/flux2/internal/flags"
"github.com/fluxcd/flux2/internal/utils" "github.com/fluxcd/flux2/internal/utils"
"github.com/fluxcd/flux2/pkg/manifestgen/sourcesecret" "github.com/fluxcd/flux2/pkg/manifestgen/sourcesecret"
@@ -152,6 +150,9 @@ func newSourceGitFlags() sourceGitFlags {
} }
func createSourceGitCmdRun(cmd *cobra.Command, args []string) error { func createSourceGitCmdRun(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("GitRepository source name is required")
}
name := args[0] name := args[0]
if sourceGitArgs.url == "" { if sourceGitArgs.url == "" {
@@ -171,7 +172,7 @@ func createSourceGitCmdRun(cmd *cobra.Command, args []string) error {
} }
if sourceGitArgs.caFile != "" && u.Scheme == "ssh" { if sourceGitArgs.caFile != "" && u.Scheme == "ssh" {
return fmt.Errorf("specifying a CA file is not supported for Git over SSH") return fmt.Errorf("specifing a CA file is not supported for Git over SSH")
} }
if sourceGitArgs.recurseSubmodules && sourceGitArgs.gitImplementation == sourcev1.LibGit2Implementation { if sourceGitArgs.recurseSubmodules && sourceGitArgs.gitImplementation == sourcev1.LibGit2Implementation {
@@ -234,7 +235,7 @@ func createSourceGitCmdRun(cmd *cobra.Command, args []string) error {
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel() defer cancel()
kubeClient, err := utils.KubeClient(kubeconfigArgs, kubeclientOptions) kubeClient, err := utils.KubeClient(kubeconfigArgs)
if err != nil { if err != nil {
return err return err
} }
@@ -357,14 +358,7 @@ func isGitRepositoryReady(ctx context.Context, kubeClient client.Client,
return false, err return false, err
} }
if c := conditions.Get(gitRepository, meta.ReadyCondition); c != nil { if c := apimeta.FindStatusCondition(gitRepository.Status.Conditions, meta.ReadyCondition); c != nil {
// Confirm the Ready condition we are observing is for the
// current generation
if c.ObservedGeneration != gitRepository.GetGeneration() {
return false, nil
}
// Further check the Status
switch c.Status { switch c.Status {
case metav1.ConditionTrue: case metav1.ConditionTrue:
return true, nil return true, nil

View File

@@ -21,17 +21,15 @@ package main
import ( import (
"context" "context"
"testing"
"time"
"github.com/fluxcd/pkg/apis/meta" "github.com/fluxcd/pkg/apis/meta"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta2" sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
"k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/errors"
apimeta "k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/wait" "k8s.io/apimachinery/pkg/util/wait"
"sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client"
"testing"
"time"
) )
var pollInterval = 50 * time.Millisecond var pollInterval = 50 * time.Millisecond
@@ -98,21 +96,14 @@ func TestCreateSourceGit(t *testing.T) {
{ {
"NoArgs", "NoArgs",
"create source git", "create source git",
assertError("name is required"), assertError("GitRepository source name is required"),
nil, nil,
}, { }, {
"Succeeded", "Succeeded",
command, command,
assertGoldenFile("testdata/create_source_git/success.golden"), assertGoldenFile("testdata/create_source_git/success.golden"),
func(repo *sourcev1.GitRepository) { func(repo *sourcev1.GitRepository) {
newCondition := metav1.Condition{ meta.SetResourceCondition(repo, meta.ReadyCondition, metav1.ConditionTrue, sourcev1.GitOperationSucceedReason, "succeeded message")
Type: meta.ReadyCondition,
Status: metav1.ConditionTrue,
Reason: sourcev1.GitOperationSucceedReason,
Message: "succeeded message",
ObservedGeneration: repo.GetGeneration(),
}
apimeta.SetStatusCondition(&repo.Status.Conditions, newCondition)
repo.Status.Artifact = &sourcev1.Artifact{ repo.Status.Artifact = &sourcev1.Artifact{
Path: "some-path", Path: "some-path",
Revision: "v1", Revision: "v1",
@@ -123,14 +114,7 @@ func TestCreateSourceGit(t *testing.T) {
command, command,
assertError("failed message"), assertError("failed message"),
func(repo *sourcev1.GitRepository) { func(repo *sourcev1.GitRepository) {
newCondition := metav1.Condition{ meta.SetResourceCondition(repo, meta.ReadyCondition, metav1.ConditionFalse, sourcev1.URLInvalidReason, "failed message")
Type: meta.ReadyCondition,
Status: metav1.ConditionFalse,
Reason: sourcev1.URLInvalidReason,
Message: "failed message",
ObservedGeneration: repo.GetGeneration(),
}
apimeta.SetStatusCondition(&repo.Status.Conditions, newCondition)
}, },
}, { }, {
"NoArtifact", "NoArtifact",
@@ -138,14 +122,7 @@ func TestCreateSourceGit(t *testing.T) {
assertError("GitRepository source reconciliation completed but no artifact was found"), assertError("GitRepository source reconciliation completed but no artifact was found"),
func(repo *sourcev1.GitRepository) { func(repo *sourcev1.GitRepository) {
// Updated with no artifact // Updated with no artifact
newCondition := metav1.Condition{ meta.SetResourceCondition(repo, meta.ReadyCondition, metav1.ConditionTrue, sourcev1.GitOperationSucceedReason, "succeeded message")
Type: meta.ReadyCondition,
Status: metav1.ConditionTrue,
Reason: sourcev1.GitOperationSucceedReason,
Message: "succeeded message",
ObservedGeneration: repo.GetGeneration(),
}
apimeta.SetStatusCondition(&repo.Status.Conditions, newCondition)
}, },
}, },
} }

View File

@@ -23,17 +23,17 @@ import (
"os" "os"
"github.com/fluxcd/pkg/apis/meta" "github.com/fluxcd/pkg/apis/meta"
"github.com/fluxcd/pkg/runtime/conditions"
"github.com/spf13/cobra" "github.com/spf13/cobra"
corev1 "k8s.io/api/core/v1" corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/errors"
apimeta "k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/wait" "k8s.io/apimachinery/pkg/util/wait"
"sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/yaml" "sigs.k8s.io/yaml"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta2" sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
"github.com/fluxcd/flux2/internal/utils" "github.com/fluxcd/flux2/internal/utils"
"github.com/fluxcd/flux2/pkg/manifestgen/sourcesecret" "github.com/fluxcd/flux2/pkg/manifestgen/sourcesecret"
@@ -91,6 +91,9 @@ func init() {
} }
func createSourceHelmCmdRun(cmd *cobra.Command, args []string) error { func createSourceHelmCmdRun(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("HelmRepository source name is required")
}
name := args[0] name := args[0]
if sourceHelmArgs.url == "" { if sourceHelmArgs.url == "" {
@@ -144,7 +147,7 @@ func createSourceHelmCmdRun(cmd *cobra.Command, args []string) error {
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel() defer cancel()
kubeClient, err := utils.KubeClient(kubeconfigArgs, kubeclientOptions) kubeClient, err := utils.KubeClient(kubeconfigArgs)
if err != nil { if err != nil {
return err return err
} }
@@ -242,14 +245,12 @@ func isHelmRepositoryReady(ctx context.Context, kubeClient client.Client,
return false, err return false, err
} }
if c := conditions.Get(helmRepository, meta.ReadyCondition); c != nil { // Confirm the state we are observing is for the current generation
// Confirm the Ready condition we are observing is for the if helmRepository.Generation != helmRepository.Status.ObservedGeneration {
// current generation return false, nil
if c.ObservedGeneration != helmRepository.GetGeneration() { }
return false, nil
}
// Further check the Status if c := apimeta.FindStatusCondition(helmRepository.Status.Conditions, meta.ReadyCondition); c != nil {
switch c.Status { switch c.Status {
case metav1.ConditionTrue: case metav1.ConditionTrue:
return true, nil return true, nil

View File

@@ -70,6 +70,9 @@ func init() {
} }
func createTenantCmdRun(cmd *cobra.Command, args []string) error { func createTenantCmdRun(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("tenant name is required")
}
tenant := args[0] tenant := args[0]
if err := validation.IsQualifiedName(tenant); len(err) > 0 { if err := validation.IsQualifiedName(tenant); len(err) > 0 {
return fmt.Errorf("invalid tenant name '%s': %v", tenant, err) return fmt.Errorf("invalid tenant name '%s': %v", tenant, err)
@@ -156,7 +159,7 @@ func createTenantCmdRun(cmd *cobra.Command, args []string) error {
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel() defer cancel()
kubeClient, err := utils.KubeClient(kubeconfigArgs, kubeclientOptions) kubeClient, err := utils.KubeClient(kubeconfigArgs)
if err != nil { if err != nil {
return err return err
} }

View File

@@ -1,55 +0,0 @@
package main
import (
"testing"
"k8s.io/apimachinery/pkg/util/rand"
)
func Test_validateObjectName(t *testing.T) {
tests := []struct {
name string
valid bool
}{
{
name: "flux-system",
valid: true,
},
{
name: "-flux-system",
valid: false,
},
{
name: "-flux-system-",
valid: false,
},
{
name: "third.first",
valid: false,
},
{
name: "THirdfirst",
valid: false,
},
{
name: "THirdfirst",
valid: false,
},
{
name: rand.String(63),
valid: true,
},
{
name: rand.String(64),
valid: false,
},
}
for _, tt := range tests {
valid := validateObjectName(tt.name)
if valid != tt.valid {
t.Errorf("expected name %q to return %t for validateObjectName func but got %t",
tt.name, tt.valid, valid)
}
}
}

View File

@@ -60,7 +60,7 @@ func (del deleteCommand) run(cmd *cobra.Command, args []string) error {
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel() defer cancel()
kubeClient, err := utils.KubeClient(kubeconfigArgs, kubeclientOptions) kubeClient, err := utils.KubeClient(kubeconfigArgs)
if err != nil { if err != nil {
return err return err
} }

View File

@@ -27,7 +27,7 @@ var deleteKsCmd = &cobra.Command{
Aliases: []string{"ks"}, Aliases: []string{"ks"},
Short: "Delete a Kustomization resource", Short: "Delete a Kustomization resource",
Long: "The delete kustomization command deletes the given Kustomization from the cluster.", Long: "The delete kustomization command deletes the given Kustomization from the cluster.",
Example: ` # Delete a kustomization and the Kubernetes resources created by it when prune is enabled Example: ` # Delete a kustomization and the Kubernetes resources created by it
flux delete kustomization podinfo`, flux delete kustomization podinfo`,
ValidArgsFunction: resourceNamesCompletionFunc(kustomizev1.GroupVersion.WithKind(kustomizev1.KustomizationKind)), ValidArgsFunction: resourceNamesCompletionFunc(kustomizev1.GroupVersion.WithKind(kustomizev1.KustomizationKind)),
RunE: deleteCommand{ RunE: deleteCommand{

View File

@@ -19,7 +19,7 @@ package main
import ( import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta2" sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
) )
var deleteSourceBucketCmd = &cobra.Command{ var deleteSourceBucketCmd = &cobra.Command{

View File

@@ -19,7 +19,7 @@ package main
import ( import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta2" sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
) )
var deleteSourceGitCmd = &cobra.Command{ var deleteSourceGitCmd = &cobra.Command{

View File

@@ -19,7 +19,7 @@ package main
import ( import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta2" sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
) )
var deleteSourceHelmCmd = &cobra.Command{ var deleteSourceHelmCmd = &cobra.Command{

View File

@@ -23,7 +23,7 @@ import (
var diffCmd = &cobra.Command{ var diffCmd = &cobra.Command{
Use: "diff", Use: "diff",
Short: "Diff a flux resource", Short: "Diff a flux resource",
Long: "The diff command is used to do a server-side dry-run on flux resources, then prints the diff.", Long: "The diff command is used to do a server-side dry-run on flux resources, then output the diff.",
} }
func init() { func init() {

View File

@@ -31,29 +31,21 @@ var diffKsCmd = &cobra.Command{
Use: "kustomization", Use: "kustomization",
Aliases: []string{"ks"}, Aliases: []string{"ks"},
Short: "Diff Kustomization", Short: "Diff Kustomization",
Long: `The diff command does a build, then it performs a server-side dry-run and prints the diff. Long: `The diff command does a build, then it performs a server-side dry-run and output the diff.`,
Exit status: 0 No differences were found. 1 Differences were found. >1 diff failed with an error.`, Example: `# Preview changes local changes as they were applied on the cluster
Example: `# Preview local changes as they were applied on the cluster flux diff kustomization my-app --path ./path/to/local/manifests`,
flux diff kustomization my-app --path ./path/to/local/manifests
# Preview using a local flux kustomization file
flux diff kustomization my-app --path ./path/to/local/manifests --kustomization-file ./path/to/local/my-app.yaml`,
ValidArgsFunction: resourceNamesCompletionFunc(kustomizev1.GroupVersion.WithKind(kustomizev1.KustomizationKind)), ValidArgsFunction: resourceNamesCompletionFunc(kustomizev1.GroupVersion.WithKind(kustomizev1.KustomizationKind)),
RunE: diffKsCmdRun, RunE: diffKsCmdRun,
} }
type diffKsFlags struct { type diffKsFlags struct {
kustomizationFile string path string
path string
progressBar bool
} }
var diffKsArgs diffKsFlags var diffKsArgs diffKsFlags
func init() { func init() {
diffKsCmd.Flags().StringVar(&diffKsArgs.path, "path", "", "Path to a local directory that matches the specified Kustomization.spec.path.") diffKsCmd.Flags().StringVar(&diffKsArgs.path, "path", "", "Path to a local directory that matches the specified Kustomization.spec.path.)")
diffKsCmd.Flags().BoolVar(&diffKsArgs.progressBar, "progress-bar", true, "Boolean to set the progress bar. The default value is true.")
diffKsCmd.Flags().StringVar(&diffKsArgs.kustomizationFile, "kustomization-file", "", "Path to the Flux Kustomization YAML file.")
diffCmd.AddCommand(diffKsCmd) diffCmd.AddCommand(diffKsCmd)
} }
@@ -64,29 +56,16 @@ func diffKsCmdRun(cmd *cobra.Command, args []string) error {
name := args[0] name := args[0]
if diffKsArgs.path == "" { if diffKsArgs.path == "" {
return &RequestError{StatusCode: 2, Err: fmt.Errorf("invalid resource path %q", diffKsArgs.path)} return fmt.Errorf("invalid resource path %q", diffKsArgs.path)
} }
if fs, err := os.Stat(diffKsArgs.path); err != nil || !fs.IsDir() { if fs, err := os.Stat(diffKsArgs.path); err != nil || !fs.IsDir() {
return &RequestError{StatusCode: 2, Err: fmt.Errorf("invalid resource path %q", diffKsArgs.path)} return fmt.Errorf("invalid resource path %q", diffKsArgs.path)
}
if diffKsArgs.kustomizationFile != "" {
if fs, err := os.Stat(diffKsArgs.kustomizationFile); os.IsNotExist(err) || fs.IsDir() {
return fmt.Errorf("invalid kustomization file %q", diffKsArgs.kustomizationFile)
}
}
var builder *build.Builder
var err error
if diffKsArgs.progressBar {
builder, err = build.NewBuilder(kubeconfigArgs, kubeclientOptions, name, diffKsArgs.path, build.WithTimeout(rootArgs.timeout), build.WithKustomizationFile(diffKsArgs.kustomizationFile), build.WithProgressBar())
} else {
builder, err = build.NewBuilder(kubeconfigArgs, kubeclientOptions, name, diffKsArgs.path, build.WithTimeout(rootArgs.timeout), build.WithKustomizationFile(diffKsArgs.kustomizationFile))
} }
builder, err := build.NewBuilder(kubeconfigArgs, name, diffKsArgs.path, build.WithTimeout(rootArgs.timeout))
if err != nil { if err != nil {
return &RequestError{StatusCode: 2, Err: err} return err
} }
// create a signal channel // create a signal channel
@@ -95,18 +74,13 @@ func diffKsCmdRun(cmd *cobra.Command, args []string) error {
errChan := make(chan error) errChan := make(chan error)
go func() { go func() {
output, hasChanged, err := builder.Diff() output, err := builder.Diff()
if err != nil { if err != nil {
errChan <- &RequestError{StatusCode: 2, Err: err} errChan <- err
} }
cmd.Print(output) 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 { select {

View File

@@ -45,59 +45,47 @@ func TestDiffKustomization(t *testing.T) {
}, },
{ {
name: "diff nothing deployed", name: "diff nothing deployed",
args: "diff kustomization podinfo --path ./testdata/build-kustomization/podinfo --progress-bar=false", args: "diff kustomization podinfo --path ./testdata/build-kustomization/podinfo",
objectFile: "", objectFile: "",
assert: assertGoldenFile("./testdata/diff-kustomization/nothing-is-deployed.golden"), assert: assertGoldenFile("./testdata/diff-kustomization/nothing-is-deployed.golden"),
}, },
{ {
name: "diff with a deployment object", name: "diff with a deployment object",
args: "diff kustomization podinfo --path ./testdata/build-kustomization/podinfo --progress-bar=false", args: "diff kustomization podinfo --path ./testdata/build-kustomization/podinfo",
objectFile: "./testdata/diff-kustomization/deployment.yaml", objectFile: "./testdata/diff-kustomization/deployment.yaml",
assert: assertGoldenFile("./testdata/diff-kustomization/diff-with-deployment.golden"), assert: assertGoldenFile("./testdata/diff-kustomization/diff-with-deployment.golden"),
}, },
{ {
name: "diff with a drifted service object", name: "diff with a drifted service object",
args: "diff kustomization podinfo --path ./testdata/build-kustomization/podinfo --progress-bar=false", args: "diff kustomization podinfo --path ./testdata/build-kustomization/podinfo",
objectFile: "./testdata/diff-kustomization/service.yaml", objectFile: "./testdata/diff-kustomization/service.yaml",
assert: assertGoldenFile("./testdata/diff-kustomization/diff-with-drifted-service.golden"), assert: assertGoldenFile("./testdata/diff-kustomization/diff-with-drifted-service.golden"),
}, },
{ {
name: "diff with a drifted secret object", name: "diff with a drifted secret object",
args: "diff kustomization podinfo --path ./testdata/build-kustomization/podinfo --progress-bar=false", args: "diff kustomization podinfo --path ./testdata/build-kustomization/podinfo",
objectFile: "./testdata/diff-kustomization/secret.yaml", objectFile: "./testdata/diff-kustomization/secret.yaml",
assert: assertGoldenFile("./testdata/diff-kustomization/diff-with-drifted-secret.golden"), assert: assertGoldenFile("./testdata/diff-kustomization/diff-with-drifted-secret.golden"),
}, },
{ {
name: "diff with a drifted key in sops secret object", name: "diff with a drifted key in sops secret object",
args: "diff kustomization podinfo --path ./testdata/build-kustomization/podinfo --progress-bar=false", args: "diff kustomization podinfo --path ./testdata/build-kustomization/podinfo",
objectFile: "./testdata/diff-kustomization/key-sops-secret.yaml", objectFile: "./testdata/diff-kustomization/key-sops-secret.yaml",
assert: assertGoldenFile("./testdata/diff-kustomization/diff-with-drifted-key-sops-secret.golden"), assert: assertGoldenFile("./testdata/diff-kustomization/diff-with-drifted-key-sops-secret.golden"),
}, },
{ {
name: "diff with a drifted value in sops secret object", name: "diff with a drifted value in sops secret object",
args: "diff kustomization podinfo --path ./testdata/build-kustomization/podinfo --progress-bar=false", args: "diff kustomization podinfo --path ./testdata/build-kustomization/podinfo",
objectFile: "./testdata/diff-kustomization/value-sops-secret.yaml", objectFile: "./testdata/diff-kustomization/value-sops-secret.yaml",
assert: assertGoldenFile("./testdata/diff-kustomization/diff-with-drifted-value-sops-secret.golden"), assert: assertGoldenFile("./testdata/diff-kustomization/diff-with-drifted-value-sops-secret.golden"),
}, },
{
name: "diff with a sops dockerconfigjson secret object",
args: "diff kustomization podinfo --path ./testdata/build-kustomization/podinfo --progress-bar=false",
objectFile: "./testdata/diff-kustomization/dockerconfigjson-sops-secret.yaml",
assert: assertGoldenFile("./testdata/diff-kustomization/diff-with-dockerconfigjson-sops-secret.golden"),
},
{
name: "diff with a sops stringdata secret object",
args: "diff kustomization podinfo --path ./testdata/build-kustomization/podinfo --progress-bar=false",
objectFile: "./testdata/diff-kustomization/stringdata-sops-secret.yaml",
assert: assertGoldenFile("./testdata/diff-kustomization/diff-with-drifted-stringdata-sops-secret.golden"),
},
} }
tmpl := map[string]string{ tmpl := map[string]string{
"fluxns": allocateNamespace("flux-system"), "fluxns": allocateNamespace("flux-system"),
} }
b, _ := build.NewBuilder(kubeconfigArgs, kubeclientOptions, "podinfo", "") b, _ := build.NewBuilder(kubeconfigArgs, "podinfo", "")
resourceManager, err := b.Manager() resourceManager, err := b.Manager()
if err != nil { if err != nil {
@@ -137,9 +125,5 @@ func createObjectFromFile(objectFile string, templateValues map[string]string, t
t.Fatalf("Error decoding yaml file '%s': %v", objectFile, err) t.Fatalf("Error decoding yaml file '%s': %v", objectFile, err)
} }
if err := ssa.SetNativeKindsDefaults(clientObjects); err != nil {
t.Fatalf("Error setting native kinds defaults for '%s': %v", objectFile, err)
}
return clientObjects return clientObjects
} }

View File

@@ -74,7 +74,7 @@ func (export exportCommand) run(cmd *cobra.Command, args []string) error {
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel() defer cancel()
kubeClient, err := utils.KubeClient(kubeconfigArgs, kubeclientOptions) kubeClient, err := utils.KubeClient(kubeconfigArgs)
if err != nil { if err != nil {
return err return err
} }

View File

@@ -59,7 +59,7 @@ func (export exportWithSecretCommand) run(cmd *cobra.Command, args []string) err
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel() defer cancel()
kubeClient, err := utils.KubeClient(kubeconfigArgs, kubeclientOptions) kubeClient, err := utils.KubeClient(kubeconfigArgs)
if err != nil { if err != nil {
return err return err
} }

View File

@@ -21,7 +21,7 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/types"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta2" sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
) )
var exportSourceBucketCmd = &cobra.Command{ var exportSourceBucketCmd = &cobra.Command{

View File

@@ -21,7 +21,7 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/types"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta2" sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
) )
var exportSourceGitCmd = &cobra.Command{ var exportSourceGitCmd = &cobra.Command{

View File

@@ -21,7 +21,7 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/types"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta2" sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
) )
var exportSourceHelmCmd = &cobra.Command{ var exportSourceHelmCmd = &cobra.Command{

View File

@@ -33,7 +33,6 @@ import (
"github.com/fluxcd/pkg/apis/meta" "github.com/fluxcd/pkg/apis/meta"
"github.com/fluxcd/flux2/internal/utils" "github.com/fluxcd/flux2/internal/utils"
"github.com/fluxcd/flux2/pkg/printers"
) )
type deriveType func(runtime.Object) (summarisable, error) type deriveType func(runtime.Object) (summarisable, error)
@@ -136,7 +135,7 @@ func (get getCommand) run(cmd *cobra.Command, args []string) error {
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel() defer cancel()
kubeClient, err := utils.KubeClient(kubeconfigArgs, kubeclientOptions) kubeClient, err := utils.KubeClient(kubeconfigArgs)
if err != nil { if err != nil {
return err return err
} }
@@ -178,10 +177,7 @@ func (get getCommand) run(cmd *cobra.Command, args []string) error {
return err return err
} }
err = printers.TablePrinter(header).Print(cmd.OutOrStdout(), rows) utils.PrintTable(cmd.OutOrStdout(), header, rows)
if err != nil {
return err
}
if getAll { if getAll {
fmt.Println() fmt.Println()
@@ -246,16 +242,10 @@ func watchUntil(ctx context.Context, w watch.Interface, get *getCommand) (bool,
return false, err return false, err
} }
if firstIteration { if firstIteration {
err = printers.TablePrinter(header).Print(os.Stdout, rows) utils.PrintTable(os.Stdout, header, rows)
if err != nil {
return false, err
}
firstIteration = false firstIteration = false
} else { } else {
err = printers.TablePrinter([]string{}).Print(os.Stdout, rows) utils.PrintTable(os.Stdout, []string{}, rows)
if err != nil {
return false, err
}
} }
return false, nil return false, nil

View File

@@ -77,11 +77,11 @@ func init() {
func (s alertListAdapter) summariseItem(i int, includeNamespace bool, includeKind bool) []string { func (s alertListAdapter) summariseItem(i int, includeNamespace bool, includeKind bool) []string {
item := s.Items[i] item := s.Items[i]
status, msg := statusAndMessage(item.Status.Conditions) status, msg := statusAndMessage(item.Status.Conditions)
return append(nameColumns(&item, includeNamespace, includeKind), strings.Title(strconv.FormatBool(item.Spec.Suspend)), status, msg) return append(nameColumns(&item, includeNamespace, includeKind), status, msg, strings.Title(strconv.FormatBool(item.Spec.Suspend)))
} }
func (s alertListAdapter) headers(includeNamespace bool) []string { func (s alertListAdapter) headers(includeNamespace bool) []string {
headers := []string{"Name", "Suspended", "Ready", "Message"} headers := []string{"Name", "Ready", "Message", "Suspended"}
if includeNamespace { if includeNamespace {
return append(namespaceHeader, headers...) return append(namespaceHeader, headers...)
} }

View File

@@ -75,11 +75,11 @@ func (a helmReleaseListAdapter) summariseItem(i int, includeNamespace bool, incl
revision := item.Status.LastAppliedRevision revision := item.Status.LastAppliedRevision
status, msg := statusAndMessage(item.Status.Conditions) status, msg := statusAndMessage(item.Status.Conditions)
return append(nameColumns(&item, includeNamespace, includeKind), return append(nameColumns(&item, includeNamespace, includeKind),
revision, strings.Title(strconv.FormatBool(item.Spec.Suspend)), status, msg) status, msg, revision, strings.Title(strconv.FormatBool(item.Spec.Suspend)))
} }
func (a helmReleaseListAdapter) headers(includeNamespace bool) []string { func (a helmReleaseListAdapter) headers(includeNamespace bool) []string {
headers := []string{"Name", "Revision", "Suspended", "Ready", "Message"} headers := []string{"Name", "Ready", "Message", "Revision", "Suspended"}
if includeNamespace { if includeNamespace {
headers = append([]string{"Namespace"}, headers...) headers = append([]string{"Namespace"}, headers...)
} }

View File

@@ -74,11 +74,11 @@ func init() {
func (s imagePolicyListAdapter) summariseItem(i int, includeNamespace bool, includeKind bool) []string { func (s imagePolicyListAdapter) summariseItem(i int, includeNamespace bool, includeKind bool) []string {
item := s.Items[i] item := s.Items[i]
status, msg := statusAndMessage(item.Status.Conditions) status, msg := statusAndMessage(item.Status.Conditions)
return append(nameColumns(&item, includeNamespace, includeKind), item.Status.LatestImage, status, msg) return append(nameColumns(&item, includeNamespace, includeKind), status, msg, item.Status.LatestImage)
} }
func (s imagePolicyListAdapter) headers(includeNamespace bool) []string { func (s imagePolicyListAdapter) headers(includeNamespace bool) []string {
headers := []string{"Name", "Latest image", "Ready", "Message"} headers := []string{"Name", "Ready", "Message", "Latest image"}
if includeNamespace { if includeNamespace {
return append(namespaceHeader, headers...) return append(namespaceHeader, headers...)
} }

View File

@@ -82,11 +82,11 @@ func (s imageRepositoryListAdapter) summariseItem(i int, includeNamespace bool,
lastScan = item.Status.LastScanResult.ScanTime.Time.Format(time.RFC3339) lastScan = item.Status.LastScanResult.ScanTime.Time.Format(time.RFC3339)
} }
return append(nameColumns(&item, includeNamespace, includeKind), return append(nameColumns(&item, includeNamespace, includeKind),
lastScan, strings.Title(strconv.FormatBool(item.Spec.Suspend)), status, msg) status, msg, lastScan, strings.Title(strconv.FormatBool(item.Spec.Suspend)))
} }
func (s imageRepositoryListAdapter) headers(includeNamespace bool) []string { func (s imageRepositoryListAdapter) headers(includeNamespace bool) []string {
headers := []string{"Name", "Last scan", "Suspended", "Ready", "Message"} headers := []string{"Name", "Ready", "Message", "Last scan", "Suspended"}
if includeNamespace { if includeNamespace {
return append(namespaceHeader, headers...) return append(namespaceHeader, headers...)
} }

View File

@@ -81,11 +81,11 @@ func (s imageUpdateAutomationListAdapter) summariseItem(i int, includeNamespace
if item.Status.LastAutomationRunTime != nil { if item.Status.LastAutomationRunTime != nil {
lastRun = item.Status.LastAutomationRunTime.Time.Format(time.RFC3339) lastRun = item.Status.LastAutomationRunTime.Time.Format(time.RFC3339)
} }
return append(nameColumns(&item, includeNamespace, includeKind), lastRun, strings.Title(strconv.FormatBool(item.Spec.Suspend)), status, msg) return append(nameColumns(&item, includeNamespace, includeKind), status, msg, lastRun, strings.Title(strconv.FormatBool(item.Spec.Suspend)))
} }
func (s imageUpdateAutomationListAdapter) headers(includeNamespace bool) []string { func (s imageUpdateAutomationListAdapter) headers(includeNamespace bool) []string {
headers := []string{"Name", "Last run", "Suspended", "Ready", "Message"} headers := []string{"Name", "Ready", "Message", "Last run", "Suspended"}
if includeNamespace { if includeNamespace {
return append(namespaceHeader, headers...) return append(namespaceHeader, headers...)
} }

View File

@@ -85,11 +85,11 @@ func (a kustomizationListAdapter) summariseItem(i int, includeNamespace bool, in
msg = shortenCommitSha(msg) msg = shortenCommitSha(msg)
} }
return append(nameColumns(&item, includeNamespace, includeKind), return append(nameColumns(&item, includeNamespace, includeKind),
revision, strings.Title(strconv.FormatBool(item.Spec.Suspend)), status, msg) status, msg, revision, strings.Title(strconv.FormatBool(item.Spec.Suspend)))
} }
func (a kustomizationListAdapter) headers(includeNamespace bool) []string { func (a kustomizationListAdapter) headers(includeNamespace bool) []string {
headers := []string{"Name", "Revision", "Suspended", "Ready", "Message"} headers := []string{"Name", "Ready", "Message", "Revision", "Suspended"}
if includeNamespace { if includeNamespace {
headers = append([]string{"Namespace"}, headers...) headers = append([]string{"Namespace"}, headers...)
} }

View File

@@ -74,11 +74,11 @@ func init() {
func (s receiverListAdapter) summariseItem(i int, includeNamespace bool, includeKind bool) []string { func (s receiverListAdapter) summariseItem(i int, includeNamespace bool, includeKind bool) []string {
item := s.Items[i] item := s.Items[i]
status, msg := statusAndMessage(item.Status.Conditions) status, msg := statusAndMessage(item.Status.Conditions)
return append(nameColumns(&item, includeNamespace, includeKind), strings.Title(strconv.FormatBool(item.Spec.Suspend)), status, msg) return append(nameColumns(&item, includeNamespace, includeKind), status, msg, strings.Title(strconv.FormatBool(item.Spec.Suspend)))
} }
func (s receiverListAdapter) headers(includeNamespace bool) []string { func (s receiverListAdapter) headers(includeNamespace bool) []string {
headers := []string{"Name", "Suspended", "Ready", "Message"} headers := []string{"Name", "Ready", "Message", "Suspended"}
if includeNamespace { if includeNamespace {
return append(namespaceHeader, headers...) return append(namespaceHeader, headers...)
} }

View File

@@ -21,7 +21,7 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta2" sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
) )
var getSourceAllCmd = &cobra.Command{ var getSourceAllCmd = &cobra.Command{

View File

@@ -24,7 +24,7 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta2" sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
) )
var getSourceBucketCmd = &cobra.Command{ var getSourceBucketCmd = &cobra.Command{
@@ -81,11 +81,11 @@ func (a *bucketListAdapter) summariseItem(i int, includeNamespace bool, includeK
} }
status, msg := statusAndMessage(item.Status.Conditions) status, msg := statusAndMessage(item.Status.Conditions)
return append(nameColumns(&item, includeNamespace, includeKind), return append(nameColumns(&item, includeNamespace, includeKind),
revision, strings.Title(strconv.FormatBool(item.Spec.Suspend)), status, msg) status, msg, revision, strings.Title(strconv.FormatBool(item.Spec.Suspend)))
} }
func (a bucketListAdapter) headers(includeNamespace bool) []string { func (a bucketListAdapter) headers(includeNamespace bool) []string {
headers := []string{"Name", "Revision", "Suspended", "Ready", "Message"} headers := []string{"Name", "Ready", "Message", "Revision", "Suspended"}
if includeNamespace { if includeNamespace {
headers = append([]string{"Namespace"}, headers...) headers = append([]string{"Namespace"}, headers...)
} }

View File

@@ -24,7 +24,7 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta2" sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
) )
var getSourceHelmChartCmd = &cobra.Command{ var getSourceHelmChartCmd = &cobra.Command{
@@ -81,11 +81,11 @@ func (a *helmChartListAdapter) summariseItem(i int, includeNamespace bool, inclu
} }
status, msg := statusAndMessage(item.Status.Conditions) status, msg := statusAndMessage(item.Status.Conditions)
return append(nameColumns(&item, includeNamespace, includeKind), return append(nameColumns(&item, includeNamespace, includeKind),
revision, strings.Title(strconv.FormatBool(item.Spec.Suspend)), status, msg) status, msg, revision, strings.Title(strconv.FormatBool(item.Spec.Suspend)))
} }
func (a helmChartListAdapter) headers(includeNamespace bool) []string { func (a helmChartListAdapter) headers(includeNamespace bool) []string {
headers := []string{"Name", "Revision", "Suspended", "Ready", "Message"} headers := []string{"Name", "Ready", "Message", "Revision", "Suspended"}
if includeNamespace { if includeNamespace {
headers = append([]string{"Namespace"}, headers...) headers = append([]string{"Namespace"}, headers...)
} }

View File

@@ -25,7 +25,7 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta2" sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
) )
var getSourceGitCmd = &cobra.Command{ var getSourceGitCmd = &cobra.Command{
@@ -86,11 +86,11 @@ func (a *gitRepositoryListAdapter) summariseItem(i int, includeNamespace bool, i
msg = shortenCommitSha(msg) msg = shortenCommitSha(msg)
} }
return append(nameColumns(&item, includeNamespace, includeKind), return append(nameColumns(&item, includeNamespace, includeKind),
revision, strings.Title(strconv.FormatBool(item.Spec.Suspend)), status, msg) status, msg, revision, strings.Title(strconv.FormatBool(item.Spec.Suspend)))
} }
func (a gitRepositoryListAdapter) headers(includeNamespace bool) []string { func (a gitRepositoryListAdapter) headers(includeNamespace bool) []string {
headers := []string{"Name", "Revision", "Suspended", "Ready", "Message"} headers := []string{"Name", "Ready", "Message", "Revision", "Suspended"}
if includeNamespace { if includeNamespace {
headers = append([]string{"Namespace"}, headers...) headers = append([]string{"Namespace"}, headers...)
} }

View File

@@ -24,7 +24,7 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta2" sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
) )
var getSourceHelmCmd = &cobra.Command{ var getSourceHelmCmd = &cobra.Command{
@@ -81,11 +81,11 @@ func (a *helmRepositoryListAdapter) summariseItem(i int, includeNamespace bool,
} }
status, msg := statusAndMessage(item.Status.Conditions) status, msg := statusAndMessage(item.Status.Conditions)
return append(nameColumns(&item, includeNamespace, includeKind), return append(nameColumns(&item, includeNamespace, includeKind),
revision, strings.Title(strconv.FormatBool(item.Spec.Suspend)), status, msg) status, msg, revision, strings.Title(strconv.FormatBool(item.Spec.Suspend)))
} }
func (a helmRepositoryListAdapter) headers(includeNamespace bool) []string { func (a helmRepositoryListAdapter) headers(includeNamespace bool) []string {
headers := []string{"Name", "Revision", "Suspended", "Ready", "Message"} headers := []string{"Name", "Ready", "Message", "Revision", "Suspended"}
if includeNamespace { if includeNamespace {
headers = append([]string{"Namespace"}, headers...) headers = append([]string{"Namespace"}, headers...)
} }

View File

@@ -25,9 +25,8 @@ import (
// helmv2.HelmRelease // helmv2.HelmRelease
var helmReleaseType = apiType{ var helmReleaseType = apiType{
kind: helmv2.HelmReleaseKind, kind: helmv2.HelmReleaseKind,
humanKind: "helmrelease", humanKind: "helmreleases",
groupVersion: helmv2.GroupVersion,
} }
type helmReleaseAdapter struct { type helmReleaseAdapter struct {

View File

@@ -30,9 +30,8 @@ import (
// imagev1.ImageRepository // imagev1.ImageRepository
var imageRepositoryType = apiType{ var imageRepositoryType = apiType{
kind: imagev1.ImageRepositoryKind, kind: imagev1.ImageRepositoryKind,
humanKind: "image repository", humanKind: "image repository",
groupVersion: imagev1.GroupVersion,
} }
type imageRepositoryAdapter struct { type imageRepositoryAdapter struct {
@@ -64,9 +63,8 @@ func (a imageRepositoryListAdapter) len() int {
// imagev1.ImagePolicy // imagev1.ImagePolicy
var imagePolicyType = apiType{ var imagePolicyType = apiType{
kind: imagev1.ImagePolicyKind, kind: imagev1.ImagePolicyKind,
humanKind: "image policy", humanKind: "image policy",
groupVersion: imagev1.GroupVersion,
} }
type imagePolicyAdapter struct { type imagePolicyAdapter struct {
@@ -94,9 +92,8 @@ func (a imagePolicyListAdapter) len() int {
// autov1.ImageUpdateAutomation // autov1.ImageUpdateAutomation
var imageUpdateAutomationType = apiType{ var imageUpdateAutomationType = apiType{
kind: autov1.ImageUpdateAutomationKind, kind: autov1.ImageUpdateAutomationKind,
humanKind: "image update automation", humanKind: "image update automation",
groupVersion: autov1.GroupVersion,
} }
type imageUpdateAutomationAdapter struct { type imageUpdateAutomationAdapter struct {

View File

@@ -37,13 +37,10 @@ var installCmd = &cobra.Command{
Long: `The install command deploys Flux in the specified namespace. Long: `The install command deploys Flux in the specified namespace.
If a previous version is installed, then an in-place upgrade will be performed.`, If a previous version is installed, then an in-place upgrade will be performed.`,
Example: ` # Install the latest version in the flux-system namespace Example: ` # Install the latest version in the flux-system namespace
flux install --namespace=flux-system flux install --version=latest --namespace=flux-system
# Install a specific series of components # Install a specific version and a series of components
flux install --components="source-controller,kustomize-controller" flux install --version=v0.0.7 --components="source-controller,kustomize-controller"
# Install all components including the image automation ones
flux install --components-extra="image-reflector-controller,image-automation-controller"
# Install Flux onto tainted Kubernetes nodes # Install Flux onto tainted Kubernetes nodes
flux install --toleration-keys=node.kubernetes.io/dedicated-to-flux flux install --toleration-keys=node.kubernetes.io/dedicated-to-flux
@@ -87,7 +84,7 @@ func init() {
installCmd.Flags().StringSliceVar(&installArgs.defaultComponents, "components", rootArgs.defaults.Components, installCmd.Flags().StringSliceVar(&installArgs.defaultComponents, "components", rootArgs.defaults.Components,
"list of components, accepts comma-separated values") "list of components, accepts comma-separated values")
installCmd.Flags().StringSliceVar(&installArgs.extraComponents, "components-extra", nil, installCmd.Flags().StringSliceVar(&installArgs.extraComponents, "components-extra", nil,
"list of components in addition to those supplied or defaulted, accepts values such as 'image-reflector-controller,image-automation-controller'") "list of components in addition to those supplied or defaulted, accepts comma-separated values")
installCmd.Flags().StringVar(&installArgs.manifestsPath, "manifests", "", "path to the manifest directory") installCmd.Flags().StringVar(&installArgs.manifestsPath, "manifests", "", "path to the manifest directory")
installCmd.Flags().StringVar(&installArgs.registry, "registry", rootArgs.defaults.Registry, installCmd.Flags().StringVar(&installArgs.registry, "registry", rootArgs.defaults.Registry,
"container registry where the toolkit images are published") "container registry where the toolkit images are published")
@@ -193,14 +190,14 @@ func installCmdRun(cmd *cobra.Command, args []string) error {
return nil return nil
} }
applyOutput, err := utils.Apply(ctx, kubeconfigArgs, kubeclientOptions, filepath.Join(tmpDir, manifest.Path)) applyOutput, err := utils.Apply(ctx, kubeconfigArgs, filepath.Join(tmpDir, manifest.Path))
if err != nil { if err != nil {
return fmt.Errorf("install failed: %w", err) return fmt.Errorf("install failed: %w", err)
} }
fmt.Fprintln(os.Stderr, applyOutput) fmt.Fprintln(os.Stderr, applyOutput)
kubeConfig, err := utils.KubeConfig(kubeconfigArgs, kubeclientOptions) kubeConfig, err := utils.KubeConfig(kubeconfigArgs)
if err != nil { if err != nil {
return fmt.Errorf("install failed: %w", err) return fmt.Errorf("install failed: %w", err)
} }

View File

@@ -25,9 +25,8 @@ import (
// kustomizev1.Kustomization // kustomizev1.Kustomization
var kustomizationType = apiType{ var kustomizationType = apiType{
kind: kustomizev1.KustomizationKind, kind: kustomizev1.KustomizationKind,
humanKind: "kustomization", humanKind: "kustomizations",
groupVersion: kustomizev1.GroupVersion,
} }
type kustomizationAdapter struct { type kustomizationAdapter struct {

View File

@@ -21,12 +21,12 @@ import (
"context" "context"
"encoding/json" "encoding/json"
"fmt" "fmt"
"html/template"
"io" "io"
"os" "os"
"sort" "sort"
"strings" "strings"
"sync" "sync"
"text/template"
"time" "time"
"github.com/spf13/cobra" "github.com/spf13/cobra"
@@ -99,7 +99,7 @@ func logsCmdRun(cmd *cobra.Command, args []string) error {
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel() defer cancel()
cfg, err := utils.KubeConfig(kubeconfigArgs, kubeclientOptions) cfg, err := utils.KubeConfig(kubeconfigArgs)
if err != nil { if err != nil {
return err return err
} }

View File

@@ -30,8 +30,6 @@ import (
"k8s.io/cli-runtime/pkg/genericclioptions" "k8s.io/cli-runtime/pkg/genericclioptions"
_ "k8s.io/client-go/plugin/pkg/client/auth" _ "k8s.io/client-go/plugin/pkg/client/auth"
runclient "github.com/fluxcd/pkg/runtime/client"
"github.com/fluxcd/flux2/pkg/manifestgen/install" "github.com/fluxcd/flux2/pkg/manifestgen/install"
) )
@@ -107,19 +105,8 @@ type rootFlags struct {
defaults install.Options 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 rootArgs = NewRootFlags()
var kubeconfigArgs = genericclioptions.NewConfigFlags(false) var kubeconfigArgs = genericclioptions.NewConfigFlags(false)
var kubeclientOptions = new(runclient.Options)
func init() { func init() {
rootCmd.PersistentFlags().DurationVar(&rootArgs.timeout, "timeout", 5*time.Minute, "timeout for this operation") rootCmd.PersistentFlags().DurationVar(&rootArgs.timeout, "timeout", 5*time.Minute, "timeout for this operation")
@@ -137,8 +124,6 @@ func init() {
kubeconfigArgs.APIServer = &apiServer kubeconfigArgs.APIServer = &apiServer
rootCmd.PersistentFlags().StringVar(kubeconfigArgs.APIServer, "server", *kubeconfigArgs.APIServer, "The address and port of the Kubernetes API server") rootCmd.PersistentFlags().StringVar(kubeconfigArgs.APIServer, "server", *kubeconfigArgs.APIServer, "The address and port of the Kubernetes API server")
kubeclientOptions.BindFlags(rootCmd.PersistentFlags())
rootCmd.RegisterFlagCompletionFunc("context", contextsCompletionFunc) rootCmd.RegisterFlagCompletionFunc("context", contextsCompletionFunc)
rootCmd.RegisterFlagCompletionFunc("namespace", resourceNamesCompletionFunc(corev1.SchemeGroupVersion.WithKind("Namespace"))) rootCmd.RegisterFlagCompletionFunc("namespace", resourceNamesCompletionFunc(corev1.SchemeGroupVersion.WithKind("Namespace")))
@@ -158,17 +143,6 @@ func NewRootFlags() rootFlags {
func main() { func main() {
log.SetFlags(0) log.SetFlags(0)
if err := rootCmd.Execute(); err != nil { if err := rootCmd.Execute(); err != nil {
if err, ok := err.(*RequestError); ok {
if err.StatusCode == 1 {
logger.Warningf("%v", err)
} else {
logger.Failuref("%v", err)
}
os.Exit(err.StatusCode)
}
logger.Failuref("%v", err) logger.Failuref("%v", err)
os.Exit(1) os.Exit(1)
} }

View File

@@ -20,7 +20,6 @@ import (
"bufio" "bufio"
"bytes" "bytes"
"context" "context"
"flag"
"fmt" "fmt"
"io" "io"
"os" "os"
@@ -43,9 +42,6 @@ import (
var nextNamespaceId int64 var nextNamespaceId int64
// update allows golden files to be updated based on the current output.
var update = flag.Bool("update", false, "update golden files")
// Return a unique namespace with the specified prefix, for tests to create // Return a unique namespace with the specified prefix, for tests to create
// objects that won't collide with each other. // objects that won't collide with each other.
func allocateNamespace(prefix string) string { func allocateNamespace(prefix string) string {
@@ -302,18 +298,6 @@ func assertGoldenTemplateFile(goldenFile string, templateValues map[string]strin
expectedOutput = string(goldenFileContents) expectedOutput = string(goldenFileContents)
} }
if assertErr := assertGoldenValue(expectedOutput)(output, err); assertErr != nil { if assertErr := assertGoldenValue(expectedOutput)(output, err); assertErr != nil {
// Update the golden files if comparison fails and the update flag is set.
if *update && output != "" {
// Skip update if there are template values.
if len(templateValues) > 0 {
fmt.Println("NOTE: -update flag passed but golden template files can't be updated, please update it manually")
} else {
if err := os.WriteFile(goldenFile, []byte(output), 0644); err != nil {
return fmt.Errorf("failed to update golden file '%s': %v", goldenFile, err)
}
return nil
}
}
return fmt.Errorf("Mismatch from golden file '%s': %v", goldenFile, assertErr) return fmt.Errorf("Mismatch from golden file '%s': %v", goldenFile, assertErr)
} }
return nil return nil
@@ -341,12 +325,6 @@ type cmdTestCase struct {
func (cmd *cmdTestCase) runTestCmd(t *testing.T) { func (cmd *cmdTestCase) runTestCmd(t *testing.T) {
actual, testErr := executeCommand(cmd.args) 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 { if assertErr := cmd.assert(actual, testErr); assertErr != nil {
t.Error(assertErr) t.Error(assertErr)
} }
@@ -388,12 +366,3 @@ func resetCmdArgs() {
getArgs = GetFlags{} getArgs = GetFlags{}
secretGitArgs = NewSecretGitFlags() 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

@@ -28,7 +28,6 @@ import (
// implementation can pick whichever it wants to use. // implementation can pick whichever it wants to use.
type apiType struct { type apiType struct {
kind, humanKind string kind, humanKind string
groupVersion schema.GroupVersion
} }
// adapter is an interface for a wrapper or alias from which we can // adapter is an interface for a wrapper or alias from which we can

View File

@@ -25,9 +25,8 @@ import (
// notificationv1.Receiver // notificationv1.Receiver
var receiverType = apiType{ var receiverType = apiType{
kind: notificationv1.ReceiverKind, kind: notificationv1.ReceiverKind,
humanKind: "receiver", humanKind: "receiver",
groupVersion: notificationv1.GroupVersion,
} }
type receiverAdapter struct { type receiverAdapter struct {

View File

@@ -24,7 +24,6 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
apimeta "k8s.io/apimachinery/pkg/api/meta" apimeta "k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/wait" "k8s.io/apimachinery/pkg/util/wait"
"k8s.io/client-go/util/retry" "k8s.io/client-go/util/retry"
@@ -60,22 +59,13 @@ type reconcilable interface {
GetAnnotations() map[string]string GetAnnotations() map[string]string
SetAnnotations(map[string]string) SetAnnotations(map[string]string)
// this is usually implemented by GOTK types, since it's used for meta.SetResourceCondition
GetStatusConditions() *[]metav1.Condition
lastHandledReconcileRequest() string // what was the last handled reconcile request? lastHandledReconcileRequest() string // what was the last handled reconcile request?
successMessage() string // what do you want to tell people when successfully reconciled? successMessage() string // what do you want to tell people when successfully reconciled?
} }
func reconcilableConditions(object reconcilable) []metav1.Condition {
if s, ok := object.(meta.ObjectWithConditions); ok {
return s.GetConditions()
}
if s, ok := object.(oldConditions); ok {
return *s.GetStatusConditions()
}
return []metav1.Condition{}
}
func (reconcile reconcileCommand) run(cmd *cobra.Command, args []string) error { func (reconcile reconcileCommand) run(cmd *cobra.Command, args []string) error {
if len(args) < 1 { if len(args) < 1 {
return fmt.Errorf("%s name is required", reconcile.kind) return fmt.Errorf("%s name is required", reconcile.kind)
@@ -85,7 +75,7 @@ func (reconcile reconcileCommand) run(cmd *cobra.Command, args []string) error {
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel() defer cancel()
kubeClient, err := utils.KubeClient(kubeconfigArgs, kubeclientOptions) kubeClient, err := utils.KubeClient(kubeconfigArgs)
if err != nil { if err != nil {
return err return err
} }
@@ -105,8 +95,7 @@ func (reconcile reconcileCommand) run(cmd *cobra.Command, args []string) error {
} }
logger.Actionf("annotating %s %s in %s namespace", reconcile.kind, name, *kubeconfigArgs.Namespace) logger.Actionf("annotating %s %s in %s namespace", reconcile.kind, name, *kubeconfigArgs.Namespace)
if err := requestReconciliation(ctx, kubeClient, namespacedName, if err := requestReconciliation(ctx, kubeClient, namespacedName, reconcile.object); err != nil {
reconcile.groupVersion.WithKind(reconcile.kind)); err != nil {
return err return err
} }
logger.Successf("%s annotated", reconcile.kind) logger.Successf("%s annotated", reconcile.kind)
@@ -127,7 +116,7 @@ func (reconcile reconcileCommand) run(cmd *cobra.Command, args []string) error {
reconciliationHandled(ctx, kubeClient, namespacedName, reconcile.object, lastHandledReconcileAt)); err != nil { reconciliationHandled(ctx, kubeClient, namespacedName, reconcile.object, lastHandledReconcileAt)); err != nil {
return err return err
} }
readyCond := apimeta.FindStatusCondition(reconcilableConditions(reconcile.object), meta.ReadyCondition) readyCond := apimeta.FindStatusCondition(*reconcile.object.GetStatusConditions(), meta.ReadyCondition)
if readyCond == nil { if readyCond == nil {
return fmt.Errorf("status can't be determined") return fmt.Errorf("status can't be determined")
} }
@@ -146,32 +135,28 @@ func reconciliationHandled(ctx context.Context, kubeClient client.Client,
if err != nil { if err != nil {
return false, err return false, err
} }
isProgressing := apimeta.IsStatusConditionPresentAndEqual(reconcilableConditions(obj), isProgressing := apimeta.IsStatusConditionPresentAndEqual(*obj.GetStatusConditions(),
meta.ReadyCondition, metav1.ConditionUnknown) meta.ReadyCondition, metav1.ConditionUnknown)
return obj.lastHandledReconcileRequest() != lastHandledReconcileAt && !isProgressing, nil return obj.lastHandledReconcileRequest() != lastHandledReconcileAt && !isProgressing, nil
} }
} }
func requestReconciliation(ctx context.Context, kubeClient client.Client, func requestReconciliation(ctx context.Context, kubeClient client.Client,
namespacedName types.NamespacedName, gvk schema.GroupVersionKind) error { namespacedName types.NamespacedName, obj reconcilable) error {
return retry.RetryOnConflict(retry.DefaultBackoff, func() (err error) { return retry.RetryOnConflict(retry.DefaultBackoff, func() (err error) {
object := &metav1.PartialObjectMetadata{} if err := kubeClient.Get(ctx, namespacedName, obj.asClientObject()); err != nil {
object.SetGroupVersionKind(gvk)
object.SetName(namespacedName.Name)
object.SetNamespace(namespacedName.Namespace)
if err := kubeClient.Get(ctx, namespacedName, object); err != nil {
return err return err
} }
patch := client.MergeFrom(object.DeepCopy()) patch := client.MergeFrom(obj.deepCopyClientObject())
if ann := object.GetAnnotations(); ann == nil { if ann := obj.GetAnnotations(); ann == nil {
object.SetAnnotations(map[string]string{ obj.SetAnnotations(map[string]string{
meta.ReconcileRequestAnnotation: time.Now().Format(time.RFC3339Nano), meta.ReconcileRequestAnnotation: time.Now().Format(time.RFC3339Nano),
}) })
} else { } else {
ann[meta.ReconcileRequestAnnotation] = time.Now().Format(time.RFC3339Nano) ann[meta.ReconcileRequestAnnotation] = time.Now().Format(time.RFC3339Nano)
object.SetAnnotations(ann) obj.SetAnnotations(ann)
} }
return kubeClient.Patch(ctx, object, patch) return kubeClient.Patch(ctx, obj.asClientObject(), patch)
}) })
} }
@@ -183,7 +168,7 @@ func isReconcileReady(ctx context.Context, kubeClient client.Client,
return false, err return false, err
} }
if c := apimeta.FindStatusCondition(reconcilableConditions(obj), meta.ReadyCondition); c != nil { if c := apimeta.FindStatusCondition(*obj.GetStatusConditions(), meta.ReadyCondition); c != nil {
switch c.Status { switch c.Status {
case metav1.ConditionTrue: case metav1.ConditionTrue:
return true, nil return true, nil

View File

@@ -54,7 +54,7 @@ func reconcileAlertProviderCmdRun(cmd *cobra.Command, args []string) error {
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel() defer cancel()
kubeClient, err := utils.KubeClient(kubeconfigArgs, kubeclientOptions) kubeClient, err := utils.KubeClient(kubeconfigArgs)
if err != nil { if err != nil {
return err return err
} }

View File

@@ -21,7 +21,7 @@ import (
"k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/types"
helmv2 "github.com/fluxcd/helm-controller/api/v2beta1" helmv2 "github.com/fluxcd/helm-controller/api/v2beta1"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta2" sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
) )
var reconcileHrCmd = &cobra.Command{ var reconcileHrCmd = &cobra.Command{

View File

@@ -21,7 +21,7 @@ import (
"k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/types"
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta2" kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta2"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta2" sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
) )
var reconcileKsCmd = &cobra.Command{ var reconcileKsCmd = &cobra.Command{

View File

@@ -54,7 +54,7 @@ func reconcileReceiverCmdRun(cmd *cobra.Command, args []string) error {
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel() defer cancel()
kubeClient, err := utils.KubeClient(kubeconfigArgs, kubeclientOptions) kubeClient, err := utils.KubeClient(kubeconfigArgs)
if err != nil { if err != nil {
return err return err
} }

View File

@@ -17,11 +17,18 @@ limitations under the License.
package main package main
import ( import (
"context"
"fmt" "fmt"
"github.com/spf13/cobra" "github.com/spf13/cobra"
apimeta "k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/wait"
"sigs.k8s.io/controller-runtime/pkg/client"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta2" "github.com/fluxcd/pkg/apis/meta"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
) )
var reconcileSourceBucketCmd = &cobra.Command{ var reconcileSourceBucketCmd = &cobra.Command{
@@ -41,6 +48,31 @@ func init() {
reconcileSourceCmd.AddCommand(reconcileSourceBucketCmd) reconcileSourceCmd.AddCommand(reconcileSourceBucketCmd)
} }
func isBucketReady(ctx context.Context, kubeClient client.Client,
namespacedName types.NamespacedName, bucket *sourcev1.Bucket) wait.ConditionFunc {
return func() (bool, error) {
err := kubeClient.Get(ctx, namespacedName, bucket)
if err != nil {
return false, err
}
// Confirm the state we are observing is for the current generation
if bucket.Generation != bucket.Status.ObservedGeneration {
return false, nil
}
if c := apimeta.FindStatusCondition(bucket.Status.Conditions, meta.ReadyCondition); c != nil {
switch c.Status {
case metav1.ConditionTrue:
return true, nil
case metav1.ConditionFalse:
return false, fmt.Errorf(c.Message)
}
}
return false, nil
}
}
func (obj bucketAdapter) lastHandledReconcileRequest() string { func (obj bucketAdapter) lastHandledReconcileRequest() string {
return obj.Status.GetLastHandledReconcileRequest() return obj.Status.GetLastHandledReconcileRequest()
} }

View File

@@ -21,7 +21,7 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta2" sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
) )
var reconcileSourceGitCmd = &cobra.Command{ var reconcileSourceGitCmd = &cobra.Command{

View File

@@ -21,7 +21,7 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta2" sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
) )
var reconcileSourceHelmCmd = &cobra.Command{ var reconcileSourceHelmCmd = &cobra.Command{

View File

@@ -10,8 +10,9 @@ import (
"k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/wait" "k8s.io/apimachinery/pkg/util/wait"
"github.com/fluxcd/flux2/internal/utils"
"github.com/fluxcd/pkg/apis/meta" "github.com/fluxcd/pkg/apis/meta"
"github.com/fluxcd/flux2/internal/utils"
) )
type reconcileWithSource interface { type reconcileWithSource interface {
@@ -35,7 +36,7 @@ func (reconcile reconcileWithSourceCommand) run(cmd *cobra.Command, args []strin
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel() defer cancel()
kubeClient, err := utils.KubeClient(kubeconfigArgs, kubeclientOptions) kubeClient, err := utils.KubeClient(kubeconfigArgs)
if err != nil { if err != nil {
return err return err
} }
@@ -70,8 +71,7 @@ func (reconcile reconcileWithSourceCommand) run(cmd *cobra.Command, args []strin
lastHandledReconcileAt := reconcile.object.lastHandledReconcileRequest() lastHandledReconcileAt := reconcile.object.lastHandledReconcileRequest()
logger.Actionf("annotating %s %s in %s namespace", reconcile.kind, name, *kubeconfigArgs.Namespace) logger.Actionf("annotating %s %s in %s namespace", reconcile.kind, name, *kubeconfigArgs.Namespace)
if err := requestReconciliation(ctx, kubeClient, namespacedName, if err := requestReconciliation(ctx, kubeClient, namespacedName, reconcile.object); err != nil {
reconcile.groupVersion.WithKind(reconcile.kind)); err != nil {
return err return err
} }
logger.Successf("%s annotated", reconcile.kind) logger.Successf("%s annotated", reconcile.kind)
@@ -82,7 +82,7 @@ func (reconcile reconcileWithSourceCommand) run(cmd *cobra.Command, args []strin
return err return err
} }
readyCond := apimeta.FindStatusCondition(reconcilableConditions(reconcile.object), meta.ReadyCondition) readyCond := apimeta.FindStatusCondition(*reconcile.object.GetStatusConditions(), meta.ReadyCondition)
if readyCond == nil { if readyCond == nil {
return fmt.Errorf("status can't be determined") return fmt.Errorf("status can't be determined")
} }

View File

@@ -35,8 +35,7 @@ var resumeCmd = &cobra.Command{
} }
type ResumeFlags struct { type ResumeFlags struct {
all bool all bool
wait bool
} }
var resumeArgs ResumeFlags var resumeArgs ResumeFlags
@@ -44,14 +43,11 @@ var resumeArgs ResumeFlags
func init() { func init() {
resumeCmd.PersistentFlags().BoolVarP(&resumeArgs.all, "all", "", false, resumeCmd.PersistentFlags().BoolVarP(&resumeArgs.all, "all", "", false,
"resume all resources in that namespace") "resume all resources in that namespace")
resumeCmd.PersistentFlags().BoolVarP(&resumeArgs.wait, "wait", "", false,
"waits for one resource to reconcile before moving to the next one")
rootCmd.AddCommand(resumeCmd) rootCmd.AddCommand(resumeCmd)
} }
type resumable interface { type resumable interface {
adapter adapter
copyable
statusable statusable
setUnsuspended() setUnsuspended()
successMessage() string successMessage() string
@@ -76,7 +72,7 @@ func (resume resumeCommand) run(cmd *cobra.Command, args []string) error {
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel() defer cancel()
kubeClient, err := utils.KubeClient(kubeconfigArgs, kubeclientOptions) kubeClient, err := utils.KubeClient(kubeconfigArgs)
if err != nil { if err != nil {
return err return err
} }
@@ -101,30 +97,25 @@ func (resume resumeCommand) run(cmd *cobra.Command, args []string) error {
for i := 0; i < resume.list.len(); i++ { 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) logger.Actionf("resuming %s %s in %s namespace", resume.humanKind, resume.list.resumeItem(i).asClientObject().GetName(), *kubeconfigArgs.Namespace)
obj := resume.list.resumeItem(i) resume.list.resumeItem(i).setUnsuspended()
patch := client.MergeFrom(obj.deepCopyClientObject()) if err := kubeClient.Update(ctx, resume.list.resumeItem(i).asClientObject()); err != nil {
obj.setUnsuspended()
if err := kubeClient.Patch(ctx, obj.asClientObject(), patch); err != nil {
return err return err
} }
logger.Successf("%s resumed", resume.humanKind) logger.Successf("%s resumed", resume.humanKind)
if resumeArgs.wait || !resumeArgs.all { namespacedName := types.NamespacedName{
namespacedName := types.NamespacedName{ Name: resume.list.resumeItem(i).asClientObject().GetName(),
Name: resume.list.resumeItem(i).asClientObject().GetName(), Namespace: *kubeconfigArgs.Namespace,
Namespace: *kubeconfigArgs.Namespace,
}
logger.Waitingf("waiting for %s reconciliation", resume.kind)
if err := wait.PollImmediate(rootArgs.pollInterval, rootArgs.timeout,
isReady(ctx, kubeClient, namespacedName, resume.list.resumeItem(i))); err != nil {
logger.Failuref(err.Error())
continue
}
logger.Successf("%s reconciliation completed", resume.kind)
logger.Successf(resume.list.resumeItem(i).successMessage())
} }
logger.Waitingf("waiting for %s reconciliation", resume.kind)
if err := wait.PollImmediate(rootArgs.pollInterval, rootArgs.timeout,
isReady(ctx, kubeClient, namespacedName, resume.list.resumeItem(i))); err != nil {
logger.Failuref(err.Error())
continue
}
logger.Successf("%s reconciliation completed", resume.kind)
logger.Successf(resume.list.resumeItem(i).successMessage())
} }
return nil return nil

View File

@@ -19,7 +19,7 @@ package main
import ( import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta2" sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
) )
var resumeSourceBucketCmd = &cobra.Command{ var resumeSourceBucketCmd = &cobra.Command{
@@ -31,8 +31,7 @@ var resumeSourceBucketCmd = &cobra.Command{
ValidArgsFunction: resourceNamesCompletionFunc(sourcev1.GroupVersion.WithKind(sourcev1.BucketKind)), ValidArgsFunction: resourceNamesCompletionFunc(sourcev1.GroupVersion.WithKind(sourcev1.BucketKind)),
RunE: resumeCommand{ RunE: resumeCommand{
apiType: bucketType, apiType: bucketType,
object: bucketAdapter{&sourcev1.Bucket{}}, object: &bucketAdapter{&sourcev1.Bucket{}},
list: bucketListAdapter{&sourcev1.BucketList{}},
}.run, }.run,
} }

View File

@@ -21,7 +21,7 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta2" sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
) )
var resumeSourceHelmChartCmd = &cobra.Command{ var resumeSourceHelmChartCmd = &cobra.Command{

View File

@@ -19,7 +19,7 @@ package main
import ( import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta2" sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
) )
var resumeSourceGitCmd = &cobra.Command{ var resumeSourceGitCmd = &cobra.Command{

View File

@@ -19,7 +19,7 @@ package main
import ( import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta2" sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
) )
var resumeSourceHelmCmd = &cobra.Command{ var resumeSourceHelmCmd = &cobra.Command{

View File

@@ -19,7 +19,7 @@ package main
import ( import (
"sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta2" sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
) )
// These are general-purpose adapters for attaching methods to, for // These are general-purpose adapters for attaching methods to, for
@@ -29,9 +29,8 @@ import (
// sourcev1.Bucket // sourcev1.Bucket
var bucketType = apiType{ var bucketType = apiType{
kind: sourcev1.BucketKind, kind: sourcev1.BucketKind,
humanKind: "source bucket", humanKind: "source bucket",
groupVersion: sourcev1.GroupVersion,
} }
type bucketAdapter struct { type bucketAdapter struct {
@@ -63,9 +62,8 @@ func (a bucketListAdapter) len() int {
// sourcev1.HelmChart // sourcev1.HelmChart
var helmChartType = apiType{ var helmChartType = apiType{
kind: sourcev1.HelmChartKind, kind: sourcev1.HelmChartKind,
humanKind: "source chart", humanKind: "source chart",
groupVersion: sourcev1.GroupVersion,
} }
type helmChartAdapter struct { type helmChartAdapter struct {
@@ -97,9 +95,8 @@ func (a helmChartListAdapter) len() int {
// sourcev1.GitRepository // sourcev1.GitRepository
var gitRepositoryType = apiType{ var gitRepositoryType = apiType{
kind: sourcev1.GitRepositoryKind, kind: sourcev1.GitRepositoryKind,
humanKind: "source git", humanKind: "source git",
groupVersion: sourcev1.GroupVersion,
} }
type gitRepositoryAdapter struct { type gitRepositoryAdapter struct {
@@ -131,9 +128,8 @@ func (a gitRepositoryListAdapter) len() int {
// sourcev1.HelmRepository // sourcev1.HelmRepository
var helmRepositoryType = apiType{ var helmRepositoryType = apiType{
kind: sourcev1.HelmRepositoryKind, kind: sourcev1.HelmRepositoryKind,
humanKind: "source helm", humanKind: "source helm",
groupVersion: sourcev1.GroupVersion,
} }
type helmRepositoryAdapter struct { type helmRepositoryAdapter struct {

View File

@@ -20,7 +20,6 @@ import (
"context" "context"
"fmt" "fmt"
"github.com/fluxcd/pkg/apis/meta"
apimeta "k8s.io/apimachinery/pkg/api/meta" apimeta "k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/schema"
@@ -28,6 +27,8 @@ import (
"k8s.io/apimachinery/pkg/util/wait" "k8s.io/apimachinery/pkg/util/wait"
"sigs.k8s.io/cli-utils/pkg/object" "sigs.k8s.io/cli-utils/pkg/object"
"sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client"
"github.com/fluxcd/pkg/apis/meta"
) )
// statusable is used to see if a resource is considered ready in the usual way // statusable is used to see if a resource is considered ready in the usual way
@@ -36,26 +37,10 @@ type statusable interface {
// this is implemented by ObjectMeta // this is implemented by ObjectMeta
GetGeneration() int64 GetGeneration() int64
getObservedGeneration() int64 getObservedGeneration() int64
}
// oldConditions represents the deprecated API which is sunsetting.
type oldConditions interface {
// this is usually implemented by GOTK API objects because it's used by pkg/apis/meta // this is usually implemented by GOTK API objects because it's used by pkg/apis/meta
GetStatusConditions() *[]metav1.Condition GetStatusConditions() *[]metav1.Condition
} }
func statusableConditions(object statusable) []metav1.Condition {
if s, ok := object.(meta.ObjectWithConditions); ok {
return s.GetConditions()
}
if s, ok := object.(oldConditions); ok {
return *s.GetStatusConditions()
}
return []metav1.Condition{}
}
func isReady(ctx context.Context, kubeClient client.Client, func isReady(ctx context.Context, kubeClient client.Client,
namespacedName types.NamespacedName, object statusable) wait.ConditionFunc { namespacedName types.NamespacedName, object statusable) wait.ConditionFunc {
return func() (bool, error) { return func() (bool, error) {
@@ -69,7 +54,7 @@ func isReady(ctx context.Context, kubeClient client.Client,
return false, nil return false, nil
} }
if c := apimeta.FindStatusCondition(statusableConditions(object), meta.ReadyCondition); c != nil { if c := apimeta.FindStatusCondition(*object.GetStatusConditions(), meta.ReadyCondition); c != nil {
switch c.Status { switch c.Status {
case metav1.ConditionTrue: case metav1.ConditionTrue:
return true, nil return true, nil

View File

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

View File

@@ -19,7 +19,7 @@ package main
import ( import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta2" sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
) )
var suspendSourceBucketCmd = &cobra.Command{ var suspendSourceBucketCmd = &cobra.Command{

View File

@@ -19,7 +19,7 @@ package main
import ( import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta2" sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
) )
var suspendSourceHelmChartCmd = &cobra.Command{ var suspendSourceHelmChartCmd = &cobra.Command{

View File

@@ -19,7 +19,7 @@ package main
import ( import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta2" sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
) )
var suspendSourceGitCmd = &cobra.Command{ var suspendSourceGitCmd = &cobra.Command{

View File

@@ -19,7 +19,7 @@ package main
import ( import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta2" sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
) )
var suspendSourceHelmCmd = &cobra.Command{ var suspendSourceHelmCmd = &cobra.Command{

View File

@@ -13,7 +13,3 @@ spec:
kind: GitRepository kind: GitRepository
name: podinfo name: podinfo
targetNamespace: default targetNamespace: default
postBuild:
substitute:
cluster_env: "prod"
cluster_region: "eu-central-1"

View File

@@ -123,31 +123,6 @@ spec:
type: ClusterIP type: ClusterIP
--- ---
apiVersion: v1 apiVersion: v1
data:
.dockerconfigjson: eyJtYXNrIjoiKipTT1BTKioifQ==
kind: Secret
metadata:
labels:
kustomize.toolkit.fluxcd.io/name: podinfo
kustomize.toolkit.fluxcd.io/namespace: {{ .fluxns }}
name: docker-secret
namespace: default
type: kubernetes.io/dockerconfigjson
---
apiVersion: v1
kind: Secret
metadata:
labels:
kustomize.toolkit.fluxcd.io/name: podinfo
kustomize.toolkit.fluxcd.io/namespace: {{ .fluxns }}
name: secret-basic-auth-stringdata
namespace: default
stringData:
password: '**SOPS**'
username: '**SOPS**'
type: kubernetes.io/basic-auth
---
apiVersion: v1
data: data:
token: KipTT1BTKio= token: KipTT1BTKio=
kind: Secret kind: Secret

View File

@@ -1,216 +0,0 @@
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
environment: prod
kustomize.toolkit.fluxcd.io/name: podinfo
kustomize.toolkit.fluxcd.io/namespace: {{ .fluxns }}
region: eu-central-1
name: podinfo
namespace: default
spec:
minReadySeconds: 3
progressDeadlineSeconds: 60
revisionHistoryLimit: 5
selector:
matchLabels:
app: podinfo
strategy:
rollingUpdate:
maxUnavailable: 0
type: RollingUpdate
template:
metadata:
annotations:
prometheus.io/port: "9797"
prometheus.io/scrape: "true"
labels:
app: podinfo
spec:
containers:
- command:
- ./podinfo
- --port=9898
- --port-metrics=9797
- --grpc-port=9999
- --grpc-service-name=podinfo
- --level=info
- --random-delay=false
- --random-error=false
env:
- name: PODINFO_UI_COLOR
value: '#34577c'
image: ghcr.io/stefanprodan/podinfo:6.0.10
imagePullPolicy: IfNotPresent
livenessProbe:
exec:
command:
- podcli
- check
- http
- localhost:9898/healthz
initialDelaySeconds: 5
timeoutSeconds: 5
name: podinfod
ports:
- containerPort: 9898
name: http
protocol: TCP
- containerPort: 9797
name: http-metrics
protocol: TCP
- containerPort: 9999
name: grpc
protocol: TCP
readinessProbe:
exec:
command:
- podcli
- check
- http
- localhost:9898/readyz
initialDelaySeconds: 5
timeoutSeconds: 5
resources:
limits:
cpu: 2000m
memory: 512Mi
requests:
cpu: 100m
memory: 64Mi
---
apiVersion: v1
data:
cluster.json: |
{
"annotations": {
"list": [
{
"builtIn": 1,
"datasource": "-- Grafana --",
"enable": true,
"hide": true,
"iconColor": "rgba(0, 211, 255, 1)",
"name": "Annotations & Alerts",
"type": "dashboard"
}
]
},
"editable": true,
"gnetId": null,
"graphTooltip": 0,
"iteration": 1636369574387,
"links": [],
"panels": [
{
"datasource": "${DS_PROMETHEUS}",
"description": "",
"fieldConfig": {
"defaults": {
"decimals": 0,
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "blue",
"value": null
},
{
"color": "red",
"value": 100
}
]
},
"unit": "short"
},
"overrides": []
},
"gridPos": {
"h": 5,
"w": 6,
"x": 0,
"y": 0
},
"id": 24,
"options": {
"colorMode": "value",
"graphMode": "none",
"justifyMode": "auto",
"orientation": "auto",
"reduceOptions": {
"calcs": [
"last"
],
"fields": "",
"values": false
},
"text": {},
"textMode": "value"
},
"pluginVersion": "7.5.5",
"targets": [
{
"exemplar": true,
"expr": "count(gotk_reconcile_condition{namespace=~\"$operator_namespace\",exported_namespace=~\"$namespace\",type=\"Ready\",status=\"True\",kind=~\"Kustomization|HelmRelease\"})\n-\nsum(gotk_reconcile_condition{namespace=~\"$operator_namespace\",exported_namespace=~\"$namespace\",type=\"Ready\",status=\"Deleted\",kind=~\"Kustomization|HelmRelease\"})",
"interval": "",
"legendFormat": "",
"refId": "A"
}
],
"timeFrom": null,
"timeShift": null,
"title": "Cluster Reconcilers",
"type": "stat"
},
{
"collapsed": false,
"datasource": "${DS_PROMETHEUS}",
"gridPos": {
"h": 1,
"w": 24,
"x": 0,
"y": 9
},
"id": 15,
"panels": [],
"title": "Status",
"type": "row"
}
],
"refresh": "",
"schemaVersion": 27,
"style": "light",
"tags": [
"flux"
],
"time": {
"from": "now-15m",
"to": "now"
},
"timepicker": {
"refresh_intervals": [
"10s",
"30s",
"1m",
"5m",
"15m",
"30m",
"1h",
"2h",
"1d"
]
},
"timezone": "",
"title": "Flux Cluster Stats",
"uid": "flux-cluster",
"version": 1
}
kind: ConfigMap
metadata:
labels:
kustomize.toolkit.fluxcd.io/name: podinfo
kustomize.toolkit.fluxcd.io/namespace: {{ .fluxns }}
kustomize.toolkit.fluxcd.io/substitute: disabled
name: flux-grafana-dashboards-kt8md725kf
namespace: default

View File

@@ -1,27 +0,0 @@
apiVersion: v1
data:
.dockerconfigjson: ENC[AES256_GCM,data:KHCFH3hNnc+PMfWLFEPjebf3W4z4WXbGFAANRZyZC+07z7wlrTALJM6rn8YslW4tMAWCoAYxblC5WRCszTy0h9rw0U/RGOv5H0qCgnNg/FILFUqhwo9pNfrUH+MEP4M9qxxbLKZwObpHUE7DUsKx1JYAxsI=,iv:q48lqUbUQD+0cbYcjNMZMJLRdGHi78ZmDhNAT2th9tg=,tag:QRI2SZZXQrAcdql3R5AH2g==,type:str]
kind: Secret
metadata:
name: docker-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

View File

@@ -4,8 +4,6 @@ resources:
- ./deployment.yaml - ./deployment.yaml
- ./hpa.yaml - ./hpa.yaml
- ./service.yaml - ./service.yaml
- ./dockerconfigjson-sops-secret.yaml
- ./stringdata-secret.yaml
secretGenerator: secretGenerator:
- files: - files:
- token=token.encrypted - token=token.encrypted

View File

@@ -1,28 +0,0 @@
apiVersion: v1
kind: Secret
metadata:
name: secret-basic-auth-stringdata
type: kubernetes.io/basic-auth
stringData:
username: ENC[AES256_GCM,data:uKiQR48=,iv:jh2lgyAVu7igJAgoJsnOGhjxFyvUAa9lvT21u3hhqpU=,tag:zXM2JEpk3ZEH7WfkcWXXkw==,type:str]
password: ENC[AES256_GCM,data:PyhZmNhy929JGQ==,iv:PBqPaJmSw21+kn4gIlg5VdjLNZyf613z5RUTCesBoVw=,tag:Hjc7DsuUrtsz7PYPdNkL3g==,type:str]
sops:
kms: []
gcp_kms: []
azure_kv: []
hc_vault: []
age:
- recipient: age10la2ge0wtvx3qr7datqf7rs4yngxszdal927fs9rukamr8u2pshsvtz7ce
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBJd0xxbDZhYjVoZzY4YWhK
d2NvMVgrSGRVUGhHRGg3R1FpVURnbmh1TDBzCjcwby85M3JaK09QVk0yZFNMb2NL
c2NQZW5hS1FhYlBHU0VoUzBVYzZYUUUKLS0tIEdaNEw2Y0VjVHpZc3pyYUtLVmJk
NmN3K2VLU0NiZ1d0VHBYbGlCM1lrNmMKeWz3yfFbMNE+ly21oLfc1XnDSPRmnlPP
wIs8lk/qrzVZ45C9GdWnnPeGZZiia46Yop9TxseUS8gCjJ6KCxJCAg==
-----END AGE ENCRYPTED FILE-----
lastmodified: "2022-02-06T12:51:07Z"
mac: ENC[AES256_GCM,data:jtdzwj19uxdxvnmXg1HkAkDA6XlKMJOYFy7uLI5t/t11LwGop5Yeo7a4nQEEELehRx9J7B6U6NiySxAxBxWx5uW5vI5c8+069VV6dkiCIefnYSzuoIhQafjlFl1/KvH7VEjIWfHYuXF09v9PEKXkxEHUYDpS3QqQ3ymHRRI08pU=, iv:xX3E7F+AM29Pm8G5oqxRfYu9E7tEBGIaHeCJYgrtFmc=,tag:MJPGusNvu05z939jg8PAwQ==,type:str]
pgp: []
encrypted_regex: ^(data|stringData)$
version: 3.7.1

View File

@@ -1,124 +0,0 @@
{
"annotations": {
"list": [
{
"builtIn": 1,
"datasource": "-- Grafana --",
"enable": true,
"hide": true,
"iconColor": "rgba(0, 211, 255, 1)",
"name": "Annotations & Alerts",
"type": "dashboard"
}
]
},
"editable": true,
"gnetId": null,
"graphTooltip": 0,
"iteration": 1636369574387,
"links": [],
"panels": [
{
"datasource": "${DS_PROMETHEUS}",
"description": "",
"fieldConfig": {
"defaults": {
"decimals": 0,
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "blue",
"value": null
},
{
"color": "red",
"value": 100
}
]
},
"unit": "short"
},
"overrides": []
},
"gridPos": {
"h": 5,
"w": 6,
"x": 0,
"y": 0
},
"id": 24,
"options": {
"colorMode": "value",
"graphMode": "none",
"justifyMode": "auto",
"orientation": "auto",
"reduceOptions": {
"calcs": [
"last"
],
"fields": "",
"values": false
},
"text": {},
"textMode": "value"
},
"pluginVersion": "7.5.5",
"targets": [
{
"exemplar": true,
"expr": "count(gotk_reconcile_condition{namespace=~\"$operator_namespace\",exported_namespace=~\"$namespace\",type=\"Ready\",status=\"True\",kind=~\"Kustomization|HelmRelease\"})\n-\nsum(gotk_reconcile_condition{namespace=~\"$operator_namespace\",exported_namespace=~\"$namespace\",type=\"Ready\",status=\"Deleted\",kind=~\"Kustomization|HelmRelease\"})",
"interval": "",
"legendFormat": "",
"refId": "A"
}
],
"timeFrom": null,
"timeShift": null,
"title": "Cluster Reconcilers",
"type": "stat"
},
{
"collapsed": false,
"datasource": "${DS_PROMETHEUS}",
"gridPos": {
"h": 1,
"w": 24,
"x": 0,
"y": 9
},
"id": 15,
"panels": [],
"title": "Status",
"type": "row"
}
],
"refresh": "",
"schemaVersion": 27,
"style": "light",
"tags": [
"flux"
],
"time": {
"from": "now-15m",
"to": "now"
},
"timepicker": {
"refresh_intervals": [
"10s",
"30s",
"1m",
"5m",
"15m",
"30m",
"1h",
"2h",
"1d"
]
},
"timezone": "",
"title": "Flux Cluster Stats",
"uid": "flux-cluster",
"version": 1
}

View File

@@ -1,77 +0,0 @@
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
environment: ${cluster_env:=dev}
region: ${cluster_region}
name: podinfo
spec:
minReadySeconds: 3
revisionHistoryLimit: 5
progressDeadlineSeconds: 60
strategy:
rollingUpdate:
maxUnavailable: 0
type: RollingUpdate
selector:
matchLabels:
app: podinfo
template:
metadata:
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "9797"
labels:
app: podinfo
spec:
containers:
- name: podinfod
image: ghcr.io/stefanprodan/podinfo:6.0.10
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 9898
protocol: TCP
- name: http-metrics
containerPort: 9797
protocol: TCP
- name: grpc
containerPort: 9999
protocol: TCP
command:
- ./podinfo
- --port=9898
- --port-metrics=9797
- --grpc-port=9999
- --grpc-service-name=podinfo
- --level=info
- --random-delay=false
- --random-error=false
env:
- name: PODINFO_UI_COLOR
value: "#34577c"
livenessProbe:
exec:
command:
- podcli
- check
- http
- localhost:9898/healthz
initialDelaySeconds: 5
timeoutSeconds: 5
readinessProbe:
exec:
command:
- podcli
- check
- http
- localhost:9898/readyz
initialDelaySeconds: 5
timeoutSeconds: 5
resources:
limits:
cpu: 2000m
memory: 512Mi
requests:
cpu: 100m
memory: 64Mi

Some files were not shown because too many files have changed in this diff Show More