Compare commits
1 Commits
fix-commit
...
flux-audit
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3f79b4dd57 |
2
.github/workflows/backport.yaml
vendored
2
.github/workflows/backport.yaml
vendored
@@ -17,7 +17,7 @@ jobs:
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
- name: Create backport PRs
|
||||
uses: korthout/backport-action@b982d297e31f500652b2246cf26714796312bd23 # v2.2.0
|
||||
uses: korthout/backport-action@08bafb375e6e9a9a2b53a744b987e5d81a133191 # v2.1.1
|
||||
# xref: https://github.com/korthout/backport-action#inputs
|
||||
with:
|
||||
# Use token to allow workflows to be triggered for the created PR
|
||||
|
||||
2
.github/workflows/e2e-arm64.yaml
vendored
2
.github/workflows/e2e-arm64.yaml
vendored
@@ -23,7 +23,7 @@ jobs:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0
|
||||
uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0
|
||||
with:
|
||||
go-version: 1.20.x
|
||||
cache-dependency-path: |
|
||||
|
||||
6
.github/workflows/e2e-azure.yaml
vendored
6
.github/workflows/e2e-azure.yaml
vendored
@@ -32,7 +32,7 @@ jobs:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0
|
||||
uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0
|
||||
with:
|
||||
go-version: 1.20.x
|
||||
cache-dependency-path: tests/azure/go.sum
|
||||
@@ -77,7 +77,7 @@ jobs:
|
||||
- name: CheckoutD
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0
|
||||
uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0
|
||||
with:
|
||||
go-version: 1.20.x
|
||||
cache-dependency-path: tests/integration/go.sum
|
||||
@@ -92,7 +92,7 @@ jobs:
|
||||
env:
|
||||
SOPS_VER: 3.7.1
|
||||
- name: Authenticate to Azure
|
||||
uses: Azure/login@de95379fe4dadc2defb305917eaa7e5dde727294 # v1.4.6
|
||||
uses: Azure/login@92a5484dfaf04ca78a94597f4f19fea633851fa2 # v1.4.6
|
||||
with:
|
||||
creds: '{"clientId":"${{ secrets.AZ_ARM_CLIENT_ID }}","clientSecret":"${{ secrets.AZ_ARM_CLIENT_SECRET }}","subscriptionId":"${{ secrets.AZ_ARM_SUBSCRIPTION_ID }}","tenantId":"${{ secrets.AZ_ARM_TENANT_ID }}"}'
|
||||
- name: Set dynamic variables in .env
|
||||
|
||||
2
.github/workflows/e2e-bootstrap.yaml
vendored
2
.github/workflows/e2e-bootstrap.yaml
vendored
@@ -19,7 +19,7 @@ jobs:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0
|
||||
uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0
|
||||
with:
|
||||
go-version: 1.20.x
|
||||
cache-dependency-path: |
|
||||
|
||||
6
.github/workflows/e2e-gcp.yaml
vendored
6
.github/workflows/e2e-gcp.yaml
vendored
@@ -31,7 +31,7 @@ jobs:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0
|
||||
uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0
|
||||
with:
|
||||
go-version: 1.20.x
|
||||
cache-dependency-path: tests/integration/go.sum
|
||||
@@ -46,13 +46,13 @@ jobs:
|
||||
env:
|
||||
SOPS_VER: 3.7.1
|
||||
- name: Authenticate to Google Cloud
|
||||
uses: google-github-actions/auth@67e9c72af6e0492df856527b474995862b7b6591 # v2.0.0
|
||||
uses: google-github-actions/auth@35b0e87d162680511bf346c299f71c9c5c379033 # v1.1.1
|
||||
id: 'auth'
|
||||
with:
|
||||
credentials_json: '${{ secrets.FLUX2_E2E_GOOGLE_CREDENTIALS }}'
|
||||
token_format: 'access_token'
|
||||
- name: Setup gcloud
|
||||
uses: google-github-actions/setup-gcloud@825196879a077b7efa50db2e88409f44de4635c2 # v2.0.0
|
||||
uses: google-github-actions/setup-gcloud@e30db14379863a8c79331b04a9969f4c1e225e0b # v1.1.1
|
||||
- name: Setup QEMU
|
||||
uses: docker/setup-qemu-action@68827325e0b33c7199eb31dd4e31fbe9023e06e3 # v3.0.0
|
||||
- name: Setup Docker Buildx
|
||||
|
||||
2
.github/workflows/e2e.yaml
vendored
2
.github/workflows/e2e.yaml
vendored
@@ -23,7 +23,7 @@ jobs:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0
|
||||
uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0
|
||||
with:
|
||||
go-version: 1.20.x
|
||||
cache-dependency-path: |
|
||||
|
||||
4
.github/workflows/release.yaml
vendored
4
.github/workflows/release.yaml
vendored
@@ -24,7 +24,7 @@ jobs:
|
||||
- name: Unshallow
|
||||
run: git fetch --prune --unshallow
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0
|
||||
uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0
|
||||
with:
|
||||
go-version: 1.20.x
|
||||
cache: false
|
||||
@@ -34,7 +34,7 @@ jobs:
|
||||
id: buildx
|
||||
uses: docker/setup-buildx-action@f95db51fddba0c2d1ec667646a06c2ce06100226 # v3.0.0
|
||||
- name: Setup Syft
|
||||
uses: anchore/sbom-action/download-syft@5ecf649a417b8ae17dc8383dc32d46c03f2312df # v0.15.1
|
||||
uses: anchore/sbom-action/download-syft@78fc58e266e87a38d4194b2137a3d4e9bcaf7ca1 # v0.14.3
|
||||
- name: Setup Cosign
|
||||
uses: sigstore/cosign-installer@1fc5bd396d372bee37d608f955b336615edf79c8 # v3.2.0
|
||||
- name: Setup Kustomize
|
||||
|
||||
6
.github/workflows/scan.yaml
vendored
6
.github/workflows/scan.yaml
vendored
@@ -19,7 +19,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
- name: Run FOSSA scan and upload build data
|
||||
uses: fossa-contrib/fossa-action@cdc5065bcdee31a32e47d4585df72d66e8e941c2 # v3.0.0
|
||||
uses: fossa-contrib/fossa-action@6728dc6fe9a068c648d080c33829ffbe56565023 # v2.0.0
|
||||
with:
|
||||
# FOSSA Push-Only API Token
|
||||
fossa-api-key: 5ee8bf422db1471e0bcf2bcb289185de
|
||||
@@ -35,7 +35,7 @@ jobs:
|
||||
- name: Setup Kustomize
|
||||
uses: fluxcd/pkg/actions/kustomize@main
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0
|
||||
uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0
|
||||
with:
|
||||
go-version: 1.20.x
|
||||
cache-dependency-path: |
|
||||
@@ -66,7 +66,7 @@ jobs:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0
|
||||
uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0
|
||||
with:
|
||||
go-version: 1.20.x
|
||||
cache-dependency-path: |
|
||||
|
||||
2
.github/workflows/update.yaml
vendored
2
.github/workflows/update.yaml
vendored
@@ -20,7 +20,7 @@ jobs:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0
|
||||
uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0
|
||||
with:
|
||||
go-version: 1.20.x
|
||||
cache-dependency-path: |
|
||||
|
||||
@@ -19,7 +19,7 @@ package main
|
||||
import (
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
notificationv1 "github.com/fluxcd/notification-controller/api/v1beta3"
|
||||
notificationv1 "github.com/fluxcd/notification-controller/api/v1beta2"
|
||||
)
|
||||
|
||||
// notificationv1.Alert
|
||||
|
||||
@@ -19,7 +19,7 @@ package main
|
||||
import (
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
notificationv1 "github.com/fluxcd/notification-controller/api/v1beta3"
|
||||
notificationv1 "github.com/fluxcd/notification-controller/api/v1beta2"
|
||||
)
|
||||
|
||||
// notificationv1.Provider
|
||||
|
||||
195
cmd/flux/audit.go
Normal file
195
cmd/flux/audit.go
Normal file
@@ -0,0 +1,195 @@
|
||||
/*
|
||||
Copyright 2023 The Flux authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/fluxcd/flux2/v2/internal/utils"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/pflag"
|
||||
v1 "k8s.io/api/apps/v1"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1"
|
||||
)
|
||||
|
||||
var ctrlChecks = map[string]map[string]bool{
|
||||
"helm-controller": {
|
||||
"insecure-kubeconfig-exec": false,
|
||||
"insecure-kubeconfig-tls": false,
|
||||
},
|
||||
"kustomize-controller": {
|
||||
"insecure-kubeconfig-exec": false,
|
||||
"insecure-kubeconfig-tls": false,
|
||||
"no-remote-bases": true,
|
||||
},
|
||||
}
|
||||
|
||||
var multiTenancyCtrlChecks = map[string]map[string]bool{
|
||||
"helm-controller": {
|
||||
"no-cross-namespace-refs": true,
|
||||
},
|
||||
"kustomize-controller": {
|
||||
"no-cross-namespace-refs": true,
|
||||
},
|
||||
"notification-controller": {
|
||||
"no-cross-namespace-refs": true,
|
||||
},
|
||||
"image-reflector-controller": {
|
||||
"no-cross-namespace-refs": true,
|
||||
},
|
||||
"image-automation-controller": {
|
||||
"no-cross-namespace-refs": true,
|
||||
},
|
||||
}
|
||||
|
||||
var multiTenancyFlag bool
|
||||
|
||||
var auditCmd = &cobra.Command{
|
||||
Use: "audit",
|
||||
Short: "Audit the Flux installation for security best practices",
|
||||
Long: withPreviewNote("TBD"),
|
||||
Example: ` TBD`,
|
||||
Args: cobra.NoArgs,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
|
||||
defer cancel()
|
||||
|
||||
kubeClient, err := utils.KubeClient(kubeconfigArgs, kubeclientOptions)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logger.Actionf("Starting audit")
|
||||
|
||||
for ctrl, checks := range ctrlChecks {
|
||||
if err := auditController(ctx, kubeClient, ctrl, checks); err != nil {
|
||||
return fmt.Errorf("failed auditing %s: %w", ctrl, err)
|
||||
}
|
||||
}
|
||||
|
||||
if err := auditSecretDecryption(ctx, kubeClient); err != nil {
|
||||
return fmt.Errorf("failed auditing Secret decryption: %w", err)
|
||||
}
|
||||
|
||||
if multiTenancyFlag {
|
||||
logger.Actionf("Multi-tenancy lock-down")
|
||||
for ctrl, checks := range multiTenancyCtrlChecks {
|
||||
if err := auditController(ctx, kubeClient, ctrl, checks); err != nil {
|
||||
return fmt.Errorf("failed auditing %s for multi-tenancy lock-down: %w", ctrl, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
func auditSecretDecryption(ctx context.Context, c client.Client) error {
|
||||
var ksl kustomizev1.KustomizationList
|
||||
if err := c.List(ctx, &ksl); err != nil {
|
||||
return fmt.Errorf("failed to retrieve Kustomizations: %w", err)
|
||||
}
|
||||
|
||||
success := true
|
||||
for _, ks := range ksl.Items {
|
||||
if ks.Status.Inventory == nil {
|
||||
continue
|
||||
}
|
||||
if ks.Spec.Decryption != nil {
|
||||
continue
|
||||
}
|
||||
for _, e := range ks.Status.Inventory.Entries {
|
||||
parts := strings.Split(e.ID, "_")
|
||||
if parts[2] == "" && parts[3] == "Secret" {
|
||||
success = false
|
||||
logger.Warningf("%s/%s doesn't have Secret decryption configured", ks.Namespace, ks.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if success {
|
||||
logger.Successf("Secret decryption is configured for all Kustomizations that create Secrets")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func auditController(ctx context.Context, c client.Client, name string, flags map[string]bool) error {
|
||||
hcDeploys, err := getManagerArgs(ctx, c, name)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get %s flags: %w", name, err)
|
||||
}
|
||||
|
||||
if len(hcDeploys) == 0 {
|
||||
logger.Warningf("No %s Deployment found, auditing skipped", name)
|
||||
} else {
|
||||
for name, args := range hcDeploys {
|
||||
for flag, desired := range flags {
|
||||
hcExec, err := assertBoolFlagValue(args, flag, desired)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed parsing %q args: %w", name, err)
|
||||
}
|
||||
if hcExec == desired {
|
||||
logger.Successf("%s: %s is %t", name, flag, desired)
|
||||
} else {
|
||||
logger.Warningf("%s: %s should be %t", name, flag, desired)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func getManagerArgs(ctx context.Context, c client.Client, component string) (map[string][]string, error) {
|
||||
var deploys v1.DeploymentList
|
||||
if err := c.List(ctx, &deploys, client.MatchingLabels{
|
||||
"app.kubernetes.io/component": component,
|
||||
}); err != nil {
|
||||
return nil, fmt.Errorf("failed to retrieve %s deployments: %w", component, err)
|
||||
}
|
||||
|
||||
res := make(map[string][]string, 0)
|
||||
|
||||
for _, deploy := range deploys.Items {
|
||||
for _, ctr := range deploy.Spec.Template.Spec.Containers {
|
||||
if ctr.Name == "manager" {
|
||||
res[deploy.Name] = ctr.Args
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func assertBoolFlagValue(args []string, flagName string, value bool) (bool, error) {
|
||||
fs := pflag.NewFlagSet("tmp", pflag.ContinueOnError)
|
||||
fs.ParseErrorsWhitelist.UnknownFlags = true
|
||||
f := fs.BoolP(flagName, "", false, "")
|
||||
if err := fs.Parse(args); err != nil {
|
||||
return false, fmt.Errorf("failed parsing args: %w", err)
|
||||
}
|
||||
return *f, nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
auditCmd.Flags().BoolVar(&multiTenancyFlag, "multi-tenancy", false, "Enable additional audit checks for multi-tenant clusters.")
|
||||
rootCmd.AddCommand(auditCmd)
|
||||
}
|
||||
@@ -56,7 +56,7 @@ the bootstrap command will perform an upgrade if needed.`,
|
||||
# Run bootstrap for a public repository on a personal account
|
||||
flux bootstrap bitbucket-server --owner=<user> --repository=<repository name> --private=false --personal --hostname=<domain> --token-auth --path=clusters/my-cluster
|
||||
|
||||
# Run bootstrap for an existing repository with a branch named main
|
||||
# Run bootstrap for a an existing repository with a branch named main
|
||||
flux bootstrap bitbucket-server --owner=<project> --username=<user> --repository=<repository name> --branch=main --hostname=<domain> --token-auth --path=clusters/my-cluster`,
|
||||
RunE: bootstrapBServerCmdRun,
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ the bootstrap command will perform an upgrade if needed.`,
|
||||
# Run bootstrap for a private repository hosted on a GitLab server
|
||||
flux bootstrap gitlab --owner=<group> --repository=<repository name> --hostname=<domain> --token-auth
|
||||
|
||||
# Run bootstrap for an existing repository with a branch named main
|
||||
# Run bootstrap for a an existing repository with a branch named main
|
||||
flux bootstrap gitlab --owner=<organization> --repository=<repository name> --branch=main --token-auth
|
||||
|
||||
# Run bootstrap for a private repository using Deploy Token authentication
|
||||
|
||||
@@ -18,7 +18,6 @@ package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
@@ -27,7 +26,6 @@ import (
|
||||
v1 "k8s.io/api/apps/v1"
|
||||
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/rest"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
"github.com/fluxcd/pkg/version"
|
||||
@@ -82,20 +80,7 @@ func runCheckCmd(cmd *cobra.Command, args []string) error {
|
||||
|
||||
fluxCheck()
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
|
||||
defer cancel()
|
||||
|
||||
cfg, err := utils.KubeConfig(kubeconfigArgs, kubeclientOptions)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Kubernetes client initialization failed: %s", err.Error())
|
||||
}
|
||||
|
||||
kubeClient, err := client.New(cfg, client.Options{Scheme: utils.NewScheme()})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !kubernetesCheck(cfg, kubernetesConstraints) {
|
||||
if !kubernetesCheck(kubernetesConstraints) {
|
||||
checkFailed = true
|
||||
}
|
||||
|
||||
@@ -107,18 +92,13 @@ func runCheckCmd(cmd *cobra.Command, args []string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
logger.Actionf("checking version in cluster")
|
||||
if !fluxClusterVersionCheck(ctx, kubeClient) {
|
||||
checkFailed = true
|
||||
}
|
||||
|
||||
logger.Actionf("checking controllers")
|
||||
if !componentsCheck(ctx, kubeClient) {
|
||||
if !componentsCheck() {
|
||||
checkFailed = true
|
||||
}
|
||||
|
||||
logger.Actionf("checking crds")
|
||||
if !crdsCheck(ctx, kubeClient) {
|
||||
if !crdsCheck() {
|
||||
checkFailed = true
|
||||
}
|
||||
|
||||
@@ -149,11 +129,17 @@ func fluxCheck() {
|
||||
return
|
||||
}
|
||||
if latestSv.GreaterThan(curSv) {
|
||||
logger.Failuref("flux %s <%s (new CLI version is available, please upgrade)", curSv, latestSv)
|
||||
logger.Failuref("flux %s <%s (new version is available, please upgrade)", curSv, latestSv)
|
||||
}
|
||||
}
|
||||
|
||||
func kubernetesCheck(cfg *rest.Config, constraints []string) bool {
|
||||
func kubernetesCheck(constraints []string) bool {
|
||||
cfg, err := utils.KubeConfig(kubeconfigArgs, kubeclientOptions)
|
||||
if err != nil {
|
||||
logger.Failuref("Kubernetes client initialization failed: %s", err.Error())
|
||||
return false
|
||||
}
|
||||
|
||||
clientSet, err := kubernetes.NewForConfig(cfg)
|
||||
if err != nil {
|
||||
logger.Failuref("Kubernetes client initialization failed: %s", err.Error())
|
||||
@@ -192,8 +178,21 @@ func kubernetesCheck(cfg *rest.Config, constraints []string) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func componentsCheck(ctx context.Context, kubeClient client.Client) bool {
|
||||
statusChecker, err := status.NewStatusCheckerWithClient(kubeClient, checkArgs.pollInterval, rootArgs.timeout, logger)
|
||||
func componentsCheck() bool {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
|
||||
defer cancel()
|
||||
|
||||
kubeConfig, err := utils.KubeConfig(kubeconfigArgs, kubeclientOptions)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
statusChecker, err := status.NewStatusChecker(kubeConfig, checkArgs.pollInterval, rootArgs.timeout, logger)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
kubeClient, err := utils.KubeClient(kubeconfigArgs, kubeclientOptions)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
@@ -223,7 +222,15 @@ func componentsCheck(ctx context.Context, kubeClient client.Client) bool {
|
||||
return ok
|
||||
}
|
||||
|
||||
func crdsCheck(ctx context.Context, kubeClient client.Client) bool {
|
||||
func crdsCheck() bool {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
|
||||
defer cancel()
|
||||
|
||||
kubeClient, err := utils.KubeClient(kubeconfigArgs, kubeclientOptions)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
ok := true
|
||||
selector := client.MatchingLabels{manifestgen.PartOfLabelKey: manifestgen.PartOfLabelValue}
|
||||
var list apiextensionsv1.CustomResourceDefinitionList
|
||||
@@ -246,17 +253,3 @@ func crdsCheck(ctx context.Context, kubeClient client.Client) bool {
|
||||
}
|
||||
return ok
|
||||
}
|
||||
|
||||
func fluxClusterVersionCheck(ctx context.Context, kubeClient client.Client) bool {
|
||||
clusterInfo, err := getFluxClusterInfo(ctx, kubeClient)
|
||||
if err != nil {
|
||||
logger.Failuref("checking failed: %s", err.Error())
|
||||
return false
|
||||
}
|
||||
|
||||
if clusterInfo.distribution() != "" {
|
||||
logger.Successf("distribution: %s", clusterInfo.distribution())
|
||||
}
|
||||
logger.Successf("bootstrapped: %t", clusterInfo.bootstrapped)
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -27,8 +27,6 @@ import (
|
||||
|
||||
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1"
|
||||
sourcev1 "github.com/fluxcd/source-controller/api/v1"
|
||||
|
||||
"github.com/fluxcd/flux2/v2/pkg/manifestgen"
|
||||
)
|
||||
|
||||
// bootstrapLabels are labels put on a resource by kustomize-controller. These labels on the CRD indicates
|
||||
@@ -44,8 +42,6 @@ type fluxClusterInfo struct {
|
||||
bootstrapped bool
|
||||
// managedBy is the name of the tool being used to manage the installation of Flux.
|
||||
managedBy string
|
||||
// partOf indicates which distribution the instance is a part of.
|
||||
partOf string
|
||||
// version is the Flux version number in semver format.
|
||||
version string
|
||||
}
|
||||
@@ -72,7 +68,7 @@ func getFluxClusterInfo(ctx context.Context, c client.Client) (fluxClusterInfo,
|
||||
return info, err
|
||||
}
|
||||
|
||||
info.version = crdMetadata.Labels[manifestgen.VersionLabelKey]
|
||||
info.version = crdMetadata.Labels["app.kubernetes.io/version"]
|
||||
|
||||
var present bool
|
||||
for _, l := range bootstrapLabels {
|
||||
@@ -82,15 +78,11 @@ func getFluxClusterInfo(ctx context.Context, c client.Client) (fluxClusterInfo,
|
||||
info.bootstrapped = true
|
||||
}
|
||||
|
||||
// the `app.kubernetes.io/managed-by` label is not set by flux but might be set by other
|
||||
// the `app.kubernetes.io` label is not set by flux but might be set by other
|
||||
// tools used to install Flux e.g Helm.
|
||||
if manager, ok := crdMetadata.Labels["app.kubernetes.io/managed-by"]; ok {
|
||||
info.managedBy = manager
|
||||
}
|
||||
|
||||
if partOf, ok := crdMetadata.Labels[manifestgen.PartOfLabelKey]; ok {
|
||||
info.partOf = partOf
|
||||
}
|
||||
return info, nil
|
||||
}
|
||||
|
||||
@@ -113,14 +105,6 @@ func confirmFluxInstallOverride(info fluxClusterInfo) error {
|
||||
return err
|
||||
}
|
||||
|
||||
func (info fluxClusterInfo) distribution() string {
|
||||
distribution := info.version
|
||||
if info.partOf != "" {
|
||||
distribution = fmt.Sprintf("%s-%s", info.partOf, info.version)
|
||||
}
|
||||
return distribution
|
||||
}
|
||||
|
||||
func installManagedByFlux(manager string) bool {
|
||||
return manager == "" || manager == "flux"
|
||||
}
|
||||
|
||||
@@ -102,17 +102,6 @@ func Test_getFluxClusterInfo(t *testing.T) {
|
||||
version: "v2.1.0",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "CRD with version and part-of labels",
|
||||
labels: map[string]string{
|
||||
"app.kubernetes.io/version": "v2.1.0",
|
||||
"app.kubernetes.io/part-of": "flux",
|
||||
},
|
||||
wantInfo: fluxClusterInfo{
|
||||
version: "v2.1.0",
|
||||
partOf: "flux",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
|
||||
@@ -132,7 +132,7 @@ func (names apiType) upsertAndWait(object upsertWaitable, mutate func() error) e
|
||||
|
||||
logger.Waitingf("waiting for %s reconciliation", names.kind)
|
||||
if err := wait.PollUntilContextTimeout(ctx, rootArgs.pollInterval, rootArgs.timeout, true,
|
||||
isObjectReadyConditionFunc(kubeClient, namespacedName, object.asClientObject())); err != nil {
|
||||
isReady(kubeClient, namespacedName, object)); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Successf("%s reconciliation completed", names.kind)
|
||||
|
||||
@@ -22,13 +22,14 @@ import (
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
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"
|
||||
|
||||
notificationv1 "github.com/fluxcd/notification-controller/api/v1"
|
||||
notificationv1b3 "github.com/fluxcd/notification-controller/api/v1beta3"
|
||||
notificationv1b2 "github.com/fluxcd/notification-controller/api/v1beta2"
|
||||
"github.com/fluxcd/pkg/apis/meta"
|
||||
|
||||
"github.com/fluxcd/flux2/v2/internal/utils"
|
||||
@@ -96,13 +97,13 @@ func createAlertCmdRun(cmd *cobra.Command, args []string) error {
|
||||
logger.Generatef("generating Alert")
|
||||
}
|
||||
|
||||
alert := notificationv1b3.Alert{
|
||||
alert := notificationv1b2.Alert{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
Namespace: *kubeconfigArgs.Namespace,
|
||||
Labels: sourceLabels,
|
||||
},
|
||||
Spec: notificationv1b3.AlertSpec{
|
||||
Spec: notificationv1b2.AlertSpec{
|
||||
ProviderRef: meta.LocalObjectReference{
|
||||
Name: alertArgs.providerRef,
|
||||
},
|
||||
@@ -132,7 +133,7 @@ func createAlertCmdRun(cmd *cobra.Command, args []string) error {
|
||||
|
||||
logger.Waitingf("waiting for Alert reconciliation")
|
||||
if err := wait.PollUntilContextTimeout(ctx, rootArgs.pollInterval, rootArgs.timeout, true,
|
||||
isStaticObjectReadyConditionFunc(kubeClient, namespacedName, &alert)); err != nil {
|
||||
isAlertReady(kubeClient, namespacedName, &alert)); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Successf("Alert %s is ready", name)
|
||||
@@ -140,13 +141,13 @@ func createAlertCmdRun(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
|
||||
func upsertAlert(ctx context.Context, kubeClient client.Client,
|
||||
alert *notificationv1b3.Alert) (types.NamespacedName, error) {
|
||||
alert *notificationv1b2.Alert) (types.NamespacedName, error) {
|
||||
namespacedName := types.NamespacedName{
|
||||
Namespace: alert.GetNamespace(),
|
||||
Name: alert.GetName(),
|
||||
}
|
||||
|
||||
var existing notificationv1b3.Alert
|
||||
var existing notificationv1b2.Alert
|
||||
err := kubeClient.Get(ctx, namespacedName, &existing)
|
||||
if err != nil {
|
||||
if errors.IsNotFound(err) {
|
||||
@@ -169,3 +170,22 @@ func upsertAlert(ctx context.Context, kubeClient client.Client,
|
||||
logger.Successf("Alert updated")
|
||||
return namespacedName, nil
|
||||
}
|
||||
|
||||
func isAlertReady(kubeClient client.Client, namespacedName types.NamespacedName, alert *notificationv1b2.Alert) wait.ConditionWithContextFunc {
|
||||
return func(ctx context.Context) (bool, error) {
|
||||
err := kubeClient.Get(ctx, namespacedName, alert)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if c := apimeta.FindStatusCondition(alert.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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,12 +22,13 @@ import (
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
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"
|
||||
|
||||
notificationv1 "github.com/fluxcd/notification-controller/api/v1beta3"
|
||||
notificationv1 "github.com/fluxcd/notification-controller/api/v1beta2"
|
||||
"github.com/fluxcd/pkg/apis/meta"
|
||||
|
||||
"github.com/fluxcd/flux2/v2/internal/utils"
|
||||
@@ -127,7 +128,7 @@ func createAlertProviderCmdRun(cmd *cobra.Command, args []string) error {
|
||||
|
||||
logger.Waitingf("waiting for Provider reconciliation")
|
||||
if err := wait.PollUntilContextTimeout(ctx, rootArgs.pollInterval, rootArgs.timeout, true,
|
||||
isStaticObjectReadyConditionFunc(kubeClient, namespacedName, &provider)); err != nil {
|
||||
isAlertProviderReady(kubeClient, namespacedName, &provider)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -166,3 +167,22 @@ func upsertAlertProvider(ctx context.Context, kubeClient client.Client,
|
||||
logger.Successf("Provider updated")
|
||||
return namespacedName, nil
|
||||
}
|
||||
|
||||
func isAlertProviderReady(kubeClient client.Client, namespacedName types.NamespacedName, provider *notificationv1.Provider) wait.ConditionWithContextFunc {
|
||||
return func(ctx context.Context) (bool, error) {
|
||||
err := kubeClient.Get(ctx, namespacedName, provider)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if c := apimeta.FindStatusCondition(provider.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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ import (
|
||||
"github.com/spf13/cobra"
|
||||
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
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"
|
||||
@@ -303,7 +304,7 @@ func createHelmReleaseCmdRun(cmd *cobra.Command, args []string) error {
|
||||
|
||||
logger.Waitingf("waiting for HelmRelease reconciliation")
|
||||
if err := wait.PollUntilContextTimeout(ctx, rootArgs.pollInterval, rootArgs.timeout, true,
|
||||
isObjectReadyConditionFunc(kubeClient, namespacedName, &helmRelease)); err != nil {
|
||||
isHelmReleaseReady(kubeClient, namespacedName, &helmRelease)); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Successf("HelmRelease %s is ready", name)
|
||||
@@ -343,6 +344,22 @@ func upsertHelmRelease(ctx context.Context, kubeClient client.Client,
|
||||
return namespacedName, nil
|
||||
}
|
||||
|
||||
func isHelmReleaseReady(kubeClient client.Client, namespacedName types.NamespacedName, helmRelease *helmv2.HelmRelease) wait.ConditionWithContextFunc {
|
||||
return func(ctx context.Context) (bool, error) {
|
||||
err := kubeClient.Get(ctx, namespacedName, helmRelease)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
// Confirm the state we are observing is for the current generation
|
||||
if helmRelease.Generation != helmRelease.Status.ObservedGeneration {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
return apimeta.IsStatusConditionTrue(helmRelease.Status.Conditions, meta.ReadyCondition), nil
|
||||
}
|
||||
}
|
||||
|
||||
func validateStrategy(input string) bool {
|
||||
allowedStrategy := []string{"Revision", "ChartVersion"}
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ import (
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
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"
|
||||
@@ -263,7 +264,7 @@ func createKsCmdRun(cmd *cobra.Command, args []string) error {
|
||||
|
||||
logger.Waitingf("waiting for Kustomization reconciliation")
|
||||
if err := wait.PollUntilContextTimeout(ctx, rootArgs.pollInterval, rootArgs.timeout, true,
|
||||
isObjectReadyConditionFunc(kubeClient, namespacedName, &kustomization)); err != nil {
|
||||
isKustomizationReady(kubeClient, namespacedName, &kustomization)); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Successf("Kustomization %s is ready", name)
|
||||
@@ -302,3 +303,27 @@ func upsertKustomization(ctx context.Context, kubeClient client.Client,
|
||||
logger.Successf("Kustomization updated")
|
||||
return namespacedName, nil
|
||||
}
|
||||
|
||||
func isKustomizationReady(kubeClient client.Client, namespacedName types.NamespacedName, kustomization *kustomizev1.Kustomization) wait.ConditionWithContextFunc {
|
||||
return func(ctx context.Context) (bool, error) {
|
||||
err := kubeClient.Get(ctx, namespacedName, kustomization)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
// Confirm the state we are observing is for the current generation
|
||||
if kustomization.Generation != kustomization.Status.ObservedGeneration {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
if c := apimeta.FindStatusCondition(kustomization.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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import (
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
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"
|
||||
@@ -139,7 +140,7 @@ func createReceiverCmdRun(cmd *cobra.Command, args []string) error {
|
||||
|
||||
logger.Waitingf("waiting for Receiver reconciliation")
|
||||
if err := wait.PollUntilContextTimeout(ctx, rootArgs.pollInterval, rootArgs.timeout, true,
|
||||
isObjectReadyConditionFunc(kubeClient, namespacedName, &receiver)); err != nil {
|
||||
isReceiverReady(kubeClient, namespacedName, &receiver)); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Successf("Receiver %s is ready", name)
|
||||
@@ -178,3 +179,22 @@ func upsertReceiver(ctx context.Context, kubeClient client.Client,
|
||||
logger.Successf("Receiver updated")
|
||||
return namespacedName, nil
|
||||
}
|
||||
|
||||
func isReceiverReady(kubeClient client.Client, namespacedName types.NamespacedName, receiver *notificationv1.Receiver) wait.ConditionWithContextFunc {
|
||||
return func(ctx context.Context) (bool, error) {
|
||||
err := kubeClient.Get(ctx, namespacedName, receiver)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if c := apimeta.FindStatusCondition(receiver.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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ import (
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
"github.com/fluxcd/pkg/apis/meta"
|
||||
"github.com/fluxcd/pkg/runtime/conditions"
|
||||
|
||||
sourcev1 "github.com/fluxcd/source-controller/api/v1beta2"
|
||||
|
||||
@@ -204,7 +205,7 @@ func createSourceBucketCmdRun(cmd *cobra.Command, args []string) error {
|
||||
|
||||
logger.Waitingf("waiting for Bucket source reconciliation")
|
||||
if err := wait.PollUntilContextTimeout(ctx, rootArgs.pollInterval, rootArgs.timeout, true,
|
||||
isObjectReadyConditionFunc(kubeClient, namespacedName, bucket)); err != nil {
|
||||
isBucketReady(kubeClient, namespacedName, bucket)); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Successf("Bucket source reconciliation completed")
|
||||
@@ -246,3 +247,29 @@ func upsertBucket(ctx context.Context, kubeClient client.Client,
|
||||
logger.Successf("Bucket source updated")
|
||||
return namespacedName, nil
|
||||
}
|
||||
|
||||
func isBucketReady(kubeClient client.Client, namespacedName types.NamespacedName, bucket *sourcev1.Bucket) wait.ConditionWithContextFunc {
|
||||
return func(ctx context.Context) (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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@ import (
|
||||
"sigs.k8s.io/yaml"
|
||||
|
||||
"github.com/fluxcd/pkg/apis/meta"
|
||||
"github.com/fluxcd/pkg/runtime/conditions"
|
||||
|
||||
sourcev1 "github.com/fluxcd/source-controller/api/v1"
|
||||
|
||||
@@ -325,7 +326,7 @@ func createSourceGitCmdRun(cmd *cobra.Command, args []string) error {
|
||||
|
||||
logger.Waitingf("waiting for GitRepository source reconciliation")
|
||||
if err := wait.PollUntilContextTimeout(ctx, rootArgs.pollInterval, rootArgs.timeout, true,
|
||||
isObjectReadyConditionFunc(kubeClient, namespacedName, &gitRepository)); err != nil {
|
||||
isGitRepositoryReady(kubeClient, namespacedName, &gitRepository)); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Successf("GitRepository source reconciliation completed")
|
||||
@@ -367,3 +368,29 @@ func upsertGitRepository(ctx context.Context, kubeClient client.Client,
|
||||
logger.Successf("GitRepository source updated")
|
||||
return namespacedName, nil
|
||||
}
|
||||
|
||||
func isGitRepositoryReady(kubeClient client.Client, namespacedName types.NamespacedName, gitRepository *sourcev1.GitRepository) wait.ConditionWithContextFunc {
|
||||
return func(ctx context.Context) (bool, error) {
|
||||
err := kubeClient.Get(ctx, namespacedName, gitRepository)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if c := conditions.Get(gitRepository, 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 {
|
||||
case metav1.ConditionTrue:
|
||||
return true, nil
|
||||
case metav1.ConditionFalse:
|
||||
return false, fmt.Errorf(c.Message)
|
||||
}
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -181,21 +181,12 @@ func TestCreateSourceGit(t *testing.T) {
|
||||
Time: time.Now(),
|
||||
},
|
||||
}
|
||||
repo.Status.ObservedGeneration = repo.GetGeneration()
|
||||
},
|
||||
}, {
|
||||
"Failed",
|
||||
command,
|
||||
assertError("failed message"),
|
||||
func(repo *sourcev1.GitRepository) {
|
||||
stalledCondition := metav1.Condition{
|
||||
Type: meta.StalledCondition,
|
||||
Status: metav1.ConditionTrue,
|
||||
Reason: sourcev1.URLInvalidReason,
|
||||
Message: "failed message",
|
||||
ObservedGeneration: repo.GetGeneration(),
|
||||
}
|
||||
apimeta.SetStatusCondition(&repo.Status.Conditions, stalledCondition)
|
||||
newCondition := metav1.Condition{
|
||||
Type: meta.ReadyCondition,
|
||||
Status: metav1.ConditionFalse,
|
||||
@@ -204,7 +195,6 @@ func TestCreateSourceGit(t *testing.T) {
|
||||
ObservedGeneration: repo.GetGeneration(),
|
||||
}
|
||||
apimeta.SetStatusCondition(&repo.Status.Conditions, newCondition)
|
||||
repo.Status.ObservedGeneration = repo.GetGeneration()
|
||||
},
|
||||
}, {
|
||||
"NoArtifact",
|
||||
@@ -220,7 +210,6 @@ func TestCreateSourceGit(t *testing.T) {
|
||||
ObservedGeneration: repo.GetGeneration(),
|
||||
}
|
||||
apimeta.SetStatusCondition(&repo.Status.Conditions, newCondition)
|
||||
repo.Status.ObservedGeneration = repo.GetGeneration()
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ import (
|
||||
"os"
|
||||
|
||||
"github.com/fluxcd/pkg/apis/meta"
|
||||
"github.com/fluxcd/pkg/runtime/conditions"
|
||||
"github.com/spf13/cobra"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
@@ -230,12 +231,8 @@ func createSourceHelmCmdRun(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
|
||||
logger.Waitingf("waiting for HelmRepository source reconciliation")
|
||||
readyConditionFunc := isObjectReadyConditionFunc(kubeClient, namespacedName, helmRepository)
|
||||
if helmRepository.Spec.Type == sourcev1.HelmRepositoryTypeOCI {
|
||||
// HelmRepository type OCI is a static object.
|
||||
readyConditionFunc = isStaticObjectReadyConditionFunc(kubeClient, namespacedName, helmRepository)
|
||||
}
|
||||
if err := wait.PollUntilContextTimeout(ctx, rootArgs.pollInterval, rootArgs.timeout, true, readyConditionFunc); err != nil {
|
||||
if err := wait.PollUntilContextTimeout(ctx, rootArgs.pollInterval, rootArgs.timeout, true,
|
||||
isHelmRepositoryReady(kubeClient, namespacedName, helmRepository)); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Successf("HelmRepository source reconciliation completed")
|
||||
@@ -282,3 +279,29 @@ func upsertHelmRepository(ctx context.Context, kubeClient client.Client,
|
||||
logger.Successf("source updated")
|
||||
return namespacedName, nil
|
||||
}
|
||||
|
||||
func isHelmRepositoryReady(kubeClient client.Client, namespacedName types.NamespacedName, helmRepository *sourcev1.HelmRepository) wait.ConditionWithContextFunc {
|
||||
return func(ctx context.Context) (bool, error) {
|
||||
err := kubeClient.Get(ctx, namespacedName, helmRepository)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if c := conditions.Get(helmRepository, meta.ReadyCondition); c != nil {
|
||||
// Confirm the Ready condition we are observing is for the
|
||||
// current generation
|
||||
if c.ObservedGeneration != helmRepository.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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ import (
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
"github.com/fluxcd/pkg/apis/meta"
|
||||
"github.com/fluxcd/pkg/runtime/conditions"
|
||||
|
||||
sourcev1 "github.com/fluxcd/source-controller/api/v1beta2"
|
||||
|
||||
@@ -192,7 +193,7 @@ func createSourceOCIRepositoryCmdRun(cmd *cobra.Command, args []string) error {
|
||||
|
||||
logger.Waitingf("waiting for OCIRepository reconciliation")
|
||||
if err := wait.PollUntilContextTimeout(ctx, rootArgs.pollInterval, rootArgs.timeout, true,
|
||||
isObjectReadyConditionFunc(kubeClient, namespacedName, repository)); err != nil {
|
||||
isOCIRepositoryReady(kubeClient, namespacedName, repository)); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Successf("OCIRepository reconciliation completed")
|
||||
@@ -234,3 +235,29 @@ func upsertOCIRepository(ctx context.Context, kubeClient client.Client,
|
||||
logger.Successf("OCIRepository updated")
|
||||
return namespacedName, nil
|
||||
}
|
||||
|
||||
func isOCIRepositoryReady(kubeClient client.Client, namespacedName types.NamespacedName, ociRepository *sourcev1.OCIRepository) wait.ConditionWithContextFunc {
|
||||
return func(ctx context.Context) (bool, error) {
|
||||
err := kubeClient.Get(ctx, namespacedName, ociRepository)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if c := conditions.Get(ociRepository, meta.ReadyCondition); c != nil {
|
||||
// Confirm the Ready condition we are observing is for the
|
||||
// current generation
|
||||
if c.ObservedGeneration != ociRepository.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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ package main
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
notificationv1 "github.com/fluxcd/notification-controller/api/v1beta3"
|
||||
notificationv1 "github.com/fluxcd/notification-controller/api/v1beta2"
|
||||
)
|
||||
|
||||
var deleteAlertCmd = &cobra.Command{
|
||||
|
||||
@@ -19,7 +19,7 @@ package main
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
notificationv1 "github.com/fluxcd/notification-controller/api/v1beta3"
|
||||
notificationv1 "github.com/fluxcd/notification-controller/api/v1beta2"
|
||||
)
|
||||
|
||||
var deleteAlertProviderCmd = &cobra.Command{
|
||||
|
||||
@@ -44,7 +44,7 @@ import (
|
||||
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1beta2"
|
||||
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1"
|
||||
notificationv1 "github.com/fluxcd/notification-controller/api/v1"
|
||||
notificationv1b3 "github.com/fluxcd/notification-controller/api/v1beta3"
|
||||
notificationv1b2 "github.com/fluxcd/notification-controller/api/v1beta2"
|
||||
sourcev1 "github.com/fluxcd/source-controller/api/v1"
|
||||
sourcev1b2 "github.com/fluxcd/source-controller/api/v1beta2"
|
||||
|
||||
@@ -426,14 +426,14 @@ var fluxKindMap = refMap{
|
||||
},
|
||||
field: []string{"spec", "chart", "spec", "sourceRef"},
|
||||
},
|
||||
notificationv1b3.AlertKind: {
|
||||
gvk: notificationv1b3.GroupVersion.WithKind(notificationv1b3.AlertKind),
|
||||
kind: notificationv1b3.ProviderKind,
|
||||
notificationv1b2.AlertKind: {
|
||||
gvk: notificationv1b2.GroupVersion.WithKind(notificationv1b2.AlertKind),
|
||||
kind: notificationv1b2.ProviderKind,
|
||||
crossNamespaced: false,
|
||||
field: []string{"spec", "providerRef"},
|
||||
},
|
||||
notificationv1.ReceiverKind: {gvk: notificationv1.GroupVersion.WithKind(notificationv1.ReceiverKind)},
|
||||
notificationv1b3.ProviderKind: {gvk: notificationv1b3.GroupVersion.WithKind(notificationv1b3.ProviderKind)},
|
||||
notificationv1b2.ProviderKind: {gvk: notificationv1b2.GroupVersion.WithKind(notificationv1b2.ProviderKind)},
|
||||
imagev1.ImagePolicyKind: {
|
||||
gvk: imagev1.GroupVersion.WithKind(imagev1.ImagePolicyKind),
|
||||
kind: imagev1.ImageRepositoryKind,
|
||||
|
||||
@@ -27,11 +27,20 @@ import (
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/fields"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client/fake"
|
||||
|
||||
helmv2beta1 "github.com/fluxcd/helm-controller/api/v2beta1"
|
||||
autov1 "github.com/fluxcd/image-automation-controller/api/v1beta1"
|
||||
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1beta2"
|
||||
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1"
|
||||
notificationv1 "github.com/fluxcd/notification-controller/api/v1"
|
||||
notificationv1b2 "github.com/fluxcd/notification-controller/api/v1beta2"
|
||||
eventv1 "github.com/fluxcd/pkg/apis/event/v1beta1"
|
||||
"github.com/fluxcd/pkg/ssa"
|
||||
sourcev1 "github.com/fluxcd/source-controller/api/v1"
|
||||
sourcev1b2 "github.com/fluxcd/source-controller/api/v1beta2"
|
||||
|
||||
"github.com/fluxcd/flux2/v2/internal/utils"
|
||||
)
|
||||
@@ -118,7 +127,7 @@ spec:
|
||||
name: podinfo-chart
|
||||
version: '*'
|
||||
---
|
||||
apiVersion: notification.toolkit.fluxcd.io/v1beta3
|
||||
apiVersion: notification.toolkit.fluxcd.io/v1beta2
|
||||
kind: Alert
|
||||
metadata:
|
||||
name: webapp
|
||||
@@ -131,7 +140,7 @@ spec:
|
||||
providerRef:
|
||||
name: slack
|
||||
---
|
||||
apiVersion: notification.toolkit.fluxcd.io/v1beta3
|
||||
apiVersion: notification.toolkit.fluxcd.io/v1beta2
|
||||
kind: Provider
|
||||
metadata:
|
||||
name: slack
|
||||
@@ -163,7 +172,7 @@ func Test_getObjectRef(t *testing.T) {
|
||||
objs, err := ssa.ReadObjects(strings.NewReader(objects))
|
||||
g.Expect(err).To(Not(HaveOccurred()))
|
||||
|
||||
builder := fake.NewClientBuilder().WithScheme(utils.NewScheme())
|
||||
builder := fake.NewClientBuilder().WithScheme(getScheme())
|
||||
for _, obj := range objs {
|
||||
builder = builder.WithObjects(obj)
|
||||
}
|
||||
@@ -247,7 +256,7 @@ func Test_getRows(t *testing.T) {
|
||||
objs, err := ssa.ReadObjects(strings.NewReader(objects))
|
||||
g.Expect(err).To(Not(HaveOccurred()))
|
||||
|
||||
builder := fake.NewClientBuilder().WithScheme(utils.NewScheme())
|
||||
builder := fake.NewClientBuilder().WithScheme(getScheme())
|
||||
for _, obj := range objs {
|
||||
builder = builder.WithObjects(obj)
|
||||
}
|
||||
@@ -401,6 +410,21 @@ func getTestListOpt(kind, name string) client.ListOption {
|
||||
return client.MatchingFieldsSelector{Selector: sel}
|
||||
}
|
||||
|
||||
func getScheme() *runtime.Scheme {
|
||||
newscheme := runtime.NewScheme()
|
||||
corev1.AddToScheme(newscheme)
|
||||
kustomizev1.AddToScheme(newscheme)
|
||||
helmv2beta1.AddToScheme(newscheme)
|
||||
notificationv1.AddToScheme(newscheme)
|
||||
notificationv1b2.AddToScheme(newscheme)
|
||||
imagev1.AddToScheme(newscheme)
|
||||
autov1.AddToScheme(newscheme)
|
||||
sourcev1.AddToScheme(newscheme)
|
||||
sourcev1b2.AddToScheme(newscheme)
|
||||
|
||||
return newscheme
|
||||
}
|
||||
|
||||
func createEvent(obj client.Object, eventType, msg, reason string) corev1.Event {
|
||||
return corev1.Event{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
|
||||
@@ -20,7 +20,7 @@ import (
|
||||
"github.com/spf13/cobra"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
notificationv1 "github.com/fluxcd/notification-controller/api/v1beta3"
|
||||
notificationv1 "github.com/fluxcd/notification-controller/api/v1beta2"
|
||||
)
|
||||
|
||||
var exportAlertCmd = &cobra.Command{
|
||||
|
||||
@@ -20,7 +20,7 @@ import (
|
||||
"github.com/spf13/cobra"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
notificationv1 "github.com/fluxcd/notification-controller/api/v1beta3"
|
||||
notificationv1 "github.com/fluxcd/notification-controller/api/v1beta2"
|
||||
)
|
||||
|
||||
var exportAlertProviderCmd = &cobra.Command{
|
||||
|
||||
@@ -23,10 +23,9 @@ import (
|
||||
"github.com/spf13/cobra"
|
||||
"golang.org/x/text/cases"
|
||||
"golang.org/x/text/language"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
|
||||
notificationv1 "github.com/fluxcd/notification-controller/api/v1beta3"
|
||||
notificationv1 "github.com/fluxcd/notification-controller/api/v1beta2"
|
||||
)
|
||||
|
||||
var getAlertCmd = &cobra.Command{
|
||||
@@ -78,7 +77,7 @@ func init() {
|
||||
|
||||
func (s alertListAdapter) summariseItem(i int, includeNamespace bool, includeKind bool) []string {
|
||||
item := s.Items[i]
|
||||
status, msg := string(metav1.ConditionTrue), "Alert is Ready"
|
||||
status, msg := statusAndMessage(item.Status.Conditions)
|
||||
return append(nameColumns(&item, includeNamespace, includeKind),
|
||||
cases.Title(language.English).String(strconv.FormatBool(item.Spec.Suspend)), status, msg)
|
||||
}
|
||||
@@ -92,5 +91,6 @@ func (s alertListAdapter) headers(includeNamespace bool) []string {
|
||||
}
|
||||
|
||||
func (s alertListAdapter) statusSelectorMatches(i int, conditionType, conditionStatus string) bool {
|
||||
return false
|
||||
item := s.Items[i]
|
||||
return statusMatches(conditionType, conditionStatus, item.Status.Conditions)
|
||||
}
|
||||
|
||||
@@ -20,10 +20,9 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
|
||||
notificationv1 "github.com/fluxcd/notification-controller/api/v1beta3"
|
||||
notificationv1 "github.com/fluxcd/notification-controller/api/v1beta2"
|
||||
)
|
||||
|
||||
var getAlertProviderCmd = &cobra.Command{
|
||||
@@ -75,7 +74,7 @@ func init() {
|
||||
|
||||
func (s alertProviderListAdapter) summariseItem(i int, includeNamespace bool, includeKind bool) []string {
|
||||
item := s.Items[i]
|
||||
status, msg := string(metav1.ConditionTrue), "Provider is Ready"
|
||||
status, msg := statusAndMessage(item.Status.Conditions)
|
||||
return append(nameColumns(&item, includeNamespace, includeKind), status, msg)
|
||||
}
|
||||
|
||||
@@ -88,5 +87,6 @@ func (s alertProviderListAdapter) headers(includeNamespace bool) []string {
|
||||
}
|
||||
|
||||
func (s alertProviderListAdapter) statusSelectorMatches(i int, conditionType, conditionStatus string) bool {
|
||||
return false
|
||||
item := s.Items[i]
|
||||
return statusMatches(conditionType, conditionStatus, item.Status.Conditions)
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ import (
|
||||
helmv2 "github.com/fluxcd/helm-controller/api/v2beta1"
|
||||
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1"
|
||||
notificationv1 "github.com/fluxcd/notification-controller/api/v1"
|
||||
notificationv1b3 "github.com/fluxcd/notification-controller/api/v1beta3"
|
||||
notificationv1b2 "github.com/fluxcd/notification-controller/api/v1beta2"
|
||||
)
|
||||
|
||||
var getAllCmd = &cobra.Command{
|
||||
@@ -63,11 +63,11 @@ var getAllCmd = &cobra.Command{
|
||||
},
|
||||
{
|
||||
apiType: alertProviderType,
|
||||
list: alertProviderListAdapter{¬ificationv1b3.ProviderList{}},
|
||||
list: alertProviderListAdapter{¬ificationv1b2.ProviderList{}},
|
||||
},
|
||||
{
|
||||
apiType: alertType,
|
||||
list: &alertListAdapter{¬ificationv1b3.AlertList{}},
|
||||
list: &alertListAdapter{¬ificationv1b2.AlertList{}},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,6 @@ import (
|
||||
"github.com/spf13/cobra"
|
||||
"golang.org/x/text/cases"
|
||||
"golang.org/x/text/language"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
|
||||
sourcev1 "github.com/fluxcd/source-controller/api/v1beta2"
|
||||
@@ -83,12 +82,7 @@ func (a *helmRepositoryListAdapter) summariseItem(i int, includeNamespace bool,
|
||||
if item.GetArtifact() != nil {
|
||||
revision = item.GetArtifact().Revision
|
||||
}
|
||||
var status, msg string
|
||||
if item.Spec.Type == sourcev1.HelmRepositoryTypeOCI {
|
||||
status, msg = string(metav1.ConditionTrue), "Helm repository is Ready"
|
||||
} else {
|
||||
status, msg = statusAndMessage(item.Status.Conditions)
|
||||
}
|
||||
status, msg := statusAndMessage(item.Status.Conditions)
|
||||
revision = utils.TruncateHex(revision)
|
||||
msg = utils.TruncateHex(msg)
|
||||
return append(nameColumns(&item, includeNamespace, includeKind),
|
||||
|
||||
@@ -25,15 +25,10 @@ import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/go-logr/logr"
|
||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
||||
|
||||
"github.com/fluxcd/flux2/v2/internal/utils"
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
log.SetLogger(logr.New(log.NullLogSink{}))
|
||||
|
||||
// Ensure tests print consistent timestamps regardless of timezone
|
||||
os.Setenv("TZ", "UTC")
|
||||
|
||||
|
||||
@@ -34,7 +34,6 @@ import (
|
||||
"github.com/fluxcd/flux2/v2/internal/utils"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/mattn/go-shellwords"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
k8syaml "k8s.io/apimachinery/pkg/util/yaml"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
@@ -113,8 +112,7 @@ func (m *testEnvKubeManager) CreateObjects(clientObjects []*unstructured.Unstruc
|
||||
}
|
||||
obj.SetResourceVersion(createObj.GetResourceVersion())
|
||||
err = m.client.Status().Update(context.Background(), obj)
|
||||
// Updating status of static objects results in not found error.
|
||||
if err != nil && !errors.IsNotFound(err) {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,13 +22,10 @@ package main
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/go-logr/logr"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// The test environment is long running process shared between tests, initialized
|
||||
@@ -37,8 +34,6 @@ import (
|
||||
var testEnv *testEnvKubeManager
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
log.SetLogger(logr.New(log.NullLogSink{}))
|
||||
|
||||
// Ensure tests print consistent timestamps regardless of timezone
|
||||
os.Setenv("TZ", "UTC")
|
||||
|
||||
|
||||
@@ -1,149 +0,0 @@
|
||||
/*
|
||||
Copyright 2023 The Flux authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
kstatus "github.com/fluxcd/cli-utils/pkg/kstatus/status"
|
||||
apimeta "k8s.io/apimachinery/pkg/api/meta"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
"github.com/fluxcd/pkg/apis/meta"
|
||||
"github.com/fluxcd/pkg/runtime/object"
|
||||
"github.com/fluxcd/pkg/runtime/patch"
|
||||
)
|
||||
|
||||
// objectStatusType is the type of object in terms of status when computing the
|
||||
// readiness of an object. Readiness check method depends on the type of object.
|
||||
// For a dynamic object, Ready status condition is considered only for the
|
||||
// latest generation of the object. For a static object that don't have any
|
||||
// condition, the object generation is not considered.
|
||||
type objectStatusType int
|
||||
|
||||
const (
|
||||
objectStatusDynamic objectStatusType = iota
|
||||
objectStatusStatic
|
||||
)
|
||||
|
||||
// isObjectReady determines if an object is ready using the kstatus.Compute()
|
||||
// result. statusType helps differenciate between static and dynamic objects to
|
||||
// accurately check the object's readiness. A dynamic object may have some extra
|
||||
// considerations depending on the object.
|
||||
func isObjectReady(obj client.Object, statusType objectStatusType) (bool, error) {
|
||||
observedGen, err := object.GetStatusObservedGeneration(obj)
|
||||
if err != nil && err != object.ErrObservedGenerationNotFound {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if statusType == objectStatusDynamic {
|
||||
// Object not reconciled yet.
|
||||
if observedGen < 1 {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
cobj, ok := obj.(meta.ObjectWithConditions)
|
||||
if !ok {
|
||||
return false, fmt.Errorf("unable to get conditions from object")
|
||||
}
|
||||
|
||||
if c := apimeta.FindStatusCondition(cobj.GetConditions(), meta.ReadyCondition); c != nil {
|
||||
// Ensure that the ready condition is for the latest generation of
|
||||
// the object.
|
||||
// NOTE: Some APIs like ImageUpdateAutomation and HelmRelease don't
|
||||
// support per condition observed generation yet. Per condition
|
||||
// observed generation for them are always zero.
|
||||
// There are two strategies used across different object kinds to
|
||||
// check the latest ready condition:
|
||||
// - check that the ready condition's generation matches the
|
||||
// object's generation.
|
||||
// - check that the observed generation of the object in the
|
||||
// status matches the object's generation.
|
||||
//
|
||||
// TODO: Once ImageUpdateAutomation and HelmRelease APIs have per
|
||||
// condition observed generation, remove the object's observed
|
||||
// generation and object's generation check (the second condition
|
||||
// below). Also, try replacing this readiness check function with
|
||||
// fluxcd/pkg/ssa's ResourceManager.Wait(), which uses kstatus
|
||||
// internally to check readiness of the objects.
|
||||
if c.ObservedGeneration != 0 && c.ObservedGeneration != obj.GetGeneration() {
|
||||
return false, nil
|
||||
}
|
||||
if c.ObservedGeneration == 0 && observedGen != obj.GetGeneration() {
|
||||
return false, nil
|
||||
}
|
||||
} else {
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
|
||||
u, err := patch.ToUnstructured(obj)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
result, err := kstatus.Compute(u)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
switch result.Status {
|
||||
case kstatus.CurrentStatus:
|
||||
return true, nil
|
||||
case kstatus.InProgressStatus:
|
||||
return false, nil
|
||||
default:
|
||||
return false, fmt.Errorf(result.Message)
|
||||
}
|
||||
}
|
||||
|
||||
// isObjectReadyConditionFunc returns a wait.ConditionFunc to be used with
|
||||
// wait.Poll* while polling for an object with dynamic status to be ready.
|
||||
func isObjectReadyConditionFunc(kubeClient client.Client, namespaceName types.NamespacedName, obj client.Object) wait.ConditionWithContextFunc {
|
||||
return func(ctx context.Context) (bool, error) {
|
||||
err := kubeClient.Get(ctx, namespaceName, obj)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return isObjectReady(obj, objectStatusDynamic)
|
||||
}
|
||||
}
|
||||
|
||||
// isStaticObjectReadyConditionFunc returns a wait.ConditionFunc to be used with
|
||||
// wait.Poll* while polling for an object with static or no status to be
|
||||
// ready.
|
||||
func isStaticObjectReadyConditionFunc(kubeClient client.Client, namespaceName types.NamespacedName, obj client.Object) wait.ConditionWithContextFunc {
|
||||
return func(ctx context.Context) (bool, error) {
|
||||
err := kubeClient.Get(ctx, namespaceName, obj)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return isObjectReady(obj, objectStatusStatic)
|
||||
}
|
||||
}
|
||||
|
||||
// kstatusCompute returns the kstatus computed result of a given object.
|
||||
func kstatusCompute(obj client.Object) (result *kstatus.Result, err error) {
|
||||
u, err := patch.ToUnstructured(obj)
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
return kstatus.Compute(u)
|
||||
}
|
||||
@@ -1,139 +0,0 @@
|
||||
/*
|
||||
Copyright 2023 The Flux authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
notificationv1 "github.com/fluxcd/notification-controller/api/v1beta3"
|
||||
"github.com/fluxcd/pkg/apis/meta"
|
||||
"github.com/fluxcd/pkg/runtime/conditions"
|
||||
sourcev1 "github.com/fluxcd/source-controller/api/v1"
|
||||
)
|
||||
|
||||
func Test_isObjectReady(t *testing.T) {
|
||||
// Ready object.
|
||||
readyObj := &sourcev1.GitRepository{}
|
||||
readyObj.Generation = 1
|
||||
readyObj.Status.ObservedGeneration = 1
|
||||
conditions.MarkTrue(readyObj, meta.ReadyCondition, "foo1", "bar1")
|
||||
|
||||
// Not ready object.
|
||||
notReadyObj := readyObj.DeepCopy()
|
||||
conditions.MarkFalse(notReadyObj, meta.ReadyCondition, "foo2", "bar2")
|
||||
|
||||
// Not reconciled object.
|
||||
notReconciledObj := readyObj.DeepCopy()
|
||||
notReconciledObj.Status = sourcev1.GitRepositoryStatus{ObservedGeneration: -1}
|
||||
|
||||
// No condition.
|
||||
noConditionObj := readyObj.DeepCopy()
|
||||
noConditionObj.Status = sourcev1.GitRepositoryStatus{ObservedGeneration: 1}
|
||||
|
||||
// Outdated condition.
|
||||
readyObjOutdated := readyObj.DeepCopy()
|
||||
readyObjOutdated.Generation = 2
|
||||
|
||||
// Object without per condition observed generation.
|
||||
oldObj := readyObj.DeepCopy()
|
||||
readyTrueCondn := conditions.TrueCondition(meta.ReadyCondition, "foo3", "bar3")
|
||||
oldObj.Status.Conditions = []metav1.Condition{*readyTrueCondn}
|
||||
|
||||
// Outdated object without per condition observed generation.
|
||||
oldObjOutdated := oldObj.DeepCopy()
|
||||
oldObjOutdated.Generation = 2
|
||||
|
||||
// Empty status object.
|
||||
staticObj := readyObj.DeepCopy()
|
||||
staticObj.Status = sourcev1.GitRepositoryStatus{}
|
||||
|
||||
// No status object.
|
||||
noStatusObj := ¬ificationv1.Provider{}
|
||||
noStatusObj.Generation = 1
|
||||
|
||||
type args struct {
|
||||
obj client.Object
|
||||
statusType objectStatusType
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want bool
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "dynamic ready",
|
||||
args: args{obj: readyObj, statusType: objectStatusDynamic},
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "dynamic not ready",
|
||||
args: args{obj: notReadyObj, statusType: objectStatusDynamic},
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "dynamic not reconciled",
|
||||
args: args{obj: notReconciledObj, statusType: objectStatusDynamic},
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "dynamic not condition",
|
||||
args: args{obj: noConditionObj, statusType: objectStatusDynamic},
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "dynamic ready outdated",
|
||||
args: args{obj: readyObjOutdated, statusType: objectStatusDynamic},
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "dynamic ready without per condition gen",
|
||||
args: args{obj: oldObj, statusType: objectStatusDynamic},
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "dynamic outdated ready status without per condition gen",
|
||||
args: args{obj: oldObjOutdated, statusType: objectStatusDynamic},
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "static empty status",
|
||||
args: args{obj: staticObj, statusType: objectStatusStatic},
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "static no status",
|
||||
args: args{obj: noStatusObj, statusType: objectStatusStatic},
|
||||
want: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := isObjectReady(tt.args.obj, tt.args.statusType)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("isObjectReady() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if got != tt.want {
|
||||
t.Errorf("isObjectReady() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -21,7 +21,6 @@ import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
kstatus "github.com/fluxcd/cli-utils/pkg/kstatus/status"
|
||||
"github.com/spf13/cobra"
|
||||
apimeta "k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
@@ -31,6 +30,8 @@ import (
|
||||
"k8s.io/client-go/util/retry"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
notificationv1 "github.com/fluxcd/notification-controller/api/v1"
|
||||
notificationv1b2 "github.com/fluxcd/notification-controller/api/v1beta2"
|
||||
"github.com/fluxcd/pkg/apis/meta"
|
||||
|
||||
"github.com/fluxcd/flux2/v2/internal/utils"
|
||||
@@ -60,7 +61,6 @@ type reconcilable interface {
|
||||
GetAnnotations() map[string]string
|
||||
SetAnnotations(map[string]string)
|
||||
|
||||
isStatic() bool // is it a static object that does not have a reconciler?
|
||||
lastHandledReconcileRequest() string // what was the last handled reconcile request?
|
||||
successMessage() string // what do you want to tell people when successfully reconciled?
|
||||
}
|
||||
@@ -101,11 +101,6 @@ func (reconcile reconcileCommand) run(cmd *cobra.Command, args []string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if reconcile.object.isStatic() {
|
||||
logger.Successf("reconciliation not supported by the object")
|
||||
return nil
|
||||
}
|
||||
|
||||
if reconcile.object.isSuspended() {
|
||||
return fmt.Errorf("resource is suspended")
|
||||
}
|
||||
@@ -117,6 +112,16 @@ func (reconcile reconcileCommand) run(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
logger.Successf("%s annotated", reconcile.kind)
|
||||
|
||||
if reconcile.kind == notificationv1b2.AlertKind || reconcile.kind == notificationv1.ReceiverKind {
|
||||
if err = wait.PollUntilContextTimeout(ctx, rootArgs.pollInterval, rootArgs.timeout, true,
|
||||
isReconcileReady(kubeClient, namespacedName, reconcile.object)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logger.Successf(reconcile.object.successMessage())
|
||||
return nil
|
||||
}
|
||||
|
||||
lastHandledReconcileAt := reconcile.object.lastHandledReconcileRequest()
|
||||
logger.Waitingf("waiting for %s reconciliation", reconcile.kind)
|
||||
if err := wait.PollUntilContextTimeout(ctx, rootArgs.pollInterval, rootArgs.timeout, true,
|
||||
@@ -141,17 +146,9 @@ func reconciliationHandled(kubeClient client.Client, namespacedName types.Namesp
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if obj.lastHandledReconcileRequest() == lastHandledReconcileAt {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
result, err := kstatusCompute(obj.asClientObject())
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return result.Status == kstatus.CurrentStatus, nil
|
||||
isProgressing := apimeta.IsStatusConditionPresentAndEqual(reconcilableConditions(obj),
|
||||
meta.ReadyCondition, metav1.ConditionUnknown)
|
||||
return obj.lastHandledReconcileRequest() != lastHandledReconcileAt && !isProgressing, nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -177,3 +174,22 @@ func requestReconciliation(ctx context.Context, kubeClient client.Client,
|
||||
return kubeClient.Patch(ctx, object, patch)
|
||||
})
|
||||
}
|
||||
|
||||
func isReconcileReady(kubeClient client.Client, namespacedName types.NamespacedName, obj reconcilable) wait.ConditionWithContextFunc {
|
||||
return func(ctx context.Context) (bool, error) {
|
||||
err := kubeClient.Get(ctx, namespacedName, obj.asClientObject())
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if c := apimeta.FindStatusCondition(reconcilableConditions(obj), 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
|
||||
}
|
||||
}
|
||||
|
||||
44
cmd/flux/reconcile_alert.go
Normal file
44
cmd/flux/reconcile_alert.go
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
Copyright 2020 The Flux authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
notificationv1 "github.com/fluxcd/notification-controller/api/v1beta2"
|
||||
)
|
||||
|
||||
var reconcileAlertCmd = &cobra.Command{
|
||||
Use: "alert [name]",
|
||||
Short: "Reconcile an Alert",
|
||||
Long: `The reconcile alert command triggers a reconciliation of an Alert resource and waits for it to finish.`,
|
||||
Example: ` # Trigger a reconciliation for an existing alert
|
||||
flux reconcile alert main`,
|
||||
ValidArgsFunction: resourceNamesCompletionFunc(notificationv1.GroupVersion.WithKind(notificationv1.AlertKind)),
|
||||
RunE: reconcileCommand{
|
||||
apiType: alertType,
|
||||
object: alertAdapter{¬ificationv1.Alert{}},
|
||||
}.run,
|
||||
}
|
||||
|
||||
func init() {
|
||||
reconcileCmd.AddCommand(reconcileAlertCmd)
|
||||
}
|
||||
|
||||
func (obj alertAdapter) lastHandledReconcileRequest() string {
|
||||
return ""
|
||||
}
|
||||
93
cmd/flux/reconcile_alertprovider.go
Normal file
93
cmd/flux/reconcile_alertprovider.go
Normal file
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
Copyright 2020 The Flux authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
|
||||
notificationv1 "github.com/fluxcd/notification-controller/api/v1beta2"
|
||||
"github.com/fluxcd/pkg/apis/meta"
|
||||
|
||||
"github.com/fluxcd/flux2/v2/internal/utils"
|
||||
)
|
||||
|
||||
var reconcileAlertProviderCmd = &cobra.Command{
|
||||
Use: "alert-provider [name]",
|
||||
Short: "Reconcile a Provider",
|
||||
Long: `The reconcile alert-provider command triggers a reconciliation of a Provider resource and waits for it to finish.`,
|
||||
Example: ` # Trigger a reconciliation for an existing provider
|
||||
flux reconcile alert-provider slack`,
|
||||
ValidArgsFunction: resourceNamesCompletionFunc(notificationv1.GroupVersion.WithKind(notificationv1.ProviderKind)),
|
||||
RunE: reconcileAlertProviderCmdRun,
|
||||
}
|
||||
|
||||
func init() {
|
||||
reconcileCmd.AddCommand(reconcileAlertProviderCmd)
|
||||
}
|
||||
|
||||
func reconcileAlertProviderCmdRun(cmd *cobra.Command, args []string) error {
|
||||
if len(args) < 1 {
|
||||
return fmt.Errorf("Provider name is required")
|
||||
}
|
||||
name := args[0]
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
|
||||
defer cancel()
|
||||
|
||||
kubeClient, err := utils.KubeClient(kubeconfigArgs, kubeclientOptions)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
namespacedName := types.NamespacedName{
|
||||
Namespace: *kubeconfigArgs.Namespace,
|
||||
Name: name,
|
||||
}
|
||||
|
||||
logger.Actionf("annotating Provider %s in %s namespace", name, *kubeconfigArgs.Namespace)
|
||||
var alertProvider notificationv1.Provider
|
||||
err = kubeClient.Get(ctx, namespacedName, &alertProvider)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if alertProvider.Annotations == nil {
|
||||
alertProvider.Annotations = map[string]string{
|
||||
meta.ReconcileRequestAnnotation: time.Now().Format(time.RFC3339Nano),
|
||||
}
|
||||
} else {
|
||||
alertProvider.Annotations[meta.ReconcileRequestAnnotation] = time.Now().Format(time.RFC3339Nano)
|
||||
}
|
||||
if err := kubeClient.Update(ctx, &alertProvider); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Successf("Provider annotated")
|
||||
|
||||
logger.Waitingf("waiting for reconciliation")
|
||||
if err := wait.PollUntilContextTimeout(ctx, rootArgs.pollInterval, rootArgs.timeout, true,
|
||||
isAlertProviderReady(kubeClient, namespacedName, &alertProvider)); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Successf("Provider reconciliation completed")
|
||||
return nil
|
||||
}
|
||||
@@ -81,7 +81,3 @@ func (obj helmReleaseAdapter) getSource() (reconcileSource, types.NamespacedName
|
||||
Namespace: ns,
|
||||
}
|
||||
}
|
||||
|
||||
func (obj helmReleaseAdapter) isStatic() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -48,7 +48,3 @@ func (obj imageRepositoryAdapter) lastHandledReconcileRequest() string {
|
||||
func (obj imageRepositoryAdapter) successMessage() string {
|
||||
return fmt.Sprintf("scan fetched %d tags", obj.Status.LastScanResult.TagCount)
|
||||
}
|
||||
|
||||
func (obj imageRepositoryAdapter) isStatic() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -56,7 +56,3 @@ func (obj imageUpdateAutomationAdapter) successMessage() string {
|
||||
}
|
||||
return "automation not yet run"
|
||||
}
|
||||
|
||||
func (obj imageUpdateAutomationAdapter) isStatic() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -88,7 +88,3 @@ func (obj kustomizationAdapter) getSource() (reconcileSource, types.NamespacedNa
|
||||
Namespace: obj.Spec.SourceRef.Namespace,
|
||||
}
|
||||
}
|
||||
|
||||
func (obj kustomizationAdapter) isStatic() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -17,9 +17,18 @@ limitations under the License.
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
|
||||
notificationv1 "github.com/fluxcd/notification-controller/api/v1"
|
||||
"github.com/fluxcd/pkg/apis/meta"
|
||||
|
||||
"github.com/fluxcd/flux2/v2/internal/utils"
|
||||
)
|
||||
|
||||
var reconcileReceiverCmd = &cobra.Command{
|
||||
@@ -29,20 +38,62 @@ var reconcileReceiverCmd = &cobra.Command{
|
||||
Example: ` # Trigger a reconciliation for an existing receiver
|
||||
flux reconcile receiver main`,
|
||||
ValidArgsFunction: resourceNamesCompletionFunc(notificationv1.GroupVersion.WithKind(notificationv1.ReceiverKind)),
|
||||
RunE: reconcileCommand{
|
||||
apiType: receiverType,
|
||||
object: receiverAdapter{¬ificationv1.Receiver{}},
|
||||
}.run,
|
||||
RunE: reconcileReceiverCmdRun,
|
||||
}
|
||||
|
||||
func init() {
|
||||
reconcileCmd.AddCommand(reconcileReceiverCmd)
|
||||
}
|
||||
|
||||
func (obj receiverAdapter) lastHandledReconcileRequest() string {
|
||||
return obj.Status.GetLastHandledReconcileRequest()
|
||||
}
|
||||
func reconcileReceiverCmdRun(cmd *cobra.Command, args []string) error {
|
||||
if len(args) < 1 {
|
||||
return fmt.Errorf("receiver name is required")
|
||||
}
|
||||
name := args[0]
|
||||
|
||||
func (obj receiverAdapter) isStatic() bool {
|
||||
return false
|
||||
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
|
||||
defer cancel()
|
||||
|
||||
kubeClient, err := utils.KubeClient(kubeconfigArgs, kubeclientOptions)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
namespacedName := types.NamespacedName{
|
||||
Namespace: *kubeconfigArgs.Namespace,
|
||||
Name: name,
|
||||
}
|
||||
|
||||
var receiver notificationv1.Receiver
|
||||
err = kubeClient.Get(ctx, namespacedName, &receiver)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if receiver.Spec.Suspend {
|
||||
return fmt.Errorf("resource is suspended")
|
||||
}
|
||||
|
||||
logger.Actionf("annotating Receiver %s in %s namespace", name, *kubeconfigArgs.Namespace)
|
||||
if receiver.Annotations == nil {
|
||||
receiver.Annotations = map[string]string{
|
||||
meta.ReconcileRequestAnnotation: time.Now().Format(time.RFC3339Nano),
|
||||
}
|
||||
} else {
|
||||
receiver.Annotations[meta.ReconcileRequestAnnotation] = time.Now().Format(time.RFC3339Nano)
|
||||
}
|
||||
if err := kubeClient.Update(ctx, &receiver); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Successf("Receiver annotated")
|
||||
|
||||
logger.Waitingf("waiting for Receiver reconciliation")
|
||||
if err := wait.PollUntilContextTimeout(ctx, rootArgs.pollInterval, rootArgs.timeout, true,
|
||||
isReceiverReady(kubeClient, namespacedName, &receiver)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logger.Successf("Receiver reconciliation completed")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -48,7 +48,3 @@ func (obj bucketAdapter) lastHandledReconcileRequest() string {
|
||||
func (obj bucketAdapter) successMessage() string {
|
||||
return fmt.Sprintf("fetched revision %s", obj.Status.Artifact.Revision)
|
||||
}
|
||||
|
||||
func (obj bucketAdapter) isStatic() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -84,7 +84,3 @@ func (obj helmChartAdapter) getSource() (reconcileSource, types.NamespacedName)
|
||||
Namespace: obj.Namespace,
|
||||
}
|
||||
}
|
||||
|
||||
func (obj helmChartAdapter) isStatic() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -48,7 +48,3 @@ func (obj gitRepositoryAdapter) lastHandledReconcileRequest() string {
|
||||
func (obj gitRepositoryAdapter) successMessage() string {
|
||||
return fmt.Sprintf("fetched revision %s", obj.Status.Artifact.Revision)
|
||||
}
|
||||
|
||||
func (obj gitRepositoryAdapter) isStatic() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -60,7 +60,3 @@ func (obj helmRepositoryAdapter) successMessage() string {
|
||||
}
|
||||
return fmt.Sprintf("fetched revision %s", obj.Status.Artifact.Revision)
|
||||
}
|
||||
|
||||
func (obj helmRepositoryAdapter) isStatic() bool {
|
||||
return obj.Spec.Type == sourcev1.HelmRepositoryTypeOCI
|
||||
}
|
||||
|
||||
@@ -48,7 +48,3 @@ func (obj ociRepositoryAdapter) lastHandledReconcileRequest() string {
|
||||
func (obj ociRepositoryAdapter) successMessage() string {
|
||||
return fmt.Sprintf("fetched revision %s", obj.Status.Artifact.Revision)
|
||||
}
|
||||
|
||||
func (obj ociRepositoryAdapter) isStatic() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -56,7 +56,6 @@ type resumable interface {
|
||||
copyable
|
||||
statusable
|
||||
setUnsuspended()
|
||||
isStatic() bool
|
||||
successMessage() string
|
||||
}
|
||||
|
||||
@@ -213,12 +212,8 @@ func (resume resumeCommand) reconcile(ctx context.Context, res resumable) reconc
|
||||
|
||||
logger.Waitingf("waiting for %s reconciliation", resume.kind)
|
||||
|
||||
readyConditionFunc := isObjectReadyConditionFunc(resume.client, namespacedName, res.asClientObject())
|
||||
if res.isStatic() {
|
||||
readyConditionFunc = isStaticObjectReadyConditionFunc(resume.client, namespacedName, res.asClientObject())
|
||||
}
|
||||
|
||||
if err := wait.PollUntilContextTimeout(ctx, rootArgs.pollInterval, rootArgs.timeout, true, readyConditionFunc); err != nil {
|
||||
if err := wait.PollUntilContextTimeout(ctx, rootArgs.pollInterval, rootArgs.timeout, true,
|
||||
isReady(resume.client, namespacedName, res)); err != nil {
|
||||
return reconcileResponse{
|
||||
resumable: res,
|
||||
err: err,
|
||||
|
||||
@@ -19,7 +19,7 @@ package main
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
notificationv1 "github.com/fluxcd/notification-controller/api/v1beta3"
|
||||
notificationv1 "github.com/fluxcd/notification-controller/api/v1beta2"
|
||||
)
|
||||
|
||||
var resumeAlertCmd = &cobra.Command{
|
||||
@@ -44,7 +44,7 @@ func init() {
|
||||
}
|
||||
|
||||
func (obj alertAdapter) getObservedGeneration() int64 {
|
||||
return 0
|
||||
return obj.Alert.Status.ObservedGeneration
|
||||
}
|
||||
|
||||
func (obj alertAdapter) setUnsuspended() {
|
||||
@@ -55,10 +55,6 @@ func (obj alertAdapter) successMessage() string {
|
||||
return "Alert reconciliation completed"
|
||||
}
|
||||
|
||||
func (a alertAdapter) isStatic() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (a alertListAdapter) resumeItem(i int) resumable {
|
||||
return &alertAdapter{&a.AlertList.Items[i]}
|
||||
}
|
||||
|
||||
@@ -1,64 +0,0 @@
|
||||
/*
|
||||
Copyright 2023 The Flux authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
notificationv1 "github.com/fluxcd/notification-controller/api/v1beta3"
|
||||
)
|
||||
|
||||
var resumeAlertProviderCmd = &cobra.Command{
|
||||
Use: "alert-provider [name]",
|
||||
Short: "Resume a suspended Provider",
|
||||
Long: `The resume command marks a previously suspended Provider resource for reconciliation and waits for it to
|
||||
finish the apply.`,
|
||||
Example: ` # Resume reconciliation for an existing Provider
|
||||
flux resume alert-provider main
|
||||
|
||||
# Resume reconciliation for multiple Providers
|
||||
flux resume alert-provider main-1 main-2`,
|
||||
ValidArgsFunction: resourceNamesCompletionFunc(notificationv1.GroupVersion.WithKind(notificationv1.ProviderKind)),
|
||||
RunE: resumeCommand{
|
||||
apiType: alertProviderType,
|
||||
list: &alertProviderListAdapter{¬ificationv1.ProviderList{}},
|
||||
}.run,
|
||||
}
|
||||
|
||||
func init() {
|
||||
resumeCmd.AddCommand(resumeAlertProviderCmd)
|
||||
}
|
||||
|
||||
func (obj alertProviderAdapter) getObservedGeneration() int64 {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (obj alertProviderAdapter) setUnsuspended() {
|
||||
obj.Provider.Spec.Suspend = false
|
||||
}
|
||||
|
||||
func (obj alertProviderAdapter) successMessage() string {
|
||||
return "Provider reconciliation completed"
|
||||
}
|
||||
|
||||
func (a alertProviderAdapter) isStatic() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (a alertProviderListAdapter) resumeItem(i int) resumable {
|
||||
return &alertProviderAdapter{&a.ProviderList.Items[i]}
|
||||
}
|
||||
@@ -32,7 +32,7 @@ import (
|
||||
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1beta2"
|
||||
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1"
|
||||
notificationv1 "github.com/fluxcd/notification-controller/api/v1"
|
||||
notificationv1b3 "github.com/fluxcd/notification-controller/api/v1beta3"
|
||||
notificationv1b2 "github.com/fluxcd/notification-controller/api/v1beta2"
|
||||
sourcev1 "github.com/fluxcd/source-controller/api/v1"
|
||||
sourcev1b2 "github.com/fluxcd/source-controller/api/v1beta2"
|
||||
|
||||
@@ -111,14 +111,14 @@ func runStatsCmd(cmd *cobra.Command, args []string) error {
|
||||
Group: helmv2.GroupVersion.Group,
|
||||
},
|
||||
{
|
||||
Kind: notificationv1b3.AlertKind,
|
||||
Version: notificationv1b3.GroupVersion.Version,
|
||||
Group: notificationv1b3.GroupVersion.Group,
|
||||
Kind: notificationv1b2.AlertKind,
|
||||
Version: notificationv1b2.GroupVersion.Version,
|
||||
Group: notificationv1b2.GroupVersion.Group,
|
||||
},
|
||||
{
|
||||
Kind: notificationv1b3.ProviderKind,
|
||||
Version: notificationv1b3.GroupVersion.Version,
|
||||
Group: notificationv1b3.GroupVersion.Group,
|
||||
Kind: notificationv1b2.ProviderKind,
|
||||
Version: notificationv1b2.GroupVersion.Version,
|
||||
Group: notificationv1b2.GroupVersion.Group,
|
||||
},
|
||||
{
|
||||
Kind: notificationv1.ReceiverKind,
|
||||
|
||||
@@ -17,9 +17,18 @@ limitations under the License.
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/fluxcd/cli-utils/pkg/object"
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
apimeta "k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
"github.com/fluxcd/cli-utils/pkg/object"
|
||||
"github.com/fluxcd/pkg/apis/meta"
|
||||
)
|
||||
|
||||
// statusable is used to see if a resource is considered ready in the usual way
|
||||
@@ -36,6 +45,42 @@ type oldConditions interface {
|
||||
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(kubeClient client.Client, namespacedName types.NamespacedName, object statusable) wait.ConditionWithContextFunc {
|
||||
return func(ctx context.Context) (bool, error) {
|
||||
err := kubeClient.Get(ctx, namespacedName, object.asClientObject())
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
// Confirm the state we are observing is for the current generation
|
||||
if object.GetGeneration() != object.getObservedGeneration() {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
if c := apimeta.FindStatusCondition(statusableConditions(object), 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 buildComponentObjectRefs(components ...string) ([]object.ObjMetadata, error) {
|
||||
var objRefs []object.ObjMetadata
|
||||
for _, deployment := range components {
|
||||
|
||||
@@ -19,7 +19,7 @@ package main
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
notificationv1 "github.com/fluxcd/notification-controller/api/v1beta3"
|
||||
notificationv1 "github.com/fluxcd/notification-controller/api/v1beta2"
|
||||
)
|
||||
|
||||
var suspendAlertCmd = &cobra.Command{
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
/*
|
||||
Copyright 2023 The Flux authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
notificationv1 "github.com/fluxcd/notification-controller/api/v1beta3"
|
||||
)
|
||||
|
||||
var suspendAlertProviderCmd = &cobra.Command{
|
||||
Use: "alert-provider [name]",
|
||||
Short: "Suspend reconciliation of Provider",
|
||||
Long: `The suspend command disables the reconciliation of a Provider resource.`,
|
||||
Example: ` # Suspend reconciliation for an existing Provider
|
||||
flux suspend alert-provider main
|
||||
|
||||
# Suspend reconciliation for multiple Providers
|
||||
flux suspend alert-providers main-1 main-2`,
|
||||
ValidArgsFunction: resourceNamesCompletionFunc(notificationv1.GroupVersion.WithKind(notificationv1.ProviderKind)),
|
||||
RunE: suspendCommand{
|
||||
apiType: alertProviderType,
|
||||
object: &alertProviderAdapter{¬ificationv1.Provider{}},
|
||||
list: &alertProviderListAdapter{¬ificationv1.ProviderList{}},
|
||||
}.run,
|
||||
}
|
||||
|
||||
func init() {
|
||||
suspendCmd.AddCommand(suspendAlertProviderCmd)
|
||||
}
|
||||
|
||||
func (obj alertProviderAdapter) isSuspended() bool {
|
||||
return obj.Provider.Spec.Suspend
|
||||
}
|
||||
|
||||
func (obj alertProviderAdapter) setSuspended() {
|
||||
obj.Provider.Spec.Suspend = true
|
||||
}
|
||||
|
||||
func (a alertProviderListAdapter) item(i int) suspendable {
|
||||
return &alertProviderAdapter{&a.ProviderList.Items[i]}
|
||||
}
|
||||
2
cmd/flux/testdata/export/alert.yaml
vendored
2
cmd/flux/testdata/export/alert.yaml
vendored
@@ -1,5 +1,5 @@
|
||||
---
|
||||
apiVersion: notification.toolkit.fluxcd.io/v1beta3
|
||||
apiVersion: notification.toolkit.fluxcd.io/v1beta2
|
||||
kind: Alert
|
||||
metadata:
|
||||
name: flux-system
|
||||
|
||||
4
cmd/flux/testdata/export/objects.yaml
vendored
4
cmd/flux/testdata/export/objects.yaml
vendored
@@ -4,7 +4,7 @@ kind: Namespace
|
||||
metadata:
|
||||
name: {{ .fluxns }}
|
||||
---
|
||||
apiVersion: notification.toolkit.fluxcd.io/v1beta3
|
||||
apiVersion: notification.toolkit.fluxcd.io/v1beta2
|
||||
kind: Provider
|
||||
metadata:
|
||||
name: slack
|
||||
@@ -14,7 +14,7 @@ spec:
|
||||
channel: 'A channel with spacess'
|
||||
address: https://hooks.slack.com/services/mock
|
||||
---
|
||||
apiVersion: notification.toolkit.fluxcd.io/v1beta3
|
||||
apiVersion: notification.toolkit.fluxcd.io/v1beta2
|
||||
kind: Alert
|
||||
metadata:
|
||||
name: flux-system
|
||||
|
||||
2
cmd/flux/testdata/export/provider.yaml
vendored
2
cmd/flux/testdata/export/provider.yaml
vendored
@@ -1,5 +1,5 @@
|
||||
---
|
||||
apiVersion: notification.toolkit.fluxcd.io/v1beta3
|
||||
apiVersion: notification.toolkit.fluxcd.io/v1beta2
|
||||
kind: Provider
|
||||
metadata:
|
||||
name: slack
|
||||
|
||||
@@ -25,9 +25,8 @@ import (
|
||||
"github.com/google/go-containerregistry/pkg/name"
|
||||
"github.com/spf13/cobra"
|
||||
v1 "k8s.io/api/apps/v1"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/yaml/goyaml.v2"
|
||||
"sigs.k8s.io/yaml"
|
||||
|
||||
"github.com/fluxcd/flux2/v2/internal/utils"
|
||||
"github.com/fluxcd/flux2/v2/pkg/manifestgen"
|
||||
@@ -56,12 +55,6 @@ type versionFlags struct {
|
||||
|
||||
var versionArgs versionFlags
|
||||
|
||||
type versionInfo struct {
|
||||
Flux string `yaml:"flux"`
|
||||
Distribution string `yaml:"distribution,omitempty"`
|
||||
Controller map[string]string `yaml:"controller,inline"`
|
||||
}
|
||||
|
||||
func init() {
|
||||
versionCmd.Flags().BoolVar(&versionArgs.client, "client", false,
|
||||
"print only client version")
|
||||
@@ -78,12 +71,8 @@ func versionCmdRun(cmd *cobra.Command, args []string) error {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
|
||||
defer cancel()
|
||||
|
||||
// versionInfo struct and goyaml is used because we care about the order.
|
||||
// Without this `distribution` is printed before `flux` when the struct is marshalled.
|
||||
info := &versionInfo{
|
||||
Controller: map[string]string{},
|
||||
}
|
||||
info.Flux = rootArgs.defaults.Version
|
||||
info := map[string]string{}
|
||||
info["flux"] = rootArgs.defaults.Version
|
||||
|
||||
if !versionArgs.client {
|
||||
kubeClient, err := utils.KubeClient(kubeconfigArgs, kubeclientOptions)
|
||||
@@ -91,16 +80,6 @@ func versionCmdRun(cmd *cobra.Command, args []string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
clusterInfo, err := getFluxClusterInfo(ctx, kubeClient)
|
||||
// ignoring not found errors because it means that the GitRepository CRD isn't installed but a user might
|
||||
// have other controllers(e.g notification-controller), and we want to still return information for them.
|
||||
if err != nil && !errors.IsNotFound(err) {
|
||||
return err
|
||||
}
|
||||
if clusterInfo.distribution() != "" {
|
||||
info.Distribution = clusterInfo.distribution()
|
||||
}
|
||||
|
||||
selector := client.MatchingLabels{manifestgen.PartOfLabelKey: manifestgen.PartOfLabelValue}
|
||||
var list v1.DeploymentList
|
||||
if err := kubeClient.List(ctx, &list, client.InNamespace(*kubeconfigArgs.Namespace), selector); err != nil {
|
||||
@@ -117,7 +96,7 @@ func versionCmdRun(cmd *cobra.Command, args []string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
info.Controller[name] = tag
|
||||
info[name] = tag
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -126,7 +105,7 @@ func versionCmdRun(cmd *cobra.Command, args []string) error {
|
||||
var err error
|
||||
|
||||
if versionArgs.output == "json" {
|
||||
marshalled, err = info.toJSON()
|
||||
marshalled, err = json.MarshalIndent(&info, "", " ")
|
||||
marshalled = append(marshalled, "\n"...)
|
||||
} else {
|
||||
marshalled, err = yaml.Marshal(&info)
|
||||
@@ -140,20 +119,6 @@ func versionCmdRun(cmd *cobra.Command, args []string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (info versionInfo) toJSON() ([]byte, error) {
|
||||
mapInfo := map[string]string{
|
||||
"flux": info.Flux,
|
||||
}
|
||||
|
||||
if info.Distribution != "" {
|
||||
mapInfo["distribution"] = info.Distribution
|
||||
}
|
||||
for k, v := range info.Controller {
|
||||
mapInfo[k] = v
|
||||
}
|
||||
return json.MarshalIndent(&mapInfo, "", " ")
|
||||
}
|
||||
|
||||
func splitImageStr(image string) (string, string, error) {
|
||||
ref, err := name.ParseReference(image)
|
||||
if err != nil {
|
||||
|
||||
34
go.mod
34
go.mod
@@ -14,9 +14,9 @@ require (
|
||||
github.com/fluxcd/go-git-providers v0.19.1
|
||||
github.com/fluxcd/helm-controller/api v0.36.2
|
||||
github.com/fluxcd/image-automation-controller/api v0.36.1
|
||||
github.com/fluxcd/image-reflector-controller/api v0.31.0
|
||||
github.com/fluxcd/image-reflector-controller/api v0.30.0
|
||||
github.com/fluxcd/kustomize-controller/api v1.1.1
|
||||
github.com/fluxcd/notification-controller/api v1.2.1
|
||||
github.com/fluxcd/notification-controller/api v1.1.0
|
||||
github.com/fluxcd/pkg/apis/event v0.6.0
|
||||
github.com/fluxcd/pkg/apis/meta v1.2.0
|
||||
github.com/fluxcd/pkg/git v0.15.0
|
||||
@@ -26,10 +26,10 @@ require (
|
||||
github.com/fluxcd/pkg/runtime v0.43.0
|
||||
github.com/fluxcd/pkg/sourceignore v0.3.5
|
||||
github.com/fluxcd/pkg/ssa v0.34.0
|
||||
github.com/fluxcd/pkg/ssh v0.10.0
|
||||
github.com/fluxcd/pkg/ssh v0.9.0
|
||||
github.com/fluxcd/pkg/tar v0.4.0
|
||||
github.com/fluxcd/pkg/version v0.2.2
|
||||
github.com/fluxcd/source-controller/api v1.2.1
|
||||
github.com/fluxcd/source-controller/api v1.1.2
|
||||
github.com/go-git/go-git/v5 v5.10.0
|
||||
github.com/go-logr/logr v1.3.0
|
||||
github.com/gonvenience/bunt v1.3.5
|
||||
@@ -47,8 +47,8 @@ require (
|
||||
github.com/spf13/cobra v1.8.0
|
||||
github.com/spf13/pflag v1.0.5
|
||||
github.com/theckman/yacspin v0.13.12
|
||||
golang.org/x/crypto v0.16.0
|
||||
golang.org/x/term v0.15.0
|
||||
golang.org/x/crypto v0.15.0
|
||||
golang.org/x/term v0.14.0
|
||||
golang.org/x/text v0.14.0
|
||||
k8s.io/api v0.28.4
|
||||
k8s.io/apiextensions-apiserver v0.28.4
|
||||
@@ -119,9 +119,9 @@ require (
|
||||
github.com/go-fed/httpsig v1.1.0 // indirect
|
||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
|
||||
github.com/go-git/go-billy/v5 v5.5.0 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.20.0 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.19.6 // indirect
|
||||
github.com/go-openapi/jsonreference v0.20.2 // indirect
|
||||
github.com/go-openapi/swag v0.22.4 // indirect
|
||||
github.com/go-openapi/swag v0.22.3 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang-jwt/jwt/v5 v5.0.0 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
@@ -144,7 +144,7 @@ require (
|
||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||
github.com/hashicorp/go-retryablehttp v0.7.5 // indirect
|
||||
github.com/hashicorp/go-version v1.6.0 // indirect
|
||||
github.com/hashicorp/go-version v1.5.0 // indirect
|
||||
github.com/hashicorp/golang-lru/arc/v2 v2.0.5 // indirect
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.5 // indirect
|
||||
github.com/imdario/mergo v0.3.15 // indirect
|
||||
@@ -197,14 +197,14 @@ require (
|
||||
go.starlark.net v0.0.0-20230525235612-a134d8f9ddca // indirect
|
||||
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e // indirect
|
||||
golang.org/x/mod v0.14.0 // indirect
|
||||
golang.org/x/net v0.19.0 // indirect
|
||||
golang.org/x/oauth2 v0.15.0 // indirect
|
||||
golang.org/x/net v0.18.0 // indirect
|
||||
golang.org/x/oauth2 v0.14.0 // indirect
|
||||
golang.org/x/sync v0.5.0 // indirect
|
||||
golang.org/x/sys v0.15.0 // indirect
|
||||
golang.org/x/time v0.5.0 // indirect
|
||||
golang.org/x/tools v0.16.0 // indirect
|
||||
golang.org/x/sys v0.14.0 // indirect
|
||||
golang.org/x/time v0.4.0 // indirect
|
||||
golang.org/x/tools v0.15.0 // indirect
|
||||
gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect
|
||||
google.golang.org/appengine v1.6.8 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/protobuf v1.31.0 // indirect
|
||||
gopkg.in/evanphx/json-patch.v5 v5.6.0 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
@@ -212,9 +212,9 @@ require (
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
k8s.io/component-base v0.28.4 // indirect
|
||||
k8s.io/klog/v2 v2.110.1 // indirect
|
||||
k8s.io/klog/v2 v2.100.1 // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20231113174909-778a5567bc1e // indirect
|
||||
k8s.io/utils v0.0.0-20231127182322-b307cd553661 // indirect
|
||||
k8s.io/utils v0.0.0-20230726121419-3b25d923346b // indirect
|
||||
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect
|
||||
)
|
||||
|
||||
70
go.sum
70
go.sum
@@ -141,12 +141,12 @@ github.com/fluxcd/helm-controller/api v0.36.2 h1:9JaTc91yocG1oQkM/GMfpZ/nGPpliRj
|
||||
github.com/fluxcd/helm-controller/api v0.36.2/go.mod h1:zkcRy3PxG0NoxSY5SjiSA5tWOGa6spIbWsChQY8FXqM=
|
||||
github.com/fluxcd/image-automation-controller/api v0.36.1 h1:Knd4SSm/bJ0iqvYcQq87uDaT/mW9poM1jOvHpJ/4tzk=
|
||||
github.com/fluxcd/image-automation-controller/api v0.36.1/go.mod h1:IsjdBtgm71KHRGDTZZZiGYdWGoJ5VjenE9F4ueADM/o=
|
||||
github.com/fluxcd/image-reflector-controller/api v0.31.0 h1:9t5zj7ufo9/d57gpcZsD6YAIxFz0vtLH4jXCj379srE=
|
||||
github.com/fluxcd/image-reflector-controller/api v0.31.0/go.mod h1:/EcjOa/EYi8sSBHcGrBkLjMjNNfC7xXMxqG9phBORCo=
|
||||
github.com/fluxcd/image-reflector-controller/api v0.30.0 h1:DiWj+4tcbnaSqZs1Pfkyt3uSy47wg3dsNMgbFE50pYc=
|
||||
github.com/fluxcd/image-reflector-controller/api v0.30.0/go.mod h1:hv57KwIzoPyy7Vu4PFcIf21eu0N3p/HbijygcuNgf8c=
|
||||
github.com/fluxcd/kustomize-controller/api v1.1.1 h1:pQcAzvBC3cFGOCgk0zrcsO1Kjtal1tvd6rHXkyp2R78=
|
||||
github.com/fluxcd/kustomize-controller/api v1.1.1/go.mod h1:FHJTX6c0+CznUNGMol5+Uc4lQsYRxWgpmIRK/xDCghA=
|
||||
github.com/fluxcd/notification-controller/api v1.2.1 h1:yPQZ7ppYvazxl/Vsespbx9VlVyopH7p8pKGzZTNxI0c=
|
||||
github.com/fluxcd/notification-controller/api v1.2.1/go.mod h1:1sWTpAXkga5zkXOgFoR+NIJgHNclBcfAHUJ/rMAjnYY=
|
||||
github.com/fluxcd/notification-controller/api v1.1.0 h1:qx5t5DmArfPLxG2bsYZXIqDXLnijUddlHeRfciALwQw=
|
||||
github.com/fluxcd/notification-controller/api v1.1.0/go.mod h1:6MqWVQeI5yrYR7zp0GFqsfXitNPGJrnfOWxO2w3jylg=
|
||||
github.com/fluxcd/pkg/apis/acl v0.1.0 h1:EoAl377hDQYL3WqanWCdifauXqXbMyFuK82NnX6pH4Q=
|
||||
github.com/fluxcd/pkg/apis/acl v0.1.0/go.mod h1:zfEZzz169Oap034EsDhmCAGgnWlcWmIObZjYMusoXS8=
|
||||
github.com/fluxcd/pkg/apis/event v0.6.0 h1:AUaeee1CGWb65BLqVximHXG8Gcu6vWuYONIq6tVpjgo=
|
||||
@@ -170,14 +170,14 @@ github.com/fluxcd/pkg/sourceignore v0.3.5 h1:omcHTH5X5tlPr9w1b9T7WuJTOP+o/KdVdar
|
||||
github.com/fluxcd/pkg/sourceignore v0.3.5/go.mod h1:6Xz3jErz8RsidsdrjUBBUGKes24rbdp/F38MnTGibEw=
|
||||
github.com/fluxcd/pkg/ssa v0.34.0 h1:hpMo0D7G3faieRYH39e9YD8Jl+aC2hTgUep8ojG5+LE=
|
||||
github.com/fluxcd/pkg/ssa v0.34.0/go.mod h1:rhVh0EtYVUOznKXlz6E7JOSgdc8xWbIwA4L5HVtJRLA=
|
||||
github.com/fluxcd/pkg/ssh v0.10.0 h1:JFz0u/CPEf3hXvmrEvUvXsc70eKh8xphqjXxZuSby9g=
|
||||
github.com/fluxcd/pkg/ssh v0.10.0/go.mod h1:1lFTj3MhU9xQuaJ5PJJoh/FyRYzK54ll9NY/s2KqOZM=
|
||||
github.com/fluxcd/pkg/ssh v0.9.0 h1:egRvg4AKarObFKXsBDZ5oBZ5PCjmQ4Q6hX+6GmrdbH0=
|
||||
github.com/fluxcd/pkg/ssh v0.9.0/go.mod h1:3KKbfcFn4l+HqYdHKqcu2LO8RvFv0Kh6tYRSUtONC/8=
|
||||
github.com/fluxcd/pkg/tar v0.4.0 h1:SuXpfXBIcSJ5R/yqQi2CBxBmV/i/LH0agqNAh2PWBZg=
|
||||
github.com/fluxcd/pkg/tar v0.4.0/go.mod h1:SyJBaQvuv2VA/rv4d1OHhCV6R8+9QKc9np193EzNHBc=
|
||||
github.com/fluxcd/pkg/version v0.2.2 h1:ZpVXECeLA5hIQMft11iLp6gN3cKcz6UNuVTQPw/bRdI=
|
||||
github.com/fluxcd/pkg/version v0.2.2/go.mod h1:NGnh/no8S6PyfCDxRFrPY3T5BUnqP48MxfxNRU0z8C0=
|
||||
github.com/fluxcd/source-controller/api v1.2.1 h1:zWRfwMB/BkV0A/duZQwHEcrE/abWJQt7DUgYTzn4IzM=
|
||||
github.com/fluxcd/source-controller/api v1.2.1/go.mod h1:n+PMCJXl/AYCjWHn5N/MUuoIFKfDg4kCDviFIa7fDvI=
|
||||
github.com/fluxcd/source-controller/api v1.1.2 h1:FfKDKVWnopo+Q2pOAxgHEjrtr4MP41L8aapR4mqBhBk=
|
||||
github.com/fluxcd/source-controller/api v1.1.2/go.mod h1:ZLkaUd1KQIjtLPCvO63Ni5zpnSTVBAkeRgFBzMItbDQ=
|
||||
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
|
||||
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
|
||||
github.com/gliderlabs/ssh v0.3.5 h1:OcaySEmAQJgyYcArR+gGGTHCyE7nvhEMTlYY+Dp8CpY=
|
||||
@@ -195,17 +195,16 @@ github.com/go-git/go-git/v5 v5.10.0/go.mod h1:1FOZ/pQnqw24ghP2n7cunVl0ON55BsjPYv
|
||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY=
|
||||
github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/zapr v1.2.4 h1:QHVo+6stLbfJmYGkQ7uGHUCu5hnAFAj6mDe6Ea0SeOo=
|
||||
github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE=
|
||||
github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=
|
||||
github.com/go-openapi/jsonpointer v0.20.0 h1:ESKJdU9ASRfaPNOPRx12IUyA1vn3R9GiE3KYD14BXdQ=
|
||||
github.com/go-openapi/jsonpointer v0.20.0/go.mod h1:6PGzBjjIIumbLYysB73Klnms1mwnU4G3YHOECG3CedA=
|
||||
github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE=
|
||||
github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k=
|
||||
github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g=
|
||||
github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
|
||||
github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogBU=
|
||||
github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
|
||||
github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA=
|
||||
@@ -228,7 +227,6 @@ github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:W
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
|
||||
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/gomodule/redigo v1.8.2 h1:H5XSIre1MB5NbPYFp+i1NBbb5qN1W8Y8YAQoAYbkm8k=
|
||||
@@ -293,9 +291,8 @@ github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+l
|
||||
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
|
||||
github.com/hashicorp/go-retryablehttp v0.7.5 h1:bJj+Pj19UZMIweq/iie+1u5YCdGrnxCT9yvm0e+Nd5M=
|
||||
github.com/hashicorp/go-retryablehttp v0.7.5/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8=
|
||||
github.com/hashicorp/go-version v1.5.0 h1:O293SZ2Eg+AAYijkVK3jR786Am1bhDEh2GHT0tIVE5E=
|
||||
github.com/hashicorp/go-version v1.5.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||
github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek=
|
||||
github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||
github.com/hashicorp/golang-lru/arc/v2 v2.0.5 h1:l2zaLDubNhW4XO3LnliVj0GXO3+/CGNJAg1dcN2Fpfw=
|
||||
github.com/hashicorp/golang-lru/arc/v2 v2.0.5/go.mod h1:ny6zBSQZi2JxIeYcv7kt2sH2PXJtirBN7RDhRpxPkxU=
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.5 h1:wW7h1TG88eUIJ2i69gaE3uNVtEPIagzhGvHgwfx2Vm4=
|
||||
@@ -497,8 +494,8 @@ golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
|
||||
golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
|
||||
golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY=
|
||||
golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
|
||||
golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA=
|
||||
golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e h1:+WEEuIdZHnUeJJmEUjyYC2gfUMj69yZXw17EnHg/otA=
|
||||
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e/go.mod h1:Kr81I6Kryrl9sr8s2FK3vxD90NdsKWRuOIl2O4CvYbA=
|
||||
@@ -517,6 +514,7 @@ golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73r
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
@@ -527,11 +525,11 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug
|
||||
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c=
|
||||
golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U=
|
||||
golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg=
|
||||
golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.15.0 h1:s8pnnxNVzjWyrvYdFUQq5llS1PX2zhPXmccZv99h7uQ=
|
||||
golang.org/x/oauth2 v0.15.0/go.mod h1:q48ptWNTY5XWf+JNten23lcvHpLJ0ZSxF5ttTHKVCAM=
|
||||
golang.org/x/oauth2 v0.14.0 h1:P0Vrf/2538nmC0H+pEQ3MNFRRnVR7RlqyVw+bvm26z0=
|
||||
golang.org/x/oauth2 v0.14.0/go.mod h1:lAtNWgaWfL4cm7j2OV8TxGi9Qb7ECORx8DktCY74OwM=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@@ -571,28 +569,28 @@ golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
|
||||
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q=
|
||||
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||
golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4=
|
||||
golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=
|
||||
golang.org/x/term v0.14.0 h1:LGK9IlZ8T9jvdy6cTdfKUCltatMFOehAQo9SRC46UQ8=
|
||||
golang.org/x/term v0.14.0/go.mod h1:TySc+nGkYR6qt8km8wUhuFRTVSMIX3XPR58y2lC8vww=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
||||
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
|
||||
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
golang.org/x/time v0.4.0 h1:Z81tqI5ddIoXDPvVQ7/7CC9TnLM7ubaFG2qXYd5BbYY=
|
||||
golang.org/x/time v0.4.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
@@ -603,8 +601,8 @@ golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roY
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/tools v0.16.0 h1:GO788SKMRunPIBCXiQyo2AaexLstOrVhuAL5YwsckQM=
|
||||
golang.org/x/tools v0.16.0/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0=
|
||||
golang.org/x/tools v0.15.0 h1:zdAyfUGbYmuVokhzVmghFl2ZJh5QhcfebBgmVPFYA+8=
|
||||
golang.org/x/tools v0.15.0/go.mod h1:hpksKq4dtpQWS1uQ61JkdqWM3LscIS6Slf+VVkm+wQk=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
@@ -613,8 +611,8 @@ gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw
|
||||
gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM=
|
||||
google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds=
|
||||
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
|
||||
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||
@@ -668,14 +666,14 @@ k8s.io/client-go v0.28.4 h1:Np5ocjlZcTrkyRJ3+T3PkXDpe4UpatQxj85+xjaD2wY=
|
||||
k8s.io/client-go v0.28.4/go.mod h1:0VDZFpgoZfelyP5Wqu0/r/TRYcLYuJ2U1KEeoaPa1N4=
|
||||
k8s.io/component-base v0.28.4 h1:c/iQLWPdUgI90O+T9TeECg8o7N3YJTiuz2sKxILYcYo=
|
||||
k8s.io/component-base v0.28.4/go.mod h1:m9hR0uvqXDybiGL2nf/3Lf0MerAfQXzkfWhUY58JUbU=
|
||||
k8s.io/klog/v2 v2.110.1 h1:U/Af64HJf7FcwMcXyKm2RPM22WZzyR7OSpYj5tg3cL0=
|
||||
k8s.io/klog/v2 v2.110.1/go.mod h1:YGtd1984u+GgbuZ7e08/yBuAfKLSO0+uR1Fhi6ExXjo=
|
||||
k8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg=
|
||||
k8s.io/klog/v2 v2.100.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
|
||||
k8s.io/kube-openapi v0.0.0-20231113174909-778a5567bc1e h1:snPmy96t93RredGRjKfMFt+gvxuVAncqSAyBveJtr4Q=
|
||||
k8s.io/kube-openapi v0.0.0-20231113174909-778a5567bc1e/go.mod h1:AsvuZPBlUDVuCdzJ87iajxtXuR9oktsTctW/R9wwouA=
|
||||
k8s.io/kubectl v0.28.4 h1:gWpUXW/T7aFne+rchYeHkyB8eVDl5UZce8G4X//kjUQ=
|
||||
k8s.io/kubectl v0.28.4/go.mod h1:CKOccVx3l+3MmDbkXtIUtibq93nN2hkDR99XDCn7c/c=
|
||||
k8s.io/utils v0.0.0-20231127182322-b307cd553661 h1:FepOBzJ0GXm8t0su67ln2wAZjbQ6RxQGZDnzuLcrUTI=
|
||||
k8s.io/utils v0.0.0-20231127182322-b307cd553661/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
|
||||
k8s.io/utils v0.0.0-20230726121419-3b25d923346b h1:sgn3ZU783SCgtaSJjpcVVlRqd6GSnlTLKgpAAttJvpI=
|
||||
k8s.io/utils v0.0.0-20230726121419-3b25d923346b/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
|
||||
sigs.k8s.io/controller-runtime v0.16.3 h1:2TuvuokmfXvDUamSx1SuAOO3eTyye+47mJCigwG62c4=
|
||||
sigs.k8s.io/controller-runtime v0.16.3/go.mod h1:j7bialYoSn142nv9sCOJmQgDXQXxnroFU4VnX/brVJ0=
|
||||
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
|
||||
|
||||
@@ -46,7 +46,7 @@ import (
|
||||
imagereflectv1 "github.com/fluxcd/image-reflector-controller/api/v1beta2"
|
||||
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1"
|
||||
notificationv1 "github.com/fluxcd/notification-controller/api/v1"
|
||||
notificationv1b3 "github.com/fluxcd/notification-controller/api/v1beta3"
|
||||
notificationv1b2 "github.com/fluxcd/notification-controller/api/v1beta2"
|
||||
"github.com/fluxcd/pkg/apis/meta"
|
||||
runclient "github.com/fluxcd/pkg/runtime/client"
|
||||
"github.com/fluxcd/pkg/version"
|
||||
@@ -133,7 +133,7 @@ func NewScheme() *apiruntime.Scheme {
|
||||
_ = kustomizev1.AddToScheme(scheme)
|
||||
_ = helmv2.AddToScheme(scheme)
|
||||
_ = notificationv1.AddToScheme(scheme)
|
||||
_ = notificationv1b3.AddToScheme(scheme)
|
||||
_ = notificationv1b2.AddToScheme(scheme)
|
||||
_ = imagereflectv1.AddToScheme(scheme)
|
||||
_ = imageautov1.AddToScheme(scheme)
|
||||
return scheme
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
resources:
|
||||
- https://github.com/fluxcd/image-reflector-controller/releases/download/v0.31.0/image-reflector-controller.crds.yaml
|
||||
- https://github.com/fluxcd/image-reflector-controller/releases/download/v0.31.0/image-reflector-controller.deployment.yaml
|
||||
- https://github.com/fluxcd/image-reflector-controller/releases/download/v0.30.0/image-reflector-controller.crds.yaml
|
||||
- https://github.com/fluxcd/image-reflector-controller/releases/download/v0.30.0/image-reflector-controller.deployment.yaml
|
||||
- account.yaml
|
||||
transformers:
|
||||
- labels.yaml
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
resources:
|
||||
- https://github.com/fluxcd/notification-controller/releases/download/v1.2.1/notification-controller.crds.yaml
|
||||
- https://github.com/fluxcd/notification-controller/releases/download/v1.2.1/notification-controller.deployment.yaml
|
||||
- https://github.com/fluxcd/notification-controller/releases/download/v1.1.0/notification-controller.crds.yaml
|
||||
- https://github.com/fluxcd/notification-controller/releases/download/v1.1.0/notification-controller.deployment.yaml
|
||||
- account.yaml
|
||||
transformers:
|
||||
- labels.yaml
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
resources:
|
||||
- https://github.com/fluxcd/source-controller/releases/download/v1.2.1/source-controller.crds.yaml
|
||||
- https://github.com/fluxcd/source-controller/releases/download/v1.2.1/source-controller.deployment.yaml
|
||||
- https://github.com/fluxcd/source-controller/releases/download/v1.1.2/source-controller.crds.yaml
|
||||
- https://github.com/fluxcd/source-controller/releases/download/v1.1.2/source-controller.deployment.yaml
|
||||
- account.yaml
|
||||
transformers:
|
||||
- labels.yaml
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
resources:
|
||||
- https://github.com/fluxcd/source-controller/releases/download/v1.2.1/source-controller.crds.yaml
|
||||
- https://github.com/fluxcd/source-controller/releases/download/v1.1.2/source-controller.crds.yaml
|
||||
- https://github.com/fluxcd/kustomize-controller/releases/download/v1.1.1/kustomize-controller.crds.yaml
|
||||
- https://github.com/fluxcd/helm-controller/releases/download/v0.36.2/helm-controller.crds.yaml
|
||||
- https://github.com/fluxcd/notification-controller/releases/download/v1.2.1/notification-controller.crds.yaml
|
||||
- https://github.com/fluxcd/image-reflector-controller/releases/download/v0.31.0/image-reflector-controller.crds.yaml
|
||||
- https://github.com/fluxcd/notification-controller/releases/download/v1.1.0/notification-controller.crds.yaml
|
||||
- https://github.com/fluxcd/image-reflector-controller/releases/download/v0.30.0/image-reflector-controller.crds.yaml
|
||||
- https://github.com/fluxcd/image-automation-controller/releases/download/v0.36.1/image-automation-controller.crds.yaml
|
||||
|
||||
@@ -20,6 +20,7 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -27,17 +28,12 @@ import (
|
||||
apierr "k8s.io/apimachinery/pkg/api/errors"
|
||||
apimeta "k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
apierrors "k8s.io/apimachinery/pkg/util/errors"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1"
|
||||
"github.com/fluxcd/pkg/apis/meta"
|
||||
sourcev1 "github.com/fluxcd/source-controller/api/v1"
|
||||
sourcev1b2 "github.com/fluxcd/source-controller/api/v1beta2"
|
||||
sourcev1 "github.com/fluxcd/source-controller/api/v1beta2"
|
||||
|
||||
"github.com/fluxcd/flux2/v2/pkg/manifestgen/install"
|
||||
"github.com/fluxcd/flux2/v2/pkg/manifestgen/sourcesecret"
|
||||
@@ -48,11 +44,6 @@ var (
|
||||
ErrReconciledWithWarning = errors.New("reconciled with warning")
|
||||
)
|
||||
|
||||
// Reconciler reconciles and reports the health of different
|
||||
// components and kubernetes resources involved in the installation of Flux.
|
||||
//
|
||||
// It is recommended use the `ReconcilerWithSyncCheck` interface that also
|
||||
// reports the health of the GitRepository.
|
||||
type Reconciler interface {
|
||||
// ReconcileComponents reconciles the components by generating the
|
||||
// manifests with the provided values, committing them to Git and
|
||||
@@ -85,14 +76,6 @@ type RepositoryReconciler interface {
|
||||
ReconcileRepository(ctx context.Context) error
|
||||
}
|
||||
|
||||
// ReconcilerWithSyncCheck extends the Reconciler interface to also report the health of the GitReposiotry
|
||||
// that syncs Flux on the cluster
|
||||
type ReconcilerWithSyncCheck interface {
|
||||
Reconciler
|
||||
// ReportGitRepoHealth reports about the health of the GitRepository synchronizing the components.
|
||||
ReportGitRepoHealth(ctx context.Context, options sync.Options, pollInterval, timeout time.Duration) error
|
||||
}
|
||||
|
||||
type PostGenerateSecretFunc func(ctx context.Context, secret corev1.Secret, options sourcesecret.Options) error
|
||||
|
||||
func Run(ctx context.Context, reconciler Reconciler, manifestsBase string,
|
||||
@@ -116,22 +99,18 @@ func Run(ctx context.Context, reconciler Reconciler, manifestsBase string,
|
||||
return err
|
||||
}
|
||||
|
||||
var errs []error
|
||||
if r, ok := reconciler.(ReconcilerWithSyncCheck); ok {
|
||||
if err := r.ReportGitRepoHealth(ctx, syncOpts, pollInterval, timeout); err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
|
||||
var healthErrCount int
|
||||
if err := reconciler.ReportKustomizationHealth(ctx, syncOpts, pollInterval, timeout); err != nil {
|
||||
errs = append(errs, err)
|
||||
healthErrCount++
|
||||
}
|
||||
|
||||
if err := reconciler.ReportComponentsHealth(ctx, installOpts, timeout); err != nil {
|
||||
errs = append(errs, err)
|
||||
healthErrCount++
|
||||
}
|
||||
if len(errs) > 0 {
|
||||
err = fmt.Errorf("bootstrap failed with %d health check failure(s): %w", len(errs), apierrors.NewAggregate(errs))
|
||||
if healthErrCount > 0 {
|
||||
// Composing a "smart" error message here from the returned
|
||||
// errors does not result in any useful information for the
|
||||
// user, as both methods log the failures they run into.
|
||||
err = fmt.Errorf("bootstrap failed with %d health check failure(s)", healthErrCount)
|
||||
}
|
||||
|
||||
return err
|
||||
@@ -194,47 +173,32 @@ func kustomizationPathDiffers(ctx context.Context, kube client.Client, objKey cl
|
||||
return k.Spec.Path, nil
|
||||
}
|
||||
|
||||
type objectWithConditions interface {
|
||||
client.Object
|
||||
GetConditions() []metav1.Condition
|
||||
}
|
||||
|
||||
func objectReconciled(kube client.Client, objKey client.ObjectKey, clientObject objectWithConditions, expectRevision string) wait.ConditionWithContextFunc {
|
||||
func kustomizationReconciled(kube client.Client, objKey client.ObjectKey, kustomization *kustomizev1.Kustomization, expectRevision string) wait.ConditionWithContextFunc {
|
||||
return func(ctx context.Context) (bool, error) {
|
||||
// for some reason, TypeMeta gets unset after kube.Get so we want to store the GVK and set it after
|
||||
// ref https://github.com/kubernetes-sigs/controller-runtime/issues/1517#issuecomment-844703142
|
||||
gvk := clientObject.GetObjectKind().GroupVersionKind()
|
||||
if err := kube.Get(ctx, objKey, clientObject); err != nil {
|
||||
return false, err
|
||||
}
|
||||
clientObject.GetObjectKind().SetGroupVersionKind(gvk)
|
||||
|
||||
kind := gvk.Kind
|
||||
obj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(clientObject)
|
||||
if err != nil {
|
||||
if err := kube.Get(ctx, objKey, kustomization); err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
// Detect suspended object, as this would result in an endless wait
|
||||
if suspended, ok, _ := unstructured.NestedBool(obj, "spec", "suspend"); ok && suspended {
|
||||
return false, fmt.Errorf("%s '%s' is suspended", kind, objKey.String())
|
||||
// Detect suspended Kustomization, as this would result in an endless wait
|
||||
if kustomization.Spec.Suspend {
|
||||
return false, fmt.Errorf("Kustomization is suspended")
|
||||
}
|
||||
|
||||
// Confirm the state we are observing is for the current generation
|
||||
if generation, ok, _ := unstructured.NestedInt64(obj, "status", "observedGeneration"); ok && generation != clientObject.GetGeneration() {
|
||||
if kustomization.Generation != kustomization.Status.ObservedGeneration {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// Confirm the given revision has been attempted by the controller
|
||||
if sourcev1.TransformLegacyRevision(kustomization.Status.LastAttemptedRevision) != expectRevision {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// Confirm the resource is healthy
|
||||
if c := apimeta.FindStatusCondition(clientObject.GetConditions(), meta.ReadyCondition); c != nil {
|
||||
if c := apimeta.FindStatusCondition(kustomization.Status.Conditions, meta.ReadyCondition); c != nil {
|
||||
switch c.Status {
|
||||
case metav1.ConditionTrue:
|
||||
// Confirm the given revision has been attempted by the controller
|
||||
hasRev, err := hasRevision(kind, obj, expectRevision)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return hasRev, nil
|
||||
return true, nil
|
||||
case metav1.ConditionFalse:
|
||||
return false, fmt.Errorf(c.Message)
|
||||
}
|
||||
@@ -243,21 +207,6 @@ func objectReconciled(kube client.Client, objKey client.ObjectKey, clientObject
|
||||
}
|
||||
}
|
||||
|
||||
// hasRevision checks that the reconciled revision (for Kustomization this is `.status.lastAttemptedRevision`
|
||||
// and for Source APIs, it is stored in `.status.artifact.revision`) is the same as the expectedRev
|
||||
func hasRevision(kind string, obj map[string]interface{}, expectedRev string) (bool, error) {
|
||||
var rev string
|
||||
switch kind {
|
||||
case sourcev1.GitRepositoryKind, sourcev1b2.OCIRepositoryKind, sourcev1b2.BucketKind, sourcev1b2.HelmChartKind:
|
||||
rev, _, _ = unstructured.NestedString(obj, "status", "artifact", "revision")
|
||||
case kustomizev1.KustomizationKind:
|
||||
rev, _, _ = unstructured.NestedString(obj, "status", "lastAttemptedRevision")
|
||||
default:
|
||||
return false, fmt.Errorf("cannot get status revision for kind: '%s'", kind)
|
||||
}
|
||||
return sourcev1b2.TransformLegacyRevision(rev) == expectedRev, nil
|
||||
}
|
||||
|
||||
func retry(retries int, wait time.Duration, fn func() error) (err error) {
|
||||
for i := 0; ; i++ {
|
||||
err = fn()
|
||||
|
||||
@@ -29,8 +29,6 @@ import (
|
||||
"github.com/ProtonMail/go-crypto/openpgp"
|
||||
gogit "github.com/go-git/go-git/v5"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
apimeta "k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"k8s.io/cli-runtime/pkg/genericclioptions"
|
||||
@@ -40,12 +38,10 @@ import (
|
||||
|
||||
"github.com/fluxcd/cli-utils/pkg/object"
|
||||
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1"
|
||||
"github.com/fluxcd/pkg/apis/meta"
|
||||
"github.com/fluxcd/pkg/git"
|
||||
"github.com/fluxcd/pkg/git/repository"
|
||||
"github.com/fluxcd/pkg/kustomize/filesys"
|
||||
runclient "github.com/fluxcd/pkg/runtime/client"
|
||||
sourcev1 "github.com/fluxcd/source-controller/api/v1"
|
||||
|
||||
"github.com/fluxcd/flux2/v2/internal/utils"
|
||||
"github.com/fluxcd/flux2/v2/pkg/log"
|
||||
@@ -174,11 +170,11 @@ func (b *PlainGitBootstrapper) ReconcileComponents(ctx context.Context, manifest
|
||||
manifests.Path: strings.NewReader(manifests.Content),
|
||||
}), repository.WithSigner(signer))
|
||||
if err != nil && err != git.ErrNoStagedFiles {
|
||||
return fmt.Errorf("failed to commit component manifests: %w", err)
|
||||
return fmt.Errorf("failed to commit sync manifests: %w", err)
|
||||
}
|
||||
|
||||
if err == nil {
|
||||
b.logger.Successf("committed component manifests to %q (%q)", b.branch, commit)
|
||||
b.logger.Successf("committed sync manifests to %q (%q)", b.branch, commit)
|
||||
b.logger.Actionf("pushing component manifests to %q", b.url)
|
||||
if err = b.gitClient.Push(ctx, repository.PushConfig{}); err != nil {
|
||||
return fmt.Errorf("failed to push manifests: %w", err)
|
||||
@@ -401,62 +397,20 @@ func (b *PlainGitBootstrapper) ReportKustomizationHealth(ctx context.Context, op
|
||||
|
||||
objKey := client.ObjectKey{Name: options.Name, Namespace: options.Namespace}
|
||||
|
||||
expectRevision := fmt.Sprintf("%s@%s", options.Branch, git.Hash(head).Digest())
|
||||
b.logger.Waitingf("waiting for Kustomization %q to be reconciled", objKey.String())
|
||||
k := &kustomizev1.Kustomization{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: kustomizev1.KustomizationKind,
|
||||
},
|
||||
}
|
||||
|
||||
expectRevision := fmt.Sprintf("%s@%s", options.Branch, git.Hash(head).Digest())
|
||||
var k kustomizev1.Kustomization
|
||||
if err := wait.PollUntilContextTimeout(ctx, pollInterval, timeout, true,
|
||||
objectReconciled(b.kube, objKey, k, expectRevision)); err != nil {
|
||||
// If the poll timed out, we want to log the ready condition message as
|
||||
// that likely contains the reason
|
||||
if errors.Is(err, context.DeadlineExceeded) {
|
||||
readyCondition := apimeta.FindStatusCondition(k.Status.Conditions, meta.ReadyCondition)
|
||||
if readyCondition != nil && readyCondition.Status != metav1.ConditionTrue {
|
||||
err = fmt.Errorf("kustomization '%s' not ready: '%s'", objKey, readyCondition.Message)
|
||||
}
|
||||
}
|
||||
kustomizationReconciled(b.kube, objKey, &k, expectRevision)); err != nil {
|
||||
b.logger.Failuref(err.Error())
|
||||
return fmt.Errorf("error while waiting for Kustomization to be ready: '%s'", err)
|
||||
return err
|
||||
}
|
||||
|
||||
b.logger.Successf("Kustomization reconciled successfully")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *PlainGitBootstrapper) ReportGitRepoHealth(ctx context.Context, options sync.Options, pollInterval, timeout time.Duration) error {
|
||||
head, err := b.gitClient.Head()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
objKey := client.ObjectKey{Name: options.Name, Namespace: options.Namespace}
|
||||
|
||||
b.logger.Waitingf("waiting for GitRepository %q to be reconciled", objKey.String())
|
||||
expectRevision := fmt.Sprintf("%s@%s", options.Branch, git.Hash(head).Digest())
|
||||
g := &sourcev1.GitRepository{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: sourcev1.GitRepositoryKind,
|
||||
APIVersion: sourcev1.GroupVersion.String(),
|
||||
},
|
||||
}
|
||||
if err := wait.PollUntilContextTimeout(ctx, pollInterval, timeout, true,
|
||||
objectReconciled(b.kube, objKey, g, expectRevision)); err != nil {
|
||||
// If the poll timed out, we want to log the ready condition message as
|
||||
// that likely contains the reason
|
||||
if errors.Is(err, context.DeadlineExceeded) {
|
||||
readyCondition := apimeta.FindStatusCondition(g.Status.Conditions, meta.ReadyCondition)
|
||||
if readyCondition != nil && readyCondition.Status != metav1.ConditionTrue {
|
||||
err = fmt.Errorf("gitrepository '%s' not ready: '%s'", objKey, readyCondition.Message)
|
||||
}
|
||||
}
|
||||
b.logger.Failuref(err.Error())
|
||||
return fmt.Errorf("error while waiting for GitRepository to be ready: '%s'", err)
|
||||
}
|
||||
b.logger.Successf("GitRepsoitory reconciled successfully")
|
||||
return nil
|
||||
}
|
||||
func (b *PlainGitBootstrapper) ReportComponentsHealth(ctx context.Context, install install.Options, timeout time.Duration) error {
|
||||
cfg, err := utils.KubeConfig(b.restClientGetter, b.restClientOptions)
|
||||
if err != nil {
|
||||
|
||||
@@ -1,469 +0,0 @@
|
||||
/*
|
||||
Copyright 2023 The Flux authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package bootstrap
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/fluxcd/pkg/apis/meta"
|
||||
. "github.com/onsi/gomega"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client/fake"
|
||||
|
||||
"github.com/fluxcd/flux2/v2/internal/utils"
|
||||
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1"
|
||||
notificationv1 "github.com/fluxcd/notification-controller/api/v1beta2"
|
||||
sourcev1 "github.com/fluxcd/source-controller/api/v1"
|
||||
sourcev1b2 "github.com/fluxcd/source-controller/api/v1beta2"
|
||||
)
|
||||
|
||||
func Test_hasRevision(t *testing.T) {
|
||||
var revision = "main@sha1:5bf3a8f9bb0aa5ae8afd6208f43757ab73fc033a"
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
obj objectWithConditions
|
||||
rev string
|
||||
expectErr bool
|
||||
expectedBool bool
|
||||
}{
|
||||
{
|
||||
name: "Kustomization revision",
|
||||
obj: &kustomizev1.Kustomization{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: kustomizev1.KustomizationKind,
|
||||
},
|
||||
Status: kustomizev1.KustomizationStatus{
|
||||
LastAttemptedRevision: "main@sha1:5bf3a8f9bb0aa5ae8afd6208f43757ab73fc033a",
|
||||
},
|
||||
},
|
||||
expectedBool: true,
|
||||
},
|
||||
{
|
||||
name: "GitRepository revision",
|
||||
obj: &sourcev1.GitRepository{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: sourcev1.GitRepositoryKind,
|
||||
APIVersion: sourcev1.GroupVersion.String(),
|
||||
},
|
||||
Status: sourcev1.GitRepositoryStatus{
|
||||
Artifact: &sourcev1.Artifact{
|
||||
Revision: "main@sha1:5bf3a8f9bb0aa5ae8afd6208f43757ab73fc033a",
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedBool: true,
|
||||
},
|
||||
{
|
||||
name: "GitRepository revision (wrong revision)",
|
||||
obj: &sourcev1.GitRepository{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: sourcev1.GitRepositoryKind,
|
||||
APIVersion: sourcev1.GroupVersion.String(),
|
||||
},
|
||||
Status: sourcev1.GitRepositoryStatus{
|
||||
Artifact: &sourcev1.Artifact{
|
||||
Revision: "main@sha1:e7f3a8f9bb0aa5ae8afd6208f43757ab73fc043a",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Kustomization revision (empty revision)",
|
||||
obj: &kustomizev1.Kustomization{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: kustomizev1.KustomizationKind,
|
||||
},
|
||||
Status: kustomizev1.KustomizationStatus{
|
||||
LastAttemptedRevision: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "OCIRepository revision",
|
||||
obj: &sourcev1b2.OCIRepository{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: sourcev1b2.OCIRepositoryKind,
|
||||
},
|
||||
Status: sourcev1b2.OCIRepositoryStatus{
|
||||
Artifact: &sourcev1.Artifact{
|
||||
Revision: "main@sha1:5bf3a8f9bb0aa5ae8afd6208f43757ab73fc033a",
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedBool: true,
|
||||
},
|
||||
{
|
||||
name: "Alert revision(Not supported)",
|
||||
obj: ¬ificationv1.Alert{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: notificationv1.AlertKind,
|
||||
},
|
||||
Status: notificationv1.AlertStatus{
|
||||
ObservedGeneration: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
g := NewWithT(t)
|
||||
obj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(tt.obj)
|
||||
g.Expect(err).To(BeNil())
|
||||
got, err := hasRevision(tt.obj.GetObjectKind().GroupVersionKind().Kind, obj, revision)
|
||||
if tt.expectErr {
|
||||
g.Expect(err).To(HaveOccurred())
|
||||
return
|
||||
}
|
||||
g.Expect(got).To(Equal(tt.expectedBool))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_objectReconciled(t *testing.T) {
|
||||
expectedRev := "main@sha1:5bf3a8f9bb0aa5ae8afd6208f43757ab73fc033a"
|
||||
|
||||
type updateStatus struct {
|
||||
statusFn func(o client.Object)
|
||||
expectedErr bool
|
||||
expectedBool bool
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
obj objectWithConditions
|
||||
statuses []updateStatus
|
||||
}{
|
||||
{
|
||||
name: "GitRepository with no status",
|
||||
obj: &sourcev1.GitRepository{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: sourcev1.GitRepositoryKind,
|
||||
APIVersion: sourcev1.GroupVersion.String(),
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "flux-system",
|
||||
Namespace: "flux-system",
|
||||
},
|
||||
},
|
||||
statuses: []updateStatus{
|
||||
{
|
||||
expectedErr: false,
|
||||
expectedBool: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "suspended Kustomization",
|
||||
obj: &kustomizev1.Kustomization{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: kustomizev1.KustomizationKind,
|
||||
APIVersion: kustomizev1.GroupVersion.String(),
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "flux-system",
|
||||
Namespace: "flux-system",
|
||||
},
|
||||
Spec: kustomizev1.KustomizationSpec{
|
||||
Suspend: true,
|
||||
},
|
||||
},
|
||||
statuses: []updateStatus{
|
||||
{
|
||||
expectedErr: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Kustomization - status with old generation",
|
||||
obj: &kustomizev1.Kustomization{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: kustomizev1.KustomizationKind,
|
||||
APIVersion: kustomizev1.GroupVersion.String(),
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "flux-system",
|
||||
Namespace: "flux-system",
|
||||
Generation: 1,
|
||||
},
|
||||
Status: kustomizev1.KustomizationStatus{
|
||||
ObservedGeneration: -1,
|
||||
},
|
||||
},
|
||||
statuses: []updateStatus{
|
||||
{
|
||||
expectedErr: false,
|
||||
expectedBool: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "GitRepository - status with same generation but no conditions",
|
||||
obj: &sourcev1.GitRepository{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: sourcev1.GitRepositoryKind,
|
||||
APIVersion: sourcev1.GroupVersion.String(),
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "flux-system",
|
||||
Namespace: "flux-system",
|
||||
Generation: 1,
|
||||
},
|
||||
Status: sourcev1.GitRepositoryStatus{
|
||||
ObservedGeneration: 1,
|
||||
},
|
||||
},
|
||||
statuses: []updateStatus{
|
||||
{
|
||||
expectedErr: false,
|
||||
expectedBool: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "GitRepository - status with conditions but no ready condition",
|
||||
obj: &sourcev1.GitRepository{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: sourcev1.GitRepositoryKind,
|
||||
APIVersion: sourcev1.GroupVersion.String(),
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "flux-system",
|
||||
Namespace: "flux-system",
|
||||
Generation: 1,
|
||||
},
|
||||
Status: sourcev1.GitRepositoryStatus{
|
||||
ObservedGeneration: 1,
|
||||
Conditions: []metav1.Condition{
|
||||
{Type: meta.ReconcilingCondition, Status: metav1.ConditionTrue, ObservedGeneration: 1, Reason: "Progressing", Message: "Progressing"},
|
||||
},
|
||||
},
|
||||
},
|
||||
statuses: []updateStatus{
|
||||
{
|
||||
expectedErr: false,
|
||||
expectedBool: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Kustomization - status with false ready condition",
|
||||
obj: &kustomizev1.Kustomization{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: kustomizev1.KustomizationKind,
|
||||
APIVersion: kustomizev1.GroupVersion.String(),
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "flux-system",
|
||||
Namespace: "flux-system",
|
||||
Generation: 1,
|
||||
},
|
||||
Status: kustomizev1.KustomizationStatus{
|
||||
ObservedGeneration: 1,
|
||||
Conditions: []metav1.Condition{
|
||||
{Type: meta.ReadyCondition, Status: metav1.ConditionFalse, ObservedGeneration: 1, Reason: "Failing", Message: "Failed to clone"},
|
||||
},
|
||||
},
|
||||
},
|
||||
statuses: []updateStatus{
|
||||
{
|
||||
expectedErr: true,
|
||||
expectedBool: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Kustomization - status with true ready condition but different revision",
|
||||
obj: &kustomizev1.Kustomization{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: kustomizev1.KustomizationKind,
|
||||
APIVersion: kustomizev1.GroupVersion.String(),
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "flux-system",
|
||||
Namespace: "flux-system",
|
||||
Generation: 1,
|
||||
},
|
||||
Status: kustomizev1.KustomizationStatus{
|
||||
ObservedGeneration: 1,
|
||||
Conditions: []metav1.Condition{
|
||||
{Type: meta.ReadyCondition, Status: metav1.ConditionTrue, ObservedGeneration: 1, Reason: "Passing", Message: "Applied revision"},
|
||||
},
|
||||
LastAttemptedRevision: "main@sha1:e7f3a8f9bb0aa5ae8afd6208f43757ab73fc043a",
|
||||
},
|
||||
},
|
||||
statuses: []updateStatus{
|
||||
{
|
||||
expectedErr: false,
|
||||
expectedBool: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "GitRepository - status with true ready condition but different revision",
|
||||
obj: &sourcev1.GitRepository{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: sourcev1.GitRepositoryKind,
|
||||
APIVersion: sourcev1.GroupVersion.String(),
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "flux-system",
|
||||
Namespace: "flux-system",
|
||||
Generation: 1,
|
||||
},
|
||||
Status: sourcev1.GitRepositoryStatus{
|
||||
ObservedGeneration: 1,
|
||||
Conditions: []metav1.Condition{
|
||||
{Type: meta.ReadyCondition, Status: metav1.ConditionTrue, ObservedGeneration: 1, Reason: "Readyyy", Message: "Cloned successfully"},
|
||||
},
|
||||
Artifact: &sourcev1.Artifact{
|
||||
Revision: "main@sha1:e7f3a8f9bb0aa5ae8afd6208f43757ab73fc043a",
|
||||
},
|
||||
},
|
||||
},
|
||||
statuses: []updateStatus{
|
||||
{
|
||||
expectedErr: false,
|
||||
expectedBool: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "GitRepository - ready with right revision",
|
||||
obj: &sourcev1.GitRepository{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: sourcev1.GitRepositoryKind,
|
||||
APIVersion: sourcev1.GroupVersion.String(),
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "flux-system",
|
||||
Namespace: "flux-system",
|
||||
Generation: 1,
|
||||
},
|
||||
Status: sourcev1.GitRepositoryStatus{
|
||||
ObservedGeneration: 1,
|
||||
Conditions: []metav1.Condition{
|
||||
{Type: meta.ReadyCondition, Status: metav1.ConditionTrue, ObservedGeneration: 1, Reason: "Readyyy", Message: "Cloned successfully"},
|
||||
},
|
||||
Artifact: &sourcev1.Artifact{
|
||||
Revision: expectedRev,
|
||||
},
|
||||
},
|
||||
},
|
||||
statuses: []updateStatus{
|
||||
{
|
||||
expectedErr: false,
|
||||
expectedBool: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "GitRepository - sequence of status updates before ready",
|
||||
obj: &sourcev1.GitRepository{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: sourcev1.GitRepositoryKind,
|
||||
APIVersion: sourcev1.GroupVersion.String(),
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "flux-system",
|
||||
Namespace: "flux-system",
|
||||
Generation: 1,
|
||||
},
|
||||
},
|
||||
statuses: []updateStatus{
|
||||
{
|
||||
// observed gen different
|
||||
statusFn: func(o client.Object) {
|
||||
gitRepo := o.(*sourcev1.GitRepository)
|
||||
gitRepo.Status = sourcev1.GitRepositoryStatus{
|
||||
ObservedGeneration: -1,
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
// ready failing
|
||||
statusFn: func(o client.Object) {
|
||||
gitRepo := o.(*sourcev1.GitRepository)
|
||||
gitRepo.Status = sourcev1.GitRepositoryStatus{
|
||||
ObservedGeneration: 1,
|
||||
Conditions: []metav1.Condition{
|
||||
{Type: meta.ReadyCondition, Status: metav1.ConditionFalse, ObservedGeneration: 1, Reason: "Not Ready", Message: "Transient connection issue"},
|
||||
},
|
||||
}
|
||||
},
|
||||
expectedErr: true,
|
||||
},
|
||||
{
|
||||
// updated to a different revision
|
||||
statusFn: func(o client.Object) {
|
||||
gitRepo := o.(*sourcev1.GitRepository)
|
||||
gitRepo.Status = sourcev1.GitRepositoryStatus{
|
||||
ObservedGeneration: 1,
|
||||
Conditions: []metav1.Condition{
|
||||
{Type: meta.ReadyCondition, Status: metav1.ConditionTrue, ObservedGeneration: 1, Reason: "Readyyy", Message: "Cloned successfully"},
|
||||
},
|
||||
Artifact: &sourcev1.Artifact{
|
||||
Revision: "wrong rev",
|
||||
},
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
// updated to the expected revision
|
||||
statusFn: func(o client.Object) {
|
||||
gitRepo := o.(*sourcev1.GitRepository)
|
||||
gitRepo.Status = sourcev1.GitRepositoryStatus{
|
||||
ObservedGeneration: 1,
|
||||
Conditions: []metav1.Condition{
|
||||
{Type: meta.ReadyCondition, Status: metav1.ConditionTrue, ObservedGeneration: 1, Reason: "Readyyy", Message: "Cloned successfully"},
|
||||
},
|
||||
Artifact: &sourcev1.Artifact{
|
||||
Revision: expectedRev,
|
||||
},
|
||||
}
|
||||
},
|
||||
expectedBool: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
g := NewWithT(t)
|
||||
builder := fake.NewClientBuilder().WithScheme(utils.NewScheme())
|
||||
builder.WithObjects(tt.obj)
|
||||
|
||||
kubeClient := builder.Build()
|
||||
|
||||
for _, updates := range tt.statuses {
|
||||
if updates.statusFn != nil {
|
||||
updates.statusFn(tt.obj)
|
||||
g.Expect(kubeClient.Update(context.TODO(), tt.obj)).To(Succeed())
|
||||
}
|
||||
|
||||
waitFunc := objectReconciled(kubeClient, client.ObjectKeyFromObject(tt.obj), tt.obj, expectedRev)
|
||||
got, err := waitFunc(context.TODO())
|
||||
g.Expect(err != nil).To(Equal(updates.expectedErr))
|
||||
g.Expect(got).To(Equal(updates.expectedBool))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -45,16 +45,6 @@ type StatusChecker struct {
|
||||
logger log.Logger
|
||||
}
|
||||
|
||||
func NewStatusCheckerWithClient(c client.Client, pollInterval time.Duration, timeout time.Duration, log log.Logger) (*StatusChecker, error) {
|
||||
return &StatusChecker{
|
||||
pollInterval: pollInterval,
|
||||
timeout: timeout,
|
||||
client: c,
|
||||
statusPoller: polling.NewStatusPoller(c, c.RESTMapper(), polling.Options{}),
|
||||
logger: log,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func NewStatusChecker(kubeConfig *rest.Config, pollInterval time.Duration, timeout time.Duration, log log.Logger) (*StatusChecker, error) {
|
||||
restMapper, err := runtimeclient.NewDynamicRESTMapper(kubeConfig)
|
||||
if err != nil {
|
||||
@@ -65,7 +55,13 @@ func NewStatusChecker(kubeConfig *rest.Config, pollInterval time.Duration, timeo
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return NewStatusCheckerWithClient(c, pollInterval, timeout, log)
|
||||
return &StatusChecker{
|
||||
pollInterval: pollInterval,
|
||||
timeout: timeout,
|
||||
client: c,
|
||||
statusPoller: polling.NewStatusPoller(c, restMapper, polling.Options{}),
|
||||
logger: log,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (sc *StatusChecker) Assess(identifiers ...object.ObjMetadata) error {
|
||||
@@ -98,7 +94,7 @@ func (sc *StatusChecker) Assess(identifiers ...object.ObjMetadata) error {
|
||||
}
|
||||
|
||||
if coll.Error != nil || ctx.Err() == context.DeadlineExceeded {
|
||||
return fmt.Errorf("timed out waiting for all resources to be ready")
|
||||
return fmt.Errorf("timed out waiting for condition")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ import (
|
||||
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1beta2"
|
||||
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1"
|
||||
notificationv1 "github.com/fluxcd/notification-controller/api/v1"
|
||||
notificationv1b3 "github.com/fluxcd/notification-controller/api/v1beta3"
|
||||
notificationv1b2 "github.com/fluxcd/notification-controller/api/v1beta2"
|
||||
sourcev1 "github.com/fluxcd/source-controller/api/v1"
|
||||
sourcev1b2 "github.com/fluxcd/source-controller/api/v1beta2"
|
||||
)
|
||||
@@ -243,7 +243,7 @@ func Finalizers(ctx context.Context, logger log.Logger, kubeClient client.Client
|
||||
}
|
||||
}
|
||||
{
|
||||
var list notificationv1b3.AlertList
|
||||
var list notificationv1b2.AlertList
|
||||
if err := kubeClient.List(ctx, &list, client.InNamespace("")); err == nil {
|
||||
for i := range list.Items {
|
||||
r := list.Items[i]
|
||||
@@ -258,7 +258,7 @@ func Finalizers(ctx context.Context, logger log.Logger, kubeClient client.Client
|
||||
}
|
||||
}
|
||||
{
|
||||
var list notificationv1b3.ProviderList
|
||||
var list notificationv1b2.ProviderList
|
||||
if err := kubeClient.List(ctx, &list, client.InNamespace("")); err == nil {
|
||||
for i := range list.Items {
|
||||
r := list.Items[i]
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
**Creation date:** 2022-03-30
|
||||
|
||||
**Last update:** 2023-11-28
|
||||
**Last update:** 2022-10-20
|
||||
|
||||
## Summary
|
||||
|
||||
@@ -252,15 +252,17 @@ Bucket API design, where the same Kind servers different implementations: AWS S3
|
||||
|
||||
## Design Details
|
||||
|
||||
Unlike the default `HelmRepository`, the OCI `HelmRepository` does not need to
|
||||
download any repository index file. The associated HelmChart can pull the chart
|
||||
directly from the OCI registry based on the registry information in the
|
||||
`HelmRepository` object. This makes the `HelmRepository` of type `oci` static,
|
||||
not backed by a reconciler to move to a desired state. It becomes a data
|
||||
container with information about the OCI registry.
|
||||
In source-controller we'll add a new predicate for filtering `HelmRepositories` based on the `spec.type` field.
|
||||
|
||||
In source-controller, the `HelmRepositoryReconciler` will be updated to check
|
||||
the `.spec.type` field of `HelmRepository` and do nothing if it is `oci`.
|
||||
The current `HelmRepositoryReconciler` will handle only objects with `type: default`,
|
||||
it's scope remains unchanged.
|
||||
|
||||
We'll introduce a new reconciler named `HelmRepositoryOCIReconciler`, that will handle
|
||||
objects with `type: oci`. This reconciler will set the `HelmRepository` Ready status to
|
||||
`False` if:
|
||||
- the URL is not prefixed with `oci://`
|
||||
- the URL is malformed and can't be parsed
|
||||
- the specified credentials result in an authentication error
|
||||
|
||||
The current `HelmChartReconciler` will be adapted to handle both types.
|
||||
|
||||
@@ -275,7 +277,6 @@ The feature is enabled by default.
|
||||
* **2022-08-11** Resolve chart dependencies from OCI released with [flux2 v0.32.0](https://github.com/fluxcd/flux2/releases/tag/v0.32.0)
|
||||
* **2022-08-29** Contextual login for AWS, Azure and GCP released with [flux2 v0.33.0](https://github.com/fluxcd/flux2/releases/tag/v0.33.0)
|
||||
* **2022-10-21** Verifying Helm charts with Cosign released with [flux2 v0.36.0](https://github.com/fluxcd/flux2/releases/tag/v0.36.0)
|
||||
* **2023-11-28** Update the design of HelmRepository of type OCI to be static object [flux2 v2.2.0](https://github.com/fluxcd/flux2/releases/tag/v2.2.0)
|
||||
|
||||
### TODOs
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ import (
|
||||
reflectorv1beta2 "github.com/fluxcd/image-reflector-controller/api/v1beta2"
|
||||
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1"
|
||||
notiv1 "github.com/fluxcd/notification-controller/api/v1"
|
||||
notiv1beta3 "github.com/fluxcd/notification-controller/api/v1beta3"
|
||||
notiv1beta2 "github.com/fluxcd/notification-controller/api/v1beta2"
|
||||
eventv1 "github.com/fluxcd/pkg/apis/event/v1beta1"
|
||||
"github.com/fluxcd/pkg/apis/meta"
|
||||
sourcev1 "github.com/fluxcd/source-controller/api/v1"
|
||||
@@ -681,14 +681,14 @@ func TestAzureDevOpsCommitStatus(t *testing.T) {
|
||||
}
|
||||
return nil
|
||||
})
|
||||
provider := notiv1beta3.Provider{
|
||||
provider := notiv1beta2.Provider{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "azuredevops",
|
||||
Namespace: name,
|
||||
},
|
||||
}
|
||||
_, err = controllerutil.CreateOrUpdate(ctx, cfg.kubeClient, &provider, func() error {
|
||||
provider.Spec = notiv1beta3.ProviderSpec{
|
||||
provider.Spec = notiv1beta2.ProviderSpec{
|
||||
Type: "azuredevops",
|
||||
Address: repoUrl,
|
||||
SecretRef: &meta.LocalObjectReference{
|
||||
@@ -698,14 +698,14 @@ func TestAzureDevOpsCommitStatus(t *testing.T) {
|
||||
return nil
|
||||
})
|
||||
require.NoError(t, err)
|
||||
alert := notiv1beta3.Alert{
|
||||
alert := notiv1beta2.Alert{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "azuredevops",
|
||||
Namespace: name,
|
||||
},
|
||||
}
|
||||
_, err = controllerutil.CreateOrUpdate(ctx, cfg.kubeClient, &alert, func() error {
|
||||
alert.Spec = notiv1beta3.AlertSpec{
|
||||
alert.Spec = notiv1beta2.AlertSpec{
|
||||
ProviderRef: meta.LocalObjectReference{
|
||||
Name: provider.Name,
|
||||
},
|
||||
@@ -809,14 +809,14 @@ func TestEventHubNotification(t *testing.T) {
|
||||
}
|
||||
return nil
|
||||
})
|
||||
provider := notiv1beta3.Provider{
|
||||
provider := notiv1beta2.Provider{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
Namespace: name,
|
||||
},
|
||||
}
|
||||
_, err = controllerutil.CreateOrUpdate(ctx, cfg.kubeClient, &provider, func() error {
|
||||
provider.Spec = notiv1beta3.ProviderSpec{
|
||||
provider.Spec = notiv1beta2.ProviderSpec{
|
||||
Type: "azureeventhub",
|
||||
Address: repoUrl,
|
||||
SecretRef: &meta.LocalObjectReference{
|
||||
@@ -826,14 +826,14 @@ func TestEventHubNotification(t *testing.T) {
|
||||
return nil
|
||||
})
|
||||
require.NoError(t, err)
|
||||
alert := notiv1beta3.Alert{
|
||||
alert := notiv1beta2.Alert{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
Namespace: name,
|
||||
},
|
||||
}
|
||||
_, err = controllerutil.CreateOrUpdate(ctx, cfg.kubeClient, &alert, func() error {
|
||||
alert.Spec = notiv1beta3.AlertSpec{
|
||||
alert.Spec = notiv1beta2.AlertSpec{
|
||||
ProviderRef: meta.LocalObjectReference{
|
||||
Name: provider.Name,
|
||||
},
|
||||
|
||||
@@ -9,14 +9,14 @@ require (
|
||||
github.com/Azure/azure-event-hubs-go/v3 v3.6.1
|
||||
github.com/fluxcd/helm-controller/api v0.36.2
|
||||
github.com/fluxcd/image-automation-controller/api v0.36.1
|
||||
github.com/fluxcd/image-reflector-controller/api v0.31.0
|
||||
github.com/fluxcd/image-reflector-controller/api v0.30.0
|
||||
github.com/fluxcd/kustomize-controller/api v1.1.1
|
||||
github.com/fluxcd/notification-controller/api v1.2.1
|
||||
github.com/fluxcd/notification-controller/api v1.1.0
|
||||
github.com/fluxcd/pkg/apis/event v0.6.0
|
||||
github.com/fluxcd/pkg/apis/meta v1.2.0
|
||||
github.com/fluxcd/pkg/git v0.15.0
|
||||
github.com/fluxcd/pkg/git/gogit v0.15.0
|
||||
github.com/fluxcd/source-controller/api v1.2.1
|
||||
github.com/fluxcd/source-controller/api v1.1.2
|
||||
github.com/go-git/go-git/v5 v5.10.0
|
||||
github.com/hashicorp/hc-install v0.5.2
|
||||
github.com/hashicorp/terraform-exec v0.18.1
|
||||
|
||||
@@ -71,12 +71,12 @@ github.com/fluxcd/helm-controller/api v0.36.2 h1:9JaTc91yocG1oQkM/GMfpZ/nGPpliRj
|
||||
github.com/fluxcd/helm-controller/api v0.36.2/go.mod h1:zkcRy3PxG0NoxSY5SjiSA5tWOGa6spIbWsChQY8FXqM=
|
||||
github.com/fluxcd/image-automation-controller/api v0.36.1 h1:Knd4SSm/bJ0iqvYcQq87uDaT/mW9poM1jOvHpJ/4tzk=
|
||||
github.com/fluxcd/image-automation-controller/api v0.36.1/go.mod h1:IsjdBtgm71KHRGDTZZZiGYdWGoJ5VjenE9F4ueADM/o=
|
||||
github.com/fluxcd/image-reflector-controller/api v0.31.0 h1:9t5zj7ufo9/d57gpcZsD6YAIxFz0vtLH4jXCj379srE=
|
||||
github.com/fluxcd/image-reflector-controller/api v0.31.0/go.mod h1:/EcjOa/EYi8sSBHcGrBkLjMjNNfC7xXMxqG9phBORCo=
|
||||
github.com/fluxcd/image-reflector-controller/api v0.30.0 h1:DiWj+4tcbnaSqZs1Pfkyt3uSy47wg3dsNMgbFE50pYc=
|
||||
github.com/fluxcd/image-reflector-controller/api v0.30.0/go.mod h1:hv57KwIzoPyy7Vu4PFcIf21eu0N3p/HbijygcuNgf8c=
|
||||
github.com/fluxcd/kustomize-controller/api v1.1.1 h1:pQcAzvBC3cFGOCgk0zrcsO1Kjtal1tvd6rHXkyp2R78=
|
||||
github.com/fluxcd/kustomize-controller/api v1.1.1/go.mod h1:FHJTX6c0+CznUNGMol5+Uc4lQsYRxWgpmIRK/xDCghA=
|
||||
github.com/fluxcd/notification-controller/api v1.2.1 h1:yPQZ7ppYvazxl/Vsespbx9VlVyopH7p8pKGzZTNxI0c=
|
||||
github.com/fluxcd/notification-controller/api v1.2.1/go.mod h1:1sWTpAXkga5zkXOgFoR+NIJgHNclBcfAHUJ/rMAjnYY=
|
||||
github.com/fluxcd/notification-controller/api v1.1.0 h1:qx5t5DmArfPLxG2bsYZXIqDXLnijUddlHeRfciALwQw=
|
||||
github.com/fluxcd/notification-controller/api v1.1.0/go.mod h1:6MqWVQeI5yrYR7zp0GFqsfXitNPGJrnfOWxO2w3jylg=
|
||||
github.com/fluxcd/pkg/apis/acl v0.1.0 h1:EoAl377hDQYL3WqanWCdifauXqXbMyFuK82NnX6pH4Q=
|
||||
github.com/fluxcd/pkg/apis/acl v0.1.0/go.mod h1:zfEZzz169Oap034EsDhmCAGgnWlcWmIObZjYMusoXS8=
|
||||
github.com/fluxcd/pkg/apis/event v0.6.0 h1:AUaeee1CGWb65BLqVximHXG8Gcu6vWuYONIq6tVpjgo=
|
||||
@@ -94,8 +94,8 @@ github.com/fluxcd/pkg/ssh v0.9.0 h1:egRvg4AKarObFKXsBDZ5oBZ5PCjmQ4Q6hX+6GmrdbH0=
|
||||
github.com/fluxcd/pkg/ssh v0.9.0/go.mod h1:3KKbfcFn4l+HqYdHKqcu2LO8RvFv0Kh6tYRSUtONC/8=
|
||||
github.com/fluxcd/pkg/version v0.2.2 h1:ZpVXECeLA5hIQMft11iLp6gN3cKcz6UNuVTQPw/bRdI=
|
||||
github.com/fluxcd/pkg/version v0.2.2/go.mod h1:NGnh/no8S6PyfCDxRFrPY3T5BUnqP48MxfxNRU0z8C0=
|
||||
github.com/fluxcd/source-controller/api v1.2.1 h1:zWRfwMB/BkV0A/duZQwHEcrE/abWJQt7DUgYTzn4IzM=
|
||||
github.com/fluxcd/source-controller/api v1.2.1/go.mod h1:n+PMCJXl/AYCjWHn5N/MUuoIFKfDg4kCDviFIa7fDvI=
|
||||
github.com/fluxcd/source-controller/api v1.1.2 h1:FfKDKVWnopo+Q2pOAxgHEjrtr4MP41L8aapR4mqBhBk=
|
||||
github.com/fluxcd/source-controller/api v1.1.2/go.mod h1:ZLkaUd1KQIjtLPCvO63Ni5zpnSTVBAkeRgFBzMItbDQ=
|
||||
github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw=
|
||||
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
|
||||
github.com/gliderlabs/ssh v0.3.5 h1:OcaySEmAQJgyYcArR+gGGTHCyE7nvhEMTlYY+Dp8CpY=
|
||||
|
||||
@@ -40,7 +40,7 @@ import (
|
||||
reflectorv1beta2 "github.com/fluxcd/image-reflector-controller/api/v1beta2"
|
||||
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1"
|
||||
notiv1 "github.com/fluxcd/notification-controller/api/v1"
|
||||
notiv1beta3 "github.com/fluxcd/notification-controller/api/v1beta3"
|
||||
notiv1beta2 "github.com/fluxcd/notification-controller/api/v1beta2"
|
||||
"github.com/fluxcd/pkg/apis/meta"
|
||||
"github.com/fluxcd/pkg/git"
|
||||
"github.com/fluxcd/pkg/git/gogit"
|
||||
@@ -96,7 +96,7 @@ func getKubernetesCredentials(kubeconfig, aksHost, aksCert, aksKey, aksCa string
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
err = notiv1beta3.AddToScheme(scheme.Scheme)
|
||||
err = notiv1beta2.AddToScheme(scheme.Scheme)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ import (
|
||||
|
||||
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1"
|
||||
notiv1 "github.com/fluxcd/notification-controller/api/v1"
|
||||
notiv1beta3 "github.com/fluxcd/notification-controller/api/v1beta3"
|
||||
notiv1beta2 "github.com/fluxcd/notification-controller/api/v1beta2"
|
||||
"github.com/fluxcd/pkg/apis/meta"
|
||||
sourcev1 "github.com/fluxcd/source-controller/api/v1"
|
||||
)
|
||||
@@ -109,12 +109,12 @@ metadata:
|
||||
g.Expect(testEnv.Create(ctx, &secret)).To(Succeed())
|
||||
defer testEnv.Delete(ctx, &secret)
|
||||
|
||||
provider := notiv1beta3.Provider{
|
||||
provider := notiv1beta2.Provider{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "azuredevops",
|
||||
Namespace: testID,
|
||||
},
|
||||
Spec: notiv1beta3.ProviderSpec{
|
||||
Spec: notiv1beta2.ProviderSpec{
|
||||
Type: "azuredevops",
|
||||
Address: repoUrl,
|
||||
SecretRef: &meta.LocalObjectReference{
|
||||
@@ -125,12 +125,12 @@ metadata:
|
||||
g.Expect(testEnv.Create(ctx, &provider)).To(Succeed())
|
||||
defer testEnv.Delete(ctx, &provider)
|
||||
|
||||
alert := notiv1beta3.Alert{
|
||||
alert := notiv1beta2.Alert{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "azuredevops",
|
||||
Namespace: testID,
|
||||
},
|
||||
Spec: notiv1beta3.AlertSpec{
|
||||
Spec: notiv1beta2.AlertSpec{
|
||||
ProviderRef: meta.LocalObjectReference{
|
||||
Name: provider.Name,
|
||||
},
|
||||
|
||||
@@ -7,15 +7,15 @@ require (
|
||||
github.com/Azure/azure-event-hubs-go/v3 v3.6.0
|
||||
github.com/fluxcd/helm-controller/api v0.36.2
|
||||
github.com/fluxcd/image-automation-controller/api v0.36.1
|
||||
github.com/fluxcd/image-reflector-controller/api v0.31.0
|
||||
github.com/fluxcd/image-reflector-controller/api v0.30.0
|
||||
github.com/fluxcd/kustomize-controller/api v1.1.1
|
||||
github.com/fluxcd/notification-controller/api v1.2.1
|
||||
github.com/fluxcd/notification-controller/api v1.1.0
|
||||
github.com/fluxcd/pkg/apis/event v0.6.0
|
||||
github.com/fluxcd/pkg/apis/meta v1.2.0
|
||||
github.com/fluxcd/pkg/git v0.15.0
|
||||
github.com/fluxcd/pkg/git/gogit v0.15.0
|
||||
github.com/fluxcd/pkg/runtime v0.43.0
|
||||
github.com/fluxcd/source-controller/api v1.2.1
|
||||
github.com/fluxcd/source-controller/api v1.1.2
|
||||
github.com/fluxcd/test-infra/tftestenv v0.0.0-20230831142147-627bca8e7916
|
||||
github.com/go-git/go-git/v5 v5.10.0
|
||||
github.com/google/go-containerregistry v0.16.1
|
||||
|
||||
@@ -126,12 +126,12 @@ github.com/fluxcd/helm-controller/api v0.36.2 h1:9JaTc91yocG1oQkM/GMfpZ/nGPpliRj
|
||||
github.com/fluxcd/helm-controller/api v0.36.2/go.mod h1:zkcRy3PxG0NoxSY5SjiSA5tWOGa6spIbWsChQY8FXqM=
|
||||
github.com/fluxcd/image-automation-controller/api v0.36.1 h1:Knd4SSm/bJ0iqvYcQq87uDaT/mW9poM1jOvHpJ/4tzk=
|
||||
github.com/fluxcd/image-automation-controller/api v0.36.1/go.mod h1:IsjdBtgm71KHRGDTZZZiGYdWGoJ5VjenE9F4ueADM/o=
|
||||
github.com/fluxcd/image-reflector-controller/api v0.31.0 h1:9t5zj7ufo9/d57gpcZsD6YAIxFz0vtLH4jXCj379srE=
|
||||
github.com/fluxcd/image-reflector-controller/api v0.31.0/go.mod h1:/EcjOa/EYi8sSBHcGrBkLjMjNNfC7xXMxqG9phBORCo=
|
||||
github.com/fluxcd/image-reflector-controller/api v0.30.0 h1:DiWj+4tcbnaSqZs1Pfkyt3uSy47wg3dsNMgbFE50pYc=
|
||||
github.com/fluxcd/image-reflector-controller/api v0.30.0/go.mod h1:hv57KwIzoPyy7Vu4PFcIf21eu0N3p/HbijygcuNgf8c=
|
||||
github.com/fluxcd/kustomize-controller/api v1.1.1 h1:pQcAzvBC3cFGOCgk0zrcsO1Kjtal1tvd6rHXkyp2R78=
|
||||
github.com/fluxcd/kustomize-controller/api v1.1.1/go.mod h1:FHJTX6c0+CznUNGMol5+Uc4lQsYRxWgpmIRK/xDCghA=
|
||||
github.com/fluxcd/notification-controller/api v1.2.1 h1:yPQZ7ppYvazxl/Vsespbx9VlVyopH7p8pKGzZTNxI0c=
|
||||
github.com/fluxcd/notification-controller/api v1.2.1/go.mod h1:1sWTpAXkga5zkXOgFoR+NIJgHNclBcfAHUJ/rMAjnYY=
|
||||
github.com/fluxcd/notification-controller/api v1.1.0 h1:qx5t5DmArfPLxG2bsYZXIqDXLnijUddlHeRfciALwQw=
|
||||
github.com/fluxcd/notification-controller/api v1.1.0/go.mod h1:6MqWVQeI5yrYR7zp0GFqsfXitNPGJrnfOWxO2w3jylg=
|
||||
github.com/fluxcd/pkg/apis/acl v0.1.0 h1:EoAl377hDQYL3WqanWCdifauXqXbMyFuK82NnX6pH4Q=
|
||||
github.com/fluxcd/pkg/apis/acl v0.1.0/go.mod h1:zfEZzz169Oap034EsDhmCAGgnWlcWmIObZjYMusoXS8=
|
||||
github.com/fluxcd/pkg/apis/event v0.6.0 h1:AUaeee1CGWb65BLqVximHXG8Gcu6vWuYONIq6tVpjgo=
|
||||
@@ -151,8 +151,8 @@ github.com/fluxcd/pkg/ssh v0.9.0 h1:egRvg4AKarObFKXsBDZ5oBZ5PCjmQ4Q6hX+6GmrdbH0=
|
||||
github.com/fluxcd/pkg/ssh v0.9.0/go.mod h1:3KKbfcFn4l+HqYdHKqcu2LO8RvFv0Kh6tYRSUtONC/8=
|
||||
github.com/fluxcd/pkg/version v0.2.2 h1:ZpVXECeLA5hIQMft11iLp6gN3cKcz6UNuVTQPw/bRdI=
|
||||
github.com/fluxcd/pkg/version v0.2.2/go.mod h1:NGnh/no8S6PyfCDxRFrPY3T5BUnqP48MxfxNRU0z8C0=
|
||||
github.com/fluxcd/source-controller/api v1.2.1 h1:zWRfwMB/BkV0A/duZQwHEcrE/abWJQt7DUgYTzn4IzM=
|
||||
github.com/fluxcd/source-controller/api v1.2.1/go.mod h1:n+PMCJXl/AYCjWHn5N/MUuoIFKfDg4kCDviFIa7fDvI=
|
||||
github.com/fluxcd/source-controller/api v1.1.2 h1:FfKDKVWnopo+Q2pOAxgHEjrtr4MP41L8aapR4mqBhBk=
|
||||
github.com/fluxcd/source-controller/api v1.1.2/go.mod h1:ZLkaUd1KQIjtLPCvO63Ni5zpnSTVBAkeRgFBzMItbDQ=
|
||||
github.com/fluxcd/test-infra/tftestenv v0.0.0-20230831142147-627bca8e7916 h1:w9UGknpfAGbiObQALZiuWYGeriAU1wKCFTmI2tj/96M=
|
||||
github.com/fluxcd/test-infra/tftestenv v0.0.0-20230831142147-627bca8e7916/go.mod h1:liFlLEXgambGVdWSJ4JzbIHf1Vjpp1HwUyPazPIVZug=
|
||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
|
||||
|
||||
@@ -27,10 +27,11 @@ import (
|
||||
. "github.com/onsi/gomega"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
|
||||
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1"
|
||||
notiv1 "github.com/fluxcd/notification-controller/api/v1"
|
||||
notiv1beta3 "github.com/fluxcd/notification-controller/api/v1beta3"
|
||||
notiv1beta2 "github.com/fluxcd/notification-controller/api/v1beta2"
|
||||
events "github.com/fluxcd/pkg/apis/event/v1beta1"
|
||||
"github.com/fluxcd/pkg/apis/meta"
|
||||
sourcev1 "github.com/fluxcd/source-controller/api/v1"
|
||||
@@ -65,12 +66,12 @@ metadata:
|
||||
g.Expect(testEnv.Create(ctx, &namespace)).To(Succeed())
|
||||
defer testEnv.Delete(ctx, &namespace)
|
||||
|
||||
provider := notiv1beta3.Provider{
|
||||
provider := notiv1beta2.Provider{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: testID,
|
||||
Namespace: testID,
|
||||
},
|
||||
Spec: notiv1beta3.ProviderSpec{
|
||||
Spec: notiv1beta2.ProviderSpec{
|
||||
Type: cfg.notificationCfg.providerType,
|
||||
Address: cfg.notificationCfg.providerAddress,
|
||||
Channel: cfg.notificationCfg.providerChannel,
|
||||
@@ -97,12 +98,12 @@ metadata:
|
||||
g.Expect(testEnv.Create(ctx, &provider)).To(Succeed())
|
||||
defer testEnv.Delete(ctx, &provider)
|
||||
|
||||
alert := notiv1beta3.Alert{
|
||||
alert := notiv1beta2.Alert{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: testID,
|
||||
Namespace: testID,
|
||||
},
|
||||
Spec: notiv1beta3.AlertSpec{
|
||||
Spec: notiv1beta2.AlertSpec{
|
||||
ProviderRef: meta.LocalObjectReference{
|
||||
Name: provider.Name,
|
||||
},
|
||||
@@ -118,6 +119,32 @@ metadata:
|
||||
g.Expect(testEnv.Create(ctx, &alert)).ToNot(HaveOccurred())
|
||||
defer testEnv.Delete(ctx, &alert)
|
||||
|
||||
g.Eventually(func() bool {
|
||||
nn := types.NamespacedName{Name: provider.Name, Namespace: provider.Namespace}
|
||||
obj := ¬iv1beta2.Provider{}
|
||||
err := testEnv.Get(ctx, nn, obj)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
if err := checkReadyCondition(obj); err != nil {
|
||||
t.Log(err)
|
||||
return false
|
||||
}
|
||||
|
||||
nn = types.NamespacedName{Name: alert.Name, Namespace: alert.Namespace}
|
||||
alertObj := ¬iv1beta2.Alert{}
|
||||
err = testEnv.Get(ctx, nn, alertObj)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
if err := checkReadyCondition(alertObj); err != nil {
|
||||
t.Log(err)
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}, testTimeout, testInterval).Should(BeTrue())
|
||||
|
||||
modifyKsSpec := func(spec *kustomizev1.KustomizationSpec) {
|
||||
spec.Interval = metav1.Duration{Duration: 30 * time.Second}
|
||||
spec.HealthChecks = []meta.NamespacedObjectKindReference{
|
||||
|
||||
@@ -49,7 +49,7 @@ func TestOCIHelmRelease(t *testing.T) {
|
||||
err := pushImagesFromURL(repoURL, "ghcr.io/stefanprodan/charts/podinfo:6.2.0", []string{"6.2.0"})
|
||||
g.Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
// Create HelmRepository.
|
||||
// Create HelmRepository and wait for it to sync
|
||||
helmRepository := sourcev1.HelmRepository{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: testID, Namespace: testID},
|
||||
Spec: sourcev1.HelmRepositorySpec{
|
||||
@@ -66,6 +66,21 @@ func TestOCIHelmRelease(t *testing.T) {
|
||||
g.Expect(testEnv.Create(ctx, &helmRepository)).To(Succeed())
|
||||
defer testEnv.Delete(ctx, &helmRepository)
|
||||
|
||||
g.Eventually(func() bool {
|
||||
obj := &sourcev1.HelmRepository{}
|
||||
nn := types.NamespacedName{Name: helmRepository.Name, Namespace: helmRepository.Namespace}
|
||||
err := testEnv.Get(ctx, nn, obj)
|
||||
if err != nil {
|
||||
t.Logf("error getting helm repository %s", err.Error())
|
||||
return false
|
||||
}
|
||||
if err := checkReadyCondition(obj); err != nil {
|
||||
t.Logf("%v", err)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}, testTimeout, testInterval).Should(BeTrue())
|
||||
|
||||
// create helm release
|
||||
helmRelease := helmv2.HelmRelease{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: testID, Namespace: testID},
|
||||
|
||||
@@ -34,7 +34,7 @@ import (
|
||||
automationv1beta1 "github.com/fluxcd/image-automation-controller/api/v1beta1"
|
||||
reflectorv1beta2 "github.com/fluxcd/image-reflector-controller/api/v1beta2"
|
||||
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1"
|
||||
notiv1beta3 "github.com/fluxcd/notification-controller/api/v1beta3"
|
||||
notiv1beta2 "github.com/fluxcd/notification-controller/api/v1beta2"
|
||||
"github.com/fluxcd/pkg/git"
|
||||
sourcev1 "github.com/fluxcd/source-controller/api/v1"
|
||||
sourcev1beta2 "github.com/fluxcd/source-controller/api/v1beta2"
|
||||
@@ -166,7 +166,7 @@ func init() {
|
||||
utilruntime.Must(helmv2beta1.AddToScheme(scheme.Scheme))
|
||||
utilruntime.Must(reflectorv1beta2.AddToScheme(scheme.Scheme))
|
||||
utilruntime.Must(automationv1beta1.AddToScheme(scheme.Scheme))
|
||||
utilruntime.Must(notiv1beta3.AddToScheme(scheme.Scheme))
|
||||
utilruntime.Must(notiv1beta2.AddToScheme(scheme.Scheme))
|
||||
|
||||
random = rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user