Compare commits
32 Commits
Author | SHA1 | Date |
---|---|---|
|
60b8f86f49 | |
|
fd63b520d5 | |
|
d17e5d2514 | |
|
e0e6e22272 | |
|
c2754dd5de | |
|
5edcf5b394 | |
|
8ec3ec388d | |
|
0c48a16ede | |
|
c48ffbef1c | |
|
2dcec193bb | |
|
b4d23e756f | |
|
2fb1fa3890 | |
|
ba3c16aa45 | |
|
2fb1482f71 | |
|
52170876d5 | |
|
1476042b1e | |
|
f479c3e1f6 | |
|
bc4756a38f | |
|
5703d47395 | |
|
30275f2615 | |
|
a342d00602 | |
|
4623a38989 | |
|
124402b53a | |
|
8e90ab8008 | |
|
8c1d87ba6a | |
|
8479377cd7 | |
|
ebee7880e7 | |
|
9f784c5e9f | |
|
07837f603c | |
|
ee8981f35d | |
|
40a75725dd | |
|
f1cfd9f0c8 |
|
@ -5,7 +5,7 @@ updates:
|
|||
directory: "/"
|
||||
labels: ["dependencies"]
|
||||
schedule:
|
||||
interval: "daily"
|
||||
interval: "monthly"
|
||||
groups:
|
||||
go-deps:
|
||||
patterns:
|
||||
|
@ -31,4 +31,4 @@ updates:
|
|||
patterns:
|
||||
- "*"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
interval: "monthly"
|
||||
|
|
|
@ -35,3 +35,6 @@
|
|||
- name: backport:release/v1.5.x
|
||||
description: To be backported to release/v1.5.x
|
||||
color: '#ffd700'
|
||||
- name: backport:release/v1.6.x
|
||||
description: To be backported to release/v1.6.x
|
||||
color: '#ffd700'
|
||||
|
|
18
CHANGELOG.md
18
CHANGELOG.md
|
@ -2,6 +2,24 @@
|
|||
|
||||
All notable changes to this project are documented in this file.
|
||||
|
||||
## 1.6.1
|
||||
|
||||
**Release date:** 2025-07-08
|
||||
|
||||
This patch release fixes a bug introduced in v1.6.0
|
||||
that causes SOPS decryption with US Government KMS
|
||||
keys to fail with the error:
|
||||
|
||||
```
|
||||
STS: AssumeRoleWithWebIdentity, https response error\n StatusCode: 0, RequestID: ,
|
||||
request send failed, Post\n \"https://sts.arn.amazonaws.com/\": dial tcp:
|
||||
lookupts.arn.amazonaws.com on 10.100.0.10:53: no such host
|
||||
```
|
||||
|
||||
Fixes:
|
||||
- Fix regression in STS endpoint for SOPS decryption with AWS KMS in US Gov partition
|
||||
[#1478](https://github.com/fluxcd/kustomize-controller/pull/1478)
|
||||
|
||||
## 1.6.0
|
||||
|
||||
**Release date:** 2025-05-28
|
||||
|
|
16
api/go.mod
16
api/go.mod
|
@ -3,10 +3,10 @@ module github.com/fluxcd/kustomize-controller/api
|
|||
go 1.24.0
|
||||
|
||||
require (
|
||||
github.com/fluxcd/pkg/apis/kustomize v1.10.0
|
||||
github.com/fluxcd/pkg/apis/meta v1.12.0
|
||||
k8s.io/apiextensions-apiserver v0.33.0
|
||||
k8s.io/apimachinery v0.33.0
|
||||
github.com/fluxcd/pkg/apis/kustomize v1.11.0
|
||||
github.com/fluxcd/pkg/apis/meta v1.18.0
|
||||
k8s.io/apiextensions-apiserver v0.33.2
|
||||
k8s.io/apimachinery v0.33.2
|
||||
sigs.k8s.io/controller-runtime v0.21.0
|
||||
)
|
||||
|
||||
|
@ -23,14 +23,14 @@ require (
|
|||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/spf13/pflag v1.0.6 // indirect
|
||||
github.com/x448/float16 v0.8.4 // indirect
|
||||
golang.org/x/net v0.40.0 // indirect
|
||||
golang.org/x/text v0.25.0 // indirect
|
||||
golang.org/x/tools v0.33.0 // indirect
|
||||
go.yaml.in/yaml/v2 v2.4.2 // indirect
|
||||
golang.org/x/net v0.41.0 // indirect
|
||||
golang.org/x/text v0.27.0 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
k8s.io/klog/v2 v2.130.1 // indirect
|
||||
k8s.io/utils v0.0.0-20250321185631-1f6e0b77f77e // indirect
|
||||
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect
|
||||
sigs.k8s.io/randfill v1.0.0 // indirect
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.7.0 // indirect
|
||||
sigs.k8s.io/yaml v1.4.0 // indirect
|
||||
sigs.k8s.io/yaml v1.5.0 // indirect
|
||||
)
|
||||
|
|
39
api/go.sum
39
api/go.sum
|
@ -2,10 +2,10 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3
|
|||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/fluxcd/pkg/apis/kustomize v1.10.0 h1:47EeSzkQvlQZdH92vHMe2lK2iR8aOSEJq95avw5idts=
|
||||
github.com/fluxcd/pkg/apis/kustomize v1.10.0/go.mod h1:UsqMV4sqNa1Yg0pmTsdkHRJr7bafBOENIJoAN+3ezaQ=
|
||||
github.com/fluxcd/pkg/apis/meta v1.12.0 h1:XW15TKZieC2b7MN8VS85stqZJOx+/b8jATQ/xTUhVYg=
|
||||
github.com/fluxcd/pkg/apis/meta v1.12.0/go.mod h1:+son1Va60x2eiDcTwd7lcctbI6C+K3gM7R+ULmEq1SI=
|
||||
github.com/fluxcd/pkg/apis/kustomize v1.11.0 h1:0IzDgxZkc4v+5SDNCvgZhfwfkdkQLPXCner7TNaJFWE=
|
||||
github.com/fluxcd/pkg/apis/kustomize v1.11.0/go.mod h1:j302mJGDww8cn9qvMsRQ0LJ1HPAPs/IlX7CSsoJV7BI=
|
||||
github.com/fluxcd/pkg/apis/meta v1.18.0 h1:ACHrMIjlcioE9GKS7NGk62KX4NshqNewr8sBwMcXABs=
|
||||
github.com/fluxcd/pkg/apis/meta v1.18.0/go.mod h1:97l3hTwBpJbXBY+wetNbqrUsvES8B1jGioKcBUxmqd8=
|
||||
github.com/fxamacker/cbor/v2 v2.8.0 h1:fFtUGXUzXPHTIUdne5+zzMPTfffl3RD5qYnkY40vtxU=
|
||||
github.com/fxamacker/cbor/v2 v2.8.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
|
||||
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
||||
|
@ -53,6 +53,10 @@ github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
|
|||
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI=
|
||||
go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU=
|
||||
go.yaml.in/yaml/v3 v3.0.3 h1:bXOww4E/J3f66rav3pX3m8w6jDE4knZjGOw8b5Y6iNE=
|
||||
go.yaml.in/yaml/v3 v3.0.3/go.mod h1:tBHosrYAkRZjRAOREWbDnBXUf08JOwYq++0QNwQiWzI=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
|
@ -62,8 +66,8 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn
|
|||
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=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=
|
||||
golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=
|
||||
golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw=
|
||||
golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
|
@ -74,14 +78,14 @@ golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
|
|||
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=
|
||||
golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=
|
||||
golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4=
|
||||
golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.33.0 h1:4qz2S3zmRxbGIhDIAgjxvFutSvH5EfnsYrRBj0UI0bc=
|
||||
golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI=
|
||||
golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo=
|
||||
golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg=
|
||||
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=
|
||||
|
@ -93,12 +97,12 @@ gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
|
|||
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
k8s.io/api v0.33.0 h1:yTgZVn1XEe6opVpP1FylmNrIFWuDqe2H0V8CT5gxfIU=
|
||||
k8s.io/api v0.33.0/go.mod h1:CTO61ECK/KU7haa3qq8sarQ0biLq2ju405IZAd9zsiM=
|
||||
k8s.io/apiextensions-apiserver v0.33.0 h1:d2qpYL7Mngbsc1taA4IjJPRJ9ilnsXIrndH+r9IimOs=
|
||||
k8s.io/apiextensions-apiserver v0.33.0/go.mod h1:VeJ8u9dEEN+tbETo+lFkwaaZPg6uFKLGj5vyNEwwSzc=
|
||||
k8s.io/apimachinery v0.33.0 h1:1a6kHrJxb2hs4t8EE5wuR/WxKDwGN1FKH3JvDtA0CIQ=
|
||||
k8s.io/apimachinery v0.33.0/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM=
|
||||
k8s.io/api v0.33.2 h1:YgwIS5jKfA+BZg//OQhkJNIfie/kmRsO0BmNaVSimvY=
|
||||
k8s.io/api v0.33.2/go.mod h1:fhrbphQJSM2cXzCWgqU29xLDuks4mu7ti9vveEnpSXs=
|
||||
k8s.io/apiextensions-apiserver v0.33.2 h1:6gnkIbngnaUflR3XwE1mCefN3YS8yTD631JXQhsU6M8=
|
||||
k8s.io/apiextensions-apiserver v0.33.2/go.mod h1:IvVanieYsEHJImTKXGP6XCOjTwv2LUMos0YWc9O+QP8=
|
||||
k8s.io/apimachinery v0.33.2 h1:IHFVhqg59mb8PJWTLi8m1mAoepkUNYmptHsV+Z1m5jY=
|
||||
k8s.io/apimachinery v0.33.2/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM=
|
||||
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
|
||||
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
|
||||
k8s.io/utils v0.0.0-20250321185631-1f6e0b77f77e h1:KqK5c/ghOm8xkHYhlodbp6i6+r+ChV2vuAuVRdFbLro=
|
||||
|
@ -112,5 +116,6 @@ sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU=
|
|||
sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.7.0 h1:qPeWmscJcXP0snki5IYF79Z8xrl8ETFxgMd7wez1XkI=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.7.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps=
|
||||
sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
|
||||
sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=
|
||||
sigs.k8s.io/yaml v1.5.0 h1:M10b2U7aEUY6hRtU870n2VTPgR5RZiL/I6Lcc2F4NUQ=
|
||||
sigs.k8s.io/yaml v1.5.0/go.mod h1:wZs27Rbxoai4C0f8/9urLZtZtF3avA3gKvGyPdDqTO4=
|
||||
|
|
|
@ -49,11 +49,11 @@ type KustomizationSpec struct {
|
|||
// +optional
|
||||
CommonMetadata *CommonMetadata `json:"commonMetadata,omitempty"`
|
||||
|
||||
// DependsOn may contain a meta.NamespacedObjectReference slice
|
||||
// DependsOn may contain a DependencyReference slice
|
||||
// with references to Kustomization resources that must be ready before this
|
||||
// Kustomization can be reconciled.
|
||||
// +optional
|
||||
DependsOn []meta.NamespacedObjectReference `json:"dependsOn,omitempty"`
|
||||
DependsOn []DependencyReference `json:"dependsOn,omitempty"`
|
||||
|
||||
// Decrypt Kubernetes secrets before applying them on the cluster.
|
||||
// +optional
|
||||
|
@ -333,9 +333,19 @@ func (in Kustomization) GetDeletionPolicy() string {
|
|||
return in.Spec.DeletionPolicy
|
||||
}
|
||||
|
||||
// GetDependsOn returns the list of dependencies across-namespaces.
|
||||
// GetDependsOn returns the dependencies as a list of meta.NamespacedObjectReference.
|
||||
//
|
||||
// This function makes the Kustomization type conformant with the meta.ObjectWithDependencies interface
|
||||
// and allows the controller-runtime to index Kustomizations by their dependencies.
|
||||
func (in Kustomization) GetDependsOn() []meta.NamespacedObjectReference {
|
||||
return in.Spec.DependsOn
|
||||
deps := make([]meta.NamespacedObjectReference, len(in.Spec.DependsOn))
|
||||
for i := range in.Spec.DependsOn {
|
||||
deps[i] = meta.NamespacedObjectReference{
|
||||
Name: in.Spec.DependsOn[i].Name,
|
||||
Namespace: in.Spec.DependsOn[i].Namespace,
|
||||
}
|
||||
}
|
||||
return deps
|
||||
}
|
||||
|
||||
// GetConditions returns the status conditions of the object.
|
||||
|
|
|
@ -16,7 +16,9 @@ limitations under the License.
|
|||
|
||||
package v1
|
||||
|
||||
import "fmt"
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// CrossNamespaceSourceReference contains enough information to let you locate the
|
||||
// typed Kubernetes resource object at cluster level.
|
||||
|
@ -40,9 +42,31 @@ type CrossNamespaceSourceReference struct {
|
|||
Namespace string `json:"namespace,omitempty"`
|
||||
}
|
||||
|
||||
// String returns a string representation of the CrossNamespaceSourceReference
|
||||
// in the format "Kind/Name" or "Kind/Namespace/Name" if Namespace is set.
|
||||
func (s *CrossNamespaceSourceReference) String() string {
|
||||
if s.Namespace != "" {
|
||||
return fmt.Sprintf("%s/%s/%s", s.Kind, s.Namespace, s.Name)
|
||||
}
|
||||
return fmt.Sprintf("%s/%s", s.Kind, s.Name)
|
||||
}
|
||||
|
||||
// DependencyReference defines a Kustomization dependency on another Kustomization resource.
|
||||
type DependencyReference struct {
|
||||
// Name of the referent.
|
||||
// +required
|
||||
Name string `json:"name"`
|
||||
|
||||
// Namespace of the referent, defaults to the namespace of the Kustomization
|
||||
// resource object that contains the reference.
|
||||
// +optional
|
||||
Namespace string `json:"namespace,omitempty"`
|
||||
|
||||
// ReadyExpr is a CEL expression that can be used to assess the readiness
|
||||
// of a dependency. When specified, the built-in readiness check
|
||||
// is replaced by the logic defined in the CEL expression.
|
||||
// To make the CEL expression additive to the built-in readiness check,
|
||||
// the feature gate `AdditiveCELDependencyCheck` must be set to `true`.
|
||||
// +optional
|
||||
ReadyExpr string `json:"readyExpr,omitempty"`
|
||||
}
|
||||
|
|
|
@ -91,6 +91,21 @@ func (in *Decryption) DeepCopy() *Decryption {
|
|||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *DependencyReference) DeepCopyInto(out *DependencyReference) {
|
||||
*out = *in
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DependencyReference.
|
||||
func (in *DependencyReference) DeepCopy() *DependencyReference {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(DependencyReference)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Kustomization) DeepCopyInto(out *Kustomization) {
|
||||
*out = *in
|
||||
|
@ -160,7 +175,7 @@ func (in *KustomizationSpec) DeepCopyInto(out *KustomizationSpec) {
|
|||
}
|
||||
if in.DependsOn != nil {
|
||||
in, out := &in.DependsOn, &out.DependsOn
|
||||
*out = make([]meta.NamespacedObjectReference, len(*in))
|
||||
*out = make([]DependencyReference, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.Decryption != nil {
|
||||
|
@ -177,7 +192,7 @@ func (in *KustomizationSpec) DeepCopyInto(out *KustomizationSpec) {
|
|||
if in.KubeConfig != nil {
|
||||
in, out := &in.KubeConfig, &out.KubeConfig
|
||||
*out = new(meta.KubeConfigReference)
|
||||
**out = **in
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.PostBuild != nil {
|
||||
in, out := &in.PostBuild, &out.PostBuild
|
||||
|
|
|
@ -178,7 +178,7 @@ func (in *KustomizationSpec) DeepCopyInto(out *KustomizationSpec) {
|
|||
if in.KubeConfig != nil {
|
||||
in, out := &in.KubeConfig, &out.KubeConfig
|
||||
*out = new(meta.KubeConfigReference)
|
||||
**out = **in
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.PostBuild != nil {
|
||||
in, out := &in.PostBuild, &out.PostBuild
|
||||
|
|
|
@ -123,20 +123,28 @@ spec:
|
|||
type: string
|
||||
dependsOn:
|
||||
description: |-
|
||||
DependsOn may contain a meta.NamespacedObjectReference slice
|
||||
DependsOn may contain a DependencyReference slice
|
||||
with references to Kustomization resources that must be ready before this
|
||||
Kustomization can be reconciled.
|
||||
items:
|
||||
description: |-
|
||||
NamespacedObjectReference contains enough information to locate the referenced Kubernetes resource object in any
|
||||
namespace.
|
||||
description: DependencyReference defines a Kustomization dependency
|
||||
on another Kustomization resource.
|
||||
properties:
|
||||
name:
|
||||
description: Name of the referent.
|
||||
type: string
|
||||
namespace:
|
||||
description: Namespace of the referent, when not specified it
|
||||
acts as LocalObjectReference.
|
||||
description: |-
|
||||
Namespace of the referent, defaults to the namespace of the Kustomization
|
||||
resource object that contains the reference.
|
||||
type: string
|
||||
readyExpr:
|
||||
description: |-
|
||||
ReadyExpr is a CEL expression that can be used to assess the readiness
|
||||
of a dependency. When specified, the built-in readiness check
|
||||
is replaced by the logic defined in the CEL expression.
|
||||
To make the CEL expression additive to the built-in readiness check,
|
||||
the feature gate `AdditiveCELDependencyCheck` must be set to `true`.
|
||||
type: string
|
||||
required:
|
||||
- name
|
||||
|
@ -256,16 +264,54 @@ spec:
|
|||
a controller level fallback for when KustomizationSpec.ServiceAccountName
|
||||
is empty.
|
||||
properties:
|
||||
configMapRef:
|
||||
description: |-
|
||||
ConfigMapRef holds an optional name of a ConfigMap that contains
|
||||
the following keys:
|
||||
|
||||
- `provider`: the provider to use. One of `aws`, `azure`, `gcp`, or
|
||||
`generic`. Required.
|
||||
- `cluster`: the fully qualified resource name of the Kubernetes
|
||||
cluster in the cloud provider API. Not used by the `generic`
|
||||
provider. Required when one of `address` or `ca.crt` is not set.
|
||||
- `address`: the address of the Kubernetes API server. Required
|
||||
for `generic`. For the other providers, if not specified, the
|
||||
first address in the cluster resource will be used, and if
|
||||
specified, it must match one of the addresses in the cluster
|
||||
resource.
|
||||
If audiences is not set, will be used as the audience for the
|
||||
`generic` provider.
|
||||
- `ca.crt`: the optional PEM-encoded CA certificate for the
|
||||
Kubernetes API server. If not set, the controller will use the
|
||||
CA certificate from the cluster resource.
|
||||
- `audiences`: the optional audiences as a list of
|
||||
line-break-separated strings for the Kubernetes ServiceAccount
|
||||
token. Defaults to the `address` for the `generic` provider, or
|
||||
to specific values for the other providers depending on the
|
||||
provider.
|
||||
- `serviceAccountName`: the optional name of the Kubernetes
|
||||
ServiceAccount in the same namespace that should be used
|
||||
for authentication. If not specified, the controller
|
||||
ServiceAccount will be used.
|
||||
|
||||
Mutually exclusive with SecretRef.
|
||||
properties:
|
||||
name:
|
||||
description: Name of the referent.
|
||||
type: string
|
||||
required:
|
||||
- name
|
||||
type: object
|
||||
secretRef:
|
||||
description: |-
|
||||
SecretRef holds the name of a secret that contains a key with
|
||||
SecretRef holds an optional name of a secret that contains a key with
|
||||
the kubeconfig file as the value. If no key is set, the key will default
|
||||
to 'value'.
|
||||
to 'value'. Mutually exclusive with ConfigMapRef.
|
||||
It is recommended that the kubeconfig is self-contained, and the secret
|
||||
is regularly updated if credentials such as a cloud-access-token expire.
|
||||
Cloud specific `cmd-path` auth helpers will not function without adding
|
||||
binaries and credentials to the Pod that is responsible for reconciling
|
||||
Kubernetes resources.
|
||||
Kubernetes resources. Supported only for the generic provider.
|
||||
properties:
|
||||
key:
|
||||
description: Key in the Secret, when not specified an implementation-specific
|
||||
|
@ -277,9 +323,14 @@ spec:
|
|||
required:
|
||||
- name
|
||||
type: object
|
||||
required:
|
||||
- secretRef
|
||||
type: object
|
||||
x-kubernetes-validations:
|
||||
- message: exactly one of spec.kubeConfig.configMapRef or spec.kubeConfig.secretRef
|
||||
must be specified
|
||||
rule: has(self.configMapRef) || has(self.secretRef)
|
||||
- message: exactly one of spec.kubeConfig.configMapRef or spec.kubeConfig.secretRef
|
||||
must be specified
|
||||
rule: '!has(self.configMapRef) || !has(self.secretRef)'
|
||||
namePrefix:
|
||||
description: NamePrefix will prefix the names of all managed resources.
|
||||
maxLength: 200
|
||||
|
@ -1347,16 +1398,54 @@ spec:
|
|||
a controller level fallback for when KustomizationSpec.ServiceAccountName
|
||||
is empty.
|
||||
properties:
|
||||
configMapRef:
|
||||
description: |-
|
||||
ConfigMapRef holds an optional name of a ConfigMap that contains
|
||||
the following keys:
|
||||
|
||||
- `provider`: the provider to use. One of `aws`, `azure`, `gcp`, or
|
||||
`generic`. Required.
|
||||
- `cluster`: the fully qualified resource name of the Kubernetes
|
||||
cluster in the cloud provider API. Not used by the `generic`
|
||||
provider. Required when one of `address` or `ca.crt` is not set.
|
||||
- `address`: the address of the Kubernetes API server. Required
|
||||
for `generic`. For the other providers, if not specified, the
|
||||
first address in the cluster resource will be used, and if
|
||||
specified, it must match one of the addresses in the cluster
|
||||
resource.
|
||||
If audiences is not set, will be used as the audience for the
|
||||
`generic` provider.
|
||||
- `ca.crt`: the optional PEM-encoded CA certificate for the
|
||||
Kubernetes API server. If not set, the controller will use the
|
||||
CA certificate from the cluster resource.
|
||||
- `audiences`: the optional audiences as a list of
|
||||
line-break-separated strings for the Kubernetes ServiceAccount
|
||||
token. Defaults to the `address` for the `generic` provider, or
|
||||
to specific values for the other providers depending on the
|
||||
provider.
|
||||
- `serviceAccountName`: the optional name of the Kubernetes
|
||||
ServiceAccount in the same namespace that should be used
|
||||
for authentication. If not specified, the controller
|
||||
ServiceAccount will be used.
|
||||
|
||||
Mutually exclusive with SecretRef.
|
||||
properties:
|
||||
name:
|
||||
description: Name of the referent.
|
||||
type: string
|
||||
required:
|
||||
- name
|
||||
type: object
|
||||
secretRef:
|
||||
description: |-
|
||||
SecretRef holds the name of a secret that contains a key with
|
||||
SecretRef holds an optional name of a secret that contains a key with
|
||||
the kubeconfig file as the value. If no key is set, the key will default
|
||||
to 'value'.
|
||||
to 'value'. Mutually exclusive with ConfigMapRef.
|
||||
It is recommended that the kubeconfig is self-contained, and the secret
|
||||
is regularly updated if credentials such as a cloud-access-token expire.
|
||||
Cloud specific `cmd-path` auth helpers will not function without adding
|
||||
binaries and credentials to the Pod that is responsible for reconciling
|
||||
Kubernetes resources.
|
||||
Kubernetes resources. Supported only for the generic provider.
|
||||
properties:
|
||||
key:
|
||||
description: Key in the Secret, when not specified an implementation-specific
|
||||
|
@ -1368,9 +1457,14 @@ spec:
|
|||
required:
|
||||
- name
|
||||
type: object
|
||||
required:
|
||||
- secretRef
|
||||
type: object
|
||||
x-kubernetes-validations:
|
||||
- message: exactly one of spec.kubeConfig.configMapRef or spec.kubeConfig.secretRef
|
||||
must be specified
|
||||
rule: has(self.configMapRef) || has(self.secretRef)
|
||||
- message: exactly one of spec.kubeConfig.configMapRef or spec.kubeConfig.secretRef
|
||||
must be specified
|
||||
rule: '!has(self.configMapRef) || !has(self.secretRef)'
|
||||
patches:
|
||||
description: |-
|
||||
Strategic merge and JSON patches, defined as inline YAML objects,
|
||||
|
|
|
@ -89,14 +89,14 @@ overridden if its key matches a common one.</p>
|
|||
<td>
|
||||
<code>dependsOn</code><br>
|
||||
<em>
|
||||
<a href="https://godoc.org/github.com/fluxcd/pkg/apis/meta#NamespacedObjectReference">
|
||||
[]github.com/fluxcd/pkg/apis/meta.NamespacedObjectReference
|
||||
<a href="#kustomize.toolkit.fluxcd.io/v1.DependencyReference">
|
||||
[]DependencyReference
|
||||
</a>
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>DependsOn may contain a meta.NamespacedObjectReference slice
|
||||
<p>DependsOn may contain a DependencyReference slice
|
||||
with references to Kustomization resources that must be ready before this
|
||||
Kustomization can be reconciled.</p>
|
||||
</td>
|
||||
|
@ -609,6 +609,67 @@ field.</p>
|
|||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<h3 id="kustomize.toolkit.fluxcd.io/v1.DependencyReference">DependencyReference
|
||||
</h3>
|
||||
<p>
|
||||
(<em>Appears on:</em>
|
||||
<a href="#kustomize.toolkit.fluxcd.io/v1.KustomizationSpec">KustomizationSpec</a>)
|
||||
</p>
|
||||
<p>DependencyReference defines a Kustomization dependency on another Kustomization resource.</p>
|
||||
<div class="md-typeset__scrollwrap">
|
||||
<div class="md-typeset__table">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Field</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<code>name</code><br>
|
||||
<em>
|
||||
string
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<p>Name of the referent.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>namespace</code><br>
|
||||
<em>
|
||||
string
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>Namespace of the referent, defaults to the namespace of the Kustomization
|
||||
resource object that contains the reference.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>readyExpr</code><br>
|
||||
<em>
|
||||
string
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>ReadyExpr is a CEL expression that can be used to assess the readiness
|
||||
of a dependency. When specified, the built-in readiness check
|
||||
is replaced by the logic defined in the CEL expression.
|
||||
To make the CEL expression additive to the built-in readiness check,
|
||||
the feature gate <code>AdditiveCELDependencyCheck</code> must be set to <code>true</code>.</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<h3 id="kustomize.toolkit.fluxcd.io/v1.KustomizationSpec">KustomizationSpec
|
||||
</h3>
|
||||
<p>
|
||||
|
@ -647,14 +708,14 @@ overridden if its key matches a common one.</p>
|
|||
<td>
|
||||
<code>dependsOn</code><br>
|
||||
<em>
|
||||
<a href="https://godoc.org/github.com/fluxcd/pkg/apis/meta#NamespacedObjectReference">
|
||||
[]github.com/fluxcd/pkg/apis/meta.NamespacedObjectReference
|
||||
<a href="#kustomize.toolkit.fluxcd.io/v1.DependencyReference">
|
||||
[]DependencyReference
|
||||
</a>
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>DependsOn may contain a meta.NamespacedObjectReference slice
|
||||
<p>DependsOn may contain a DependencyReference slice
|
||||
with references to Kustomization resources that must be ready before this
|
||||
Kustomization can be reconciled.</p>
|
||||
</td>
|
||||
|
|
|
@ -487,6 +487,51 @@ is running before deploying applications inside the mesh.
|
|||
**Note:** Circular dependencies between Kustomizations must be avoided,
|
||||
otherwise the interdependent Kustomizations will never be applied on the cluster.
|
||||
|
||||
#### Dependency Ready Expression
|
||||
|
||||
`.spec.dependsOn[].readyExpr` is an optional field that can be used to define a CEL expression
|
||||
to determine the readiness of a Kustomization dependency.
|
||||
|
||||
This is helpful for when custom logic is needed to determine if a dependency is ready.
|
||||
For example, when performing a lockstep upgrade, the `readyExpr` can be used to
|
||||
verify that a dependency has a matching version label before proceeding with the
|
||||
reconciliation of the dependent Kustomization.
|
||||
|
||||
```yaml
|
||||
apiVersion: kustomize.toolkit.fluxcd.io/v1
|
||||
kind: Kustomization
|
||||
metadata:
|
||||
name: app-backend
|
||||
namespace: apps
|
||||
labels:
|
||||
app/version: v1.2.3
|
||||
---
|
||||
apiVersion: kustomize.toolkit.fluxcd.io/v1
|
||||
kind: Kustomization
|
||||
metadata:
|
||||
name: app-frontend
|
||||
namespace: apps
|
||||
labels:
|
||||
app/version: v1.2.3
|
||||
spec:
|
||||
dependsOn:
|
||||
- name: app-backend
|
||||
readyExpr: >
|
||||
dep.metadata.labels['app/version'] == self.metadata.labels['app/version'] &&
|
||||
dep.status.conditions.filter(e, e.type == 'Ready').all(e, e.status == 'True') &&
|
||||
dep.metadata.generation == dep.status.observedGeneration
|
||||
```
|
||||
|
||||
The CEL expression contains the following variables:
|
||||
|
||||
- `dep`: The dependency Kustomization object being evaluated.
|
||||
- `self`: The Kustomization object being reconciled.
|
||||
|
||||
**Note:** When `readyExpr` is specified, the built-in readiness check is replaced by the logic
|
||||
defined in the CEL expression. You can configure the controller to run both the CEL expression
|
||||
evaluation and the built-in readiness check, with the `AdditiveCELDependencyCheck`
|
||||
[feature gate](https://fluxcd.io/flux/components/kustomize/options/#feature-gates).
|
||||
|
||||
### Service Account reference
|
||||
|
||||
`.spec.serviceAccountName` is an optional field used to specify the
|
||||
|
@ -639,6 +684,10 @@ With `.spec.postBuild.substituteFrom` you can provide a list of ConfigMaps and
|
|||
Secrets from which the variables are loaded. The ConfigMap and Secret data keys
|
||||
are used as the variable names.
|
||||
|
||||
To make a Kustomization react immediately to changes in the referenced Secret
|
||||
or ConfigMap see [this](#reacting-immediately-to-configuration-dependencies)
|
||||
section.
|
||||
|
||||
The `.spec.postBuild.substituteFrom.optional` field indicates how the
|
||||
controller should handle a referenced ConfigMap or Secret being absent
|
||||
at reconciliation time. The controller's default behavior ― with
|
||||
|
@ -699,7 +748,7 @@ spec:
|
|||
# Fail if this Secret does not exist.
|
||||
```
|
||||
|
||||
**Note:** For substituting variables in a secret, `.spec.stringData` field must be used i.e:
|
||||
For substituting variables in a secret, `.spec.stringData` field must be used i.e:
|
||||
|
||||
```yaml
|
||||
---
|
||||
|
@ -713,11 +762,11 @@ stringData:
|
|||
token: ${token}
|
||||
```
|
||||
|
||||
**Note:** The var values which are specified in-line with `substitute`
|
||||
The var values which are specified in-line with `substitute`
|
||||
take precedence over the ones derived from `substituteFrom`.
|
||||
When var values for the same variable keys are derived from multiple
|
||||
`ConfigMaps` or `Secrets` referenced in the `substituteFrom` list, then the
|
||||
first take precedence over the later values.
|
||||
`ConfigMaps` or `Secrets` referenced in the `substituteFrom` list,
|
||||
the later values overwrite earlier values.
|
||||
|
||||
**Note:** If you want to avoid var substitutions in scripts embedded in
|
||||
ConfigMaps or container commands, you must use the format `$var` instead of
|
||||
|
@ -791,14 +840,44 @@ with:
|
|||
kustomize.toolkit.fluxcd.io/force: enabled
|
||||
```
|
||||
|
||||
### KubeConfig reference
|
||||
### KubeConfig (Remote clusters)
|
||||
|
||||
With the `.spec.kubeConfig` field a Kustomization
|
||||
can apply and manage resources on a remote cluster.
|
||||
|
||||
Two authentication alternatives are available:
|
||||
|
||||
- `.spec.kubeConfig.secretRef`: Secret-based authentication using a
|
||||
static kubeconfig stored in a Kubernetes Secret in the same namespace
|
||||
as the Kustomization.
|
||||
- `.spec.kubeConfig.configMapRef` (Recommended): Secret-less authentication
|
||||
building a kubeconfig dynamically with parameters stored in a Kubernetes
|
||||
ConfigMap in the same namespace as the Kustomization via workload identity.
|
||||
|
||||
To make a Kustomization react immediately to changes in the referenced Secret
|
||||
or ConfigMap see [this](#reacting-immediately-to-configuration-dependencies)
|
||||
section.
|
||||
|
||||
When both `.spec.kubeConfig` and
|
||||
[`.spec.serviceAccountName`](#service-account-reference) are specified,
|
||||
the controller will impersonate the ServiceAccount on the target cluster,
|
||||
i.e. a ServiceAccount with name `.spec.serviceAccountName` must exist in
|
||||
the target cluster inside a namespace with the same name as the namespace
|
||||
of the Kustomization. For example, if the Kustomization is in the namespace
|
||||
`apps` of the cluster where Flux is running, then the ServiceAccount
|
||||
must be in the `apps` namespace of the target remote cluster, and have the
|
||||
name `.spec.serviceAccountName`. In other words, the namespace of the
|
||||
Kustomization must exist both in the cluster where Flux is running
|
||||
and in the target remote cluster where Flux will apply resources.
|
||||
|
||||
#### Secret-based authentication
|
||||
|
||||
`.spec.kubeConfig.secretRef.Name` is an optional field to specify the name of
|
||||
the secret containing a KubeConfig. If specified, objects will be applied,
|
||||
health-checked, pruned, and deleted for the default cluster specified in that
|
||||
KubeConfig instead of using the in-cluster ServiceAccount.
|
||||
|
||||
The secret defined in the `kubeConfig.SecretRef` must exist in the same
|
||||
The secret defined in the `.spec.kubeConfig.secretRef` must exist in the same
|
||||
namespace as the Kustomization. On every reconciliation, the KubeConfig bytes
|
||||
will be loaded from the `.secretRef.key` key (default: `value` or `value.yaml`)
|
||||
of the Secret’s data , and the Secret can thus be regularly updated if
|
||||
|
@ -822,12 +901,88 @@ stringData:
|
|||
environment, or credential files from the kustomize-controller Pod.
|
||||
This matches the constraints of KubeConfigs from current Cluster API providers.
|
||||
KubeConfigs with `cmd-path` in them likely won't work without a custom,
|
||||
per-provider installation of kustomize-controller.
|
||||
per-provider installation of kustomize-controller. For more information, see
|
||||
[remote clusters/Cluster-API](#remote-cluster-api-clusters).
|
||||
|
||||
When both `.spec.kubeConfig` and `.spec.ServiceAccountName` are specified,
|
||||
the controller will impersonate the service account on the target cluster.
|
||||
#### Secret-less authentication
|
||||
|
||||
For more information, see [remote clusters/Cluster-API](#remote-clusterscluster-api).
|
||||
The field `.spec.kubeConfig.configMapRef.name` can be used to specify the
|
||||
name of a ConfigMap in the same namespace as the Kustomization containing
|
||||
parameters for secret-less authentication via workload identity. The
|
||||
supported keys inside the `.data` field of the ConfigMap are:
|
||||
|
||||
- `.data.provider`: The provider to use. One of `aws`, `azure`, `gcp`,
|
||||
or `generic`. Required. The `aws` provider is used for connecting to
|
||||
remote EKS clusters, `azure` for AKS, `gcp` for GKE, and `generic`
|
||||
for Kubernetes OIDC authentication between clusters. For the
|
||||
`generic` provider, the remote cluster must be configured to trust
|
||||
the OIDC issuer of the cluster where Flux is running.
|
||||
- `.data.cluster`: The fully qualified resource name of the Kubernetes
|
||||
cluster in the cloud provider API. Not used by the `generic`
|
||||
provider. Required when one of `.data.address` or `.data["ca.crt"]` is
|
||||
not set, or if the provider is `aws` (required for defining a region).
|
||||
- `.data.address`: The address of the Kubernetes API server. Required
|
||||
for `generic`. For the other providers, if not specified, the
|
||||
first address in the cluster resource will be used, and if
|
||||
specified, it must match one of the addresses in the cluster
|
||||
resource.
|
||||
If `audiences` is not set, will be used as the audience for the
|
||||
`generic` provider.
|
||||
- `.data["ca.crt"]`: The optional PEM-encoded CA certificate for the
|
||||
Kubernetes API server. If not set, the controller will use the
|
||||
CA certificate from the cluster resource.
|
||||
- `.data.audiences`: The optional audiences as a list of
|
||||
line-break-separated strings for the Kubernetes ServiceAccount token.
|
||||
Defaults to the address for the `generic` provider, or to specific
|
||||
values for the other providers depending on the provider.
|
||||
- `.data.serviceAccountName`: The optional name of the Kubernetes
|
||||
ServiceAccount in the same namespace that should be used
|
||||
for authentication. If not specified, the controller
|
||||
ServiceAccount will be used. Not confuse with the ServiceAccount
|
||||
used for impersonation, which is specified with
|
||||
[`.spec.serviceAccountName`](#service-account-reference) directly
|
||||
in the Kustomization spec and must exist in the target remote cluster.
|
||||
|
||||
The `.data.cluster` field, when specified, must have the following formats:
|
||||
|
||||
- `aws`: `arn:<partition>:eks:<region>:<account-id>:cluster/<cluster-name>`
|
||||
- `azure`: `/subscriptions/<subscription-id>/resourceGroups/<resource-group>/providers/Microsoft.ContainerService/managedClusters/<cluster-name>`
|
||||
- `gcp`: `projects/<project-id>/locations/<location>/clusters/<cluster-name>`
|
||||
|
||||
For complete guides on workload identity and setting up permissions for
|
||||
this feature, see the following docs:
|
||||
|
||||
- [EKS](/flux/integrations/aws/#for-amazon-elastic-kubernetes-service)
|
||||
- [AKS](/flux/integrations/azure/#for-azure-kubernetes-service)
|
||||
- [GKE](/flux/integrations/gcp/#for-google-kubernetes-engine)
|
||||
- [Generic](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#configuring-the-api-server)
|
||||
|
||||
Example for an EKS cluster:
|
||||
|
||||
```yaml
|
||||
apiVersion: kustomize.toolkit.fluxcd.io/v1
|
||||
kind: Kustomization
|
||||
metadata:
|
||||
name: backend
|
||||
namespace: apps
|
||||
spec:
|
||||
... # other fields omitted for brevity
|
||||
kubeConfig:
|
||||
configMapRef:
|
||||
name: kubeconfig
|
||||
serviceAccountName: apps-sa # optional. must exist in the target cluster. user for impersonation
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: kubeconfig
|
||||
namespace: apps
|
||||
data:
|
||||
kubeConfig:
|
||||
provider: aws
|
||||
cluster: arn:aws:eks:eu-central-1:123456789012:cluster/my-cluster
|
||||
serviceAccountName: apps-iam-role # optional. maps to an AWS IAM Role. used for authentication
|
||||
```
|
||||
|
||||
### Decryption
|
||||
|
||||
|
@ -856,6 +1011,9 @@ The `.spec.decryption` field has the following subfields:
|
|||
- `.serviceAccountName`: The name of the service account used for
|
||||
secret-less authentication with KMS services from cloud providers.
|
||||
|
||||
To make a Kustomization react immediately to changes in the referenced Secret
|
||||
see [this](#reacting-immediately-to-configuration-dependencies) section.
|
||||
|
||||
For a complete guide on how to set up authentication for KMS services from
|
||||
cloud providers, see the integration [docs](/flux/integrations/).
|
||||
|
||||
|
@ -1353,9 +1511,9 @@ When the flag is set, all Kustomizations which don't have [`.spec.serviceAccount
|
|||
specified will use the service account name provided by
|
||||
`--default-service-account=<SA Name>` in the namespace of the object.
|
||||
|
||||
### Remote clusters/Cluster-API
|
||||
### Remote Cluster API clusters
|
||||
|
||||
With the [`.spec.kubeConfig` field](#kubeconfig-reference) a Kustomization can be fully
|
||||
Using a [`.spec.kubeConfig` reference](#kubeconfig-remote-clusters) a Kustomization can be fully
|
||||
reconciled on a remote cluster. This composes well with Cluster API bootstrap
|
||||
providers such as CAPBK (kubeadm), CAPA (AWS) and others.
|
||||
|
||||
|
@ -1430,155 +1588,24 @@ Kustomization object itself, it will fall back to these defaults.
|
|||
|
||||
See also the [workload identity](/flux/installation/configuration/workload-identity/) docs.
|
||||
|
||||
#### AWS KMS
|
||||
#### Cloud Provider KMS Services
|
||||
|
||||
While making use of the [IAM OIDC provider](https://eksctl.io/usage/iamserviceaccounts/)
|
||||
on your EKS cluster, you can create an IAM Role and Service Account with access
|
||||
to AWS KMS (using at least `kms:Decrypt` and `kms:DescribeKey`). Once these are
|
||||
created, you can annotate the kustomize-controller Service Account with the
|
||||
Role ARN, granting the controller permission to decrypt the Secrets. Please refer
|
||||
to the [SOPS guide](https://fluxcd.io/flux/guides/mozilla-sops/#aws) for detailed steps.
|
||||
For cloud provider KMS services, please refer to the specific sections in the integration guides:
|
||||
|
||||
```sh
|
||||
kubectl -n flux-system annotate serviceaccount kustomize-controller \
|
||||
--field-manager=flux-client-side-apply \
|
||||
eks.amazonaws.com/role-arn='arn:aws:iam::<ACCOUNT_ID>:role/<KMS-ROLE-NAME>'
|
||||
```
|
||||
Service-specific configuration:
|
||||
|
||||
Furthermore, you can also use the usual [environment variables used for specifying AWS
|
||||
credentials](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-envvars.html#envvars-list),
|
||||
by patching the kustomize-controller Deployment:
|
||||
- [AWS KMS](https://fluxcd.io/flux/integrations/aws/#for-amazon-key-management-service)
|
||||
- [Azure Key Vault](https://fluxcd.io/flux/integrations/azure/#for-azure-key-vault)
|
||||
- [GCP KMS](https://fluxcd.io/flux/integrations/gcp/#for-google-cloud-key-management-service)
|
||||
|
||||
```yaml
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: kustomize-controller
|
||||
namespace: flux-system
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: manager
|
||||
env:
|
||||
- name: AWS_ACCESS_KEY_ID
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: aws-creds
|
||||
key: awsAccessKeyID
|
||||
- name: AWS_SECRET_ACCESS_KEY
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: aws-creds
|
||||
key: awsSecretAccessKey
|
||||
- name: AWS_SESSION_TOKEN
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: aws-creds
|
||||
key: awsSessionToken
|
||||
```
|
||||
Controller-level configuration:
|
||||
|
||||
In addition to this, the
|
||||
[general SOPS documentation around KMS AWS applies](https://github.com/mozilla/sops#27kms-aws-profiles),
|
||||
allowing you to specify e.g. a `SOPS_KMS_ARN` environment variable.
|
||||
- [AWS](https://fluxcd.io/flux/integrations/aws/#at-the-controller-level)
|
||||
- [Azure](https://fluxcd.io/flux/integrations/azure/#at-the-controller-level)
|
||||
- [GCP](https://fluxcd.io/flux/integrations/gcp/#at-the-controller-level)
|
||||
|
||||
**Note:**: If you are mounting a secret containing the AWS credentials as a
|
||||
file in the `kustomize-controller` Pod, you need to specify an environment
|
||||
variable `$HOME`, since the AWS credentials file is expected to be present at
|
||||
`~/.aws`. For example:
|
||||
|
||||
```yaml
|
||||
env:
|
||||
- name: HOME
|
||||
value: /home/{$USER}
|
||||
```
|
||||
|
||||
#### Azure Key Vault
|
||||
|
||||
##### Workload Identity
|
||||
|
||||
If you have Workload Identity set up on your AKS cluster, you can establish
|
||||
a federated identity between the kustomize-controller ServiceAccount and an
|
||||
identity that has "Decrypt" role on the Azure Key Vault. Once, this is done
|
||||
you can label and annotate the kustomize-controller ServiceAccount and Pod
|
||||
with the patch shown below:
|
||||
|
||||
```yaml
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
resources:
|
||||
- gotk-components.yaml
|
||||
- gotk-sync.yaml
|
||||
patches:
|
||||
- patch: |-
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: kustomize-controller
|
||||
namespace: flux-system
|
||||
annotations:
|
||||
azure.workload.identity/client-id: <AZURE_CLIENT_ID>
|
||||
labels:
|
||||
azure.workload.identity/use: "true"
|
||||
- patch: |-
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: kustomize-controller
|
||||
namespace: flux-system
|
||||
labels:
|
||||
azure.workload.identity/use: "true"
|
||||
spec:
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
azure.workload.identity/use: "true"
|
||||
```
|
||||
|
||||
##### Kubelet Identity
|
||||
|
||||
If the kubelet managed identity has `Decrypt` permissions on Azure Key Vault,
|
||||
no additional configuration is required for the kustomize-controller to decrypt
|
||||
data.
|
||||
|
||||
#### GCP KMS
|
||||
|
||||
While making use of Google Cloud Platform, the [`GOOGLE_APPLICATION_CREDENTIALS`
|
||||
environment variable](https://cloud.google.com/docs/authentication/production)
|
||||
is automatically taken into account.
|
||||
[Granting permissions](https://cloud.google.com/kms/docs/reference/permissions-and-roles)
|
||||
to the Service Account attached to this will therefore be sufficient to decrypt
|
||||
data. When running outside GCP, it is possible to manually patch the
|
||||
kustomize-controller Deployment with a valid set of (mounted) credentials.
|
||||
|
||||
```yaml
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: kustomize-controller
|
||||
namespace: flux-system
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: manager
|
||||
env:
|
||||
- name: GOOGLE_APPLICATION_CREDENTIALS
|
||||
value: /var/gcp/credentials.json
|
||||
volumeMounts:
|
||||
- name: gcp-credentials
|
||||
mountPath: /var/gcp/
|
||||
readOnly: true
|
||||
volumes:
|
||||
- name: gcp-credentials
|
||||
secret:
|
||||
secretName: mysecret
|
||||
items:
|
||||
- key: credentials
|
||||
path: credentials.json
|
||||
```
|
||||
These guides provide detailed instructions for setting up authentication,
|
||||
permissions, and controller configuration for each cloud provider.
|
||||
|
||||
#### Hashicorp Vault
|
||||
|
||||
|
@ -1602,6 +1629,48 @@ spec:
|
|||
value: <token>
|
||||
```
|
||||
|
||||
#### SOPS Age Keys
|
||||
|
||||
To configure global decryption for SOPS Age keys, use the `--sops-age-secret`
|
||||
controller flag to specify a Kubernetes Secret containing the Age private keys.
|
||||
|
||||
First, create a Secret containing the Age private keys with the `.agekey` suffix:
|
||||
|
||||
```yaml
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: sops-age-keys
|
||||
namespace: flux-system
|
||||
stringData:
|
||||
identity1.agekey: <identity1 key>
|
||||
identity2.agekey: <identity1 key>
|
||||
```
|
||||
|
||||
The Secret must be in the same namespace as the kustomize-controller Deployment.
|
||||
|
||||
Then, patch the kustomize-controller Deployment to add the `--sops-age-secret` flag:
|
||||
|
||||
```yaml
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: kustomize-controller
|
||||
namespace: flux-system
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: manager
|
||||
args:
|
||||
- --sops-age-secret=sops-age-keys
|
||||
```
|
||||
|
||||
The field `.spec.decryption.secretRef` in the Kustomization will take precedence
|
||||
in case both the controller flag and the Kustomization field are set.
|
||||
|
||||
### Kustomize secretGenerator
|
||||
|
||||
SOPS encrypted data can be stored as a base64 encoded Secret, which enables the
|
||||
|
@ -1897,6 +1966,29 @@ the controller. The Flux CLI offer commands for filtering the logs for a
|
|||
specific Kustomization, e.g.
|
||||
`flux logs --level=error --kind=Kustomization --name=<kustomization-name>`.
|
||||
|
||||
### Reacting immediately to configuration dependencies
|
||||
|
||||
To trigger a reconciliation when changes occur in referenced
|
||||
Secrets or ConfigMaps, you can set the following label on the
|
||||
Secret or ConfigMap:
|
||||
|
||||
```yaml
|
||||
metadata:
|
||||
labels:
|
||||
reconcile.fluxcd.io/watch: Enabled
|
||||
```
|
||||
|
||||
An alternative to labeling every Secret or ConfigMap is
|
||||
setting the `--watch-configs-label-selector=owner!=helm`
|
||||
[flag](https://fluxcd.io/flux/components/kustomize/options/#flags)
|
||||
in kustomize-controller, which allows watching all Secrets and
|
||||
ConfigMaps except for Helm storage Secrets.
|
||||
|
||||
**Note**: A reconciliation will be triggered for an event on a
|
||||
referenced Secret/ConfigMap even if it's marked as optional in
|
||||
the `.spec.postBuild.substituteFrom` field, including deletion
|
||||
events.
|
||||
|
||||
## Kustomization Status
|
||||
|
||||
### Conditions
|
||||
|
|
171
go.mod
171
go.mod
|
@ -9,69 +9,72 @@ replace github.com/fluxcd/kustomize-controller/api => ./api
|
|||
replace github.com/opencontainers/go-digest => github.com/opencontainers/go-digest v1.0.1-0.20220411205349-bde1400a84be
|
||||
|
||||
require (
|
||||
cloud.google.com/go/kms v1.21.2
|
||||
cloud.google.com/go/kms v1.22.0
|
||||
filippo.io/age v1.2.1
|
||||
github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.0
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.9.0
|
||||
github.com/aws/aws-sdk-go-v2 v1.36.3
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.67
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.1
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.10.1
|
||||
github.com/aws/aws-sdk-go-v2 v1.36.5
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.70
|
||||
github.com/cyphar/filepath-securejoin v0.4.1
|
||||
github.com/dimchansky/utfbom v1.1.1
|
||||
github.com/fluxcd/cli-utils v0.36.0-flux.13
|
||||
github.com/fluxcd/cli-utils v0.36.0-flux.14
|
||||
github.com/fluxcd/kustomize-controller/api v1.6.0
|
||||
github.com/fluxcd/pkg/apis/acl v0.7.0
|
||||
github.com/fluxcd/pkg/apis/event v0.17.0
|
||||
github.com/fluxcd/pkg/apis/kustomize v1.10.0
|
||||
github.com/fluxcd/pkg/apis/meta v1.12.0
|
||||
github.com/fluxcd/pkg/auth v0.16.0
|
||||
github.com/fluxcd/pkg/cache v0.9.0
|
||||
github.com/fluxcd/pkg/http/fetch v0.16.0
|
||||
github.com/fluxcd/pkg/kustomize v1.18.0
|
||||
github.com/fluxcd/pkg/runtime v0.60.0
|
||||
github.com/fluxcd/pkg/ssa v0.48.0
|
||||
github.com/fluxcd/pkg/tar v0.12.0
|
||||
github.com/fluxcd/pkg/apis/acl v0.8.0
|
||||
github.com/fluxcd/pkg/apis/event v0.18.0
|
||||
github.com/fluxcd/pkg/apis/kustomize v1.11.0
|
||||
github.com/fluxcd/pkg/apis/meta v1.18.0
|
||||
github.com/fluxcd/pkg/auth v0.23.0
|
||||
github.com/fluxcd/pkg/cache v0.10.0
|
||||
github.com/fluxcd/pkg/http/fetch v0.17.0
|
||||
github.com/fluxcd/pkg/kustomize v1.19.0
|
||||
github.com/fluxcd/pkg/runtime v0.72.0
|
||||
github.com/fluxcd/pkg/ssa v0.51.0
|
||||
github.com/fluxcd/pkg/tar v0.13.0
|
||||
github.com/fluxcd/pkg/testserver v0.11.0
|
||||
github.com/fluxcd/source-controller/api v1.6.0
|
||||
github.com/getsops/sops/v3 v3.10.2
|
||||
github.com/hashicorp/vault/api v1.16.0
|
||||
github.com/google/cel-go v0.23.2
|
||||
github.com/hashicorp/vault/api v1.20.0
|
||||
github.com/onsi/gomega v1.37.0
|
||||
github.com/opencontainers/go-digest v1.0.0
|
||||
github.com/ory/dockertest/v3 v3.12.0
|
||||
github.com/spf13/pflag v1.0.6
|
||||
golang.org/x/net v0.40.0
|
||||
golang.org/x/net v0.42.0
|
||||
golang.org/x/oauth2 v0.30.0
|
||||
k8s.io/api v0.33.0
|
||||
k8s.io/apimachinery v0.33.0
|
||||
k8s.io/client-go v0.33.0
|
||||
k8s.io/utils v0.0.0-20250321185631-1f6e0b77f77e
|
||||
k8s.io/api v0.33.2
|
||||
k8s.io/apimachinery v0.33.2
|
||||
k8s.io/client-go v0.33.2
|
||||
k8s.io/utils v0.0.0-20250604170112-4c0f3b243397
|
||||
sigs.k8s.io/controller-runtime v0.21.0
|
||||
sigs.k8s.io/kustomize/api v0.19.0
|
||||
sigs.k8s.io/yaml v1.4.0
|
||||
sigs.k8s.io/kustomize/api v0.20.0
|
||||
sigs.k8s.io/yaml v1.5.0
|
||||
)
|
||||
|
||||
// Pin kustomize to v5.6.0
|
||||
// Pin kustomize to v5.7.0
|
||||
replace (
|
||||
sigs.k8s.io/kustomize/api => sigs.k8s.io/kustomize/api v0.19.0
|
||||
sigs.k8s.io/kustomize/kyaml => sigs.k8s.io/kustomize/kyaml v0.19.0
|
||||
sigs.k8s.io/kustomize/api => sigs.k8s.io/kustomize/api v0.20.0
|
||||
sigs.k8s.io/kustomize/kyaml => sigs.k8s.io/kustomize/kyaml v0.20.0
|
||||
)
|
||||
|
||||
// Fix CVE-2022-28948
|
||||
replace gopkg.in/yaml.v3 => gopkg.in/yaml.v3 v3.0.1
|
||||
|
||||
require (
|
||||
cel.dev/expr v0.22.1 // indirect
|
||||
cel.dev/expr v0.23.0 // indirect
|
||||
cloud.google.com/go v0.120.1 // indirect
|
||||
cloud.google.com/go/auth v0.16.1 // indirect
|
||||
cloud.google.com/go/auth v0.16.2 // indirect
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect
|
||||
cloud.google.com/go/compute/metadata v0.6.0 // indirect
|
||||
cloud.google.com/go/compute/metadata v0.7.0 // indirect
|
||||
cloud.google.com/go/iam v1.5.2 // indirect
|
||||
cloud.google.com/go/longrunning v0.6.7 // indirect
|
||||
cloud.google.com/go/monitoring v1.24.2 // indirect
|
||||
cloud.google.com/go/storage v1.51.0 // indirect
|
||||
dario.cat/mergo v1.0.1 // indirect
|
||||
filippo.io/edwards25519 v1.1.0 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/containers/azcontainerregistry v0.2.3 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/containerservice/armcontainerservice v1.0.0 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.3.1 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.1.1 // indirect
|
||||
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect
|
||||
|
@ -85,38 +88,41 @@ require (
|
|||
github.com/ProtonMail/go-crypto v1.2.0 // indirect
|
||||
github.com/antlr4-go/antlr/v4 v4.13.0 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.10 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/config v1.29.14 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.30 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/config v1.29.17 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.32 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.72 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.36 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.36 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.34 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ecr v1.43.3 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ecr v1.45.1 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.33.2 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/eks v1.66.1 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.4 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.7.0 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.15 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.17 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.15 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/kms v1.38.3 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.79.2 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.25.3 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.1 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.33.19 // indirect
|
||||
github.com/aws/smithy-go v1.22.3 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.25.5 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.3 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.34.0 // indirect
|
||||
github.com/aws/smithy-go v1.22.4 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/blang/semver v3.5.1+incompatible // indirect
|
||||
github.com/blang/semver/v4 v4.0.0 // indirect
|
||||
github.com/carapace-sh/carapace-shlex v1.0.1 // indirect
|
||||
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/chai2010/gettext-go v1.0.3 // indirect
|
||||
github.com/cloudflare/circl v1.6.1 // indirect
|
||||
github.com/cncf/xds/go v0.0.0-20250326154945-ae57f3c0d45f // indirect
|
||||
github.com/containerd/continuity v0.4.5 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.6 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.7 // indirect
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/docker/cli v28.1.1+incompatible // indirect
|
||||
github.com/docker/docker v28.1.1+incompatible // indirect
|
||||
github.com/docker/docker-credential-helpers v0.8.2 // indirect
|
||||
github.com/docker/cli v28.2.2+incompatible // indirect
|
||||
github.com/docker/docker v28.2.2+incompatible // indirect
|
||||
github.com/docker/docker-credential-helpers v0.9.3 // indirect
|
||||
github.com/docker/go-connections v0.5.0 // indirect
|
||||
github.com/docker/go-units v0.5.0 // indirect
|
||||
github.com/emicklei/go-restful/v3 v3.12.2 // indirect
|
||||
|
@ -127,46 +133,45 @@ require (
|
|||
github.com/fatih/color v1.18.0 // indirect
|
||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||
github.com/fluxcd/pkg/envsubst v1.4.0 // indirect
|
||||
github.com/fluxcd/pkg/sourceignore v0.12.0 // indirect
|
||||
github.com/fluxcd/pkg/sourceignore v0.13.0 // indirect
|
||||
github.com/fsnotify/fsnotify v1.9.0 // indirect
|
||||
github.com/fxamacker/cbor/v2 v2.8.0 // indirect
|
||||
github.com/getsops/gopgagent v0.0.0-20241224165529-7044f28e491e // indirect
|
||||
github.com/go-errors/errors v1.5.1 // indirect
|
||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
|
||||
github.com/go-git/go-billy/v5 v5.6.2 // indirect
|
||||
github.com/go-git/go-git/v5 v5.16.0 // indirect
|
||||
github.com/go-git/go-git/v5 v5.16.2 // indirect
|
||||
github.com/go-jose/go-jose/v4 v4.1.0 // indirect
|
||||
github.com/go-logr/logr v1.4.2 // indirect
|
||||
github.com/go-logr/logr v1.4.3 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/go-logr/zapr v1.3.0 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.21.1 // indirect
|
||||
github.com/go-openapi/jsonreference v0.21.0 // indirect
|
||||
github.com/go-openapi/swag v0.23.1 // indirect
|
||||
github.com/go-viper/mapstructure/v2 v2.2.1 // indirect
|
||||
github.com/go-viper/mapstructure/v2 v2.4.0 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang-jwt/jwt/v5 v5.2.2 // indirect
|
||||
github.com/google/btree v1.1.3 // indirect
|
||||
github.com/google/cel-go v0.23.2 // indirect
|
||||
github.com/google/gnostic-models v0.6.9 // indirect
|
||||
github.com/google/gnostic-models v0.7.0 // indirect
|
||||
github.com/google/go-cmp v0.7.0 // indirect
|
||||
github.com/google/go-containerregistry v0.20.3 // indirect
|
||||
github.com/google/go-containerregistry v0.20.6 // indirect
|
||||
github.com/google/s2a-go v0.1.9 // indirect
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.6 // indirect
|
||||
github.com/googleapis/gax-go/v2 v2.14.1 // indirect
|
||||
github.com/googleapis/gax-go/v2 v2.14.2 // indirect
|
||||
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 // indirect
|
||||
github.com/goware/prefixer v0.0.0-20160118172347-395022866408 // indirect
|
||||
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect
|
||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||
github.com/hashicorp/go-retryablehttp v0.7.7 // indirect
|
||||
github.com/hashicorp/go-retryablehttp v0.7.8 // indirect
|
||||
github.com/hashicorp/go-rootcerts v1.0.2 // indirect
|
||||
github.com/hashicorp/go-secure-stdlib/parseutil v0.2.0 // indirect
|
||||
github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect
|
||||
github.com/hashicorp/go-sockaddr v1.0.7 // indirect
|
||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||
github.com/hashicorp/hcl v1.0.1-vault-7 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
|
@ -199,8 +204,8 @@ require (
|
|||
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect
|
||||
github.com/prometheus/client_golang v1.22.0 // indirect
|
||||
github.com/prometheus/client_model v0.6.2 // indirect
|
||||
github.com/prometheus/common v0.63.0 // indirect
|
||||
github.com/prometheus/procfs v0.16.1 // indirect
|
||||
github.com/prometheus/common v0.65.0 // indirect
|
||||
github.com/prometheus/procfs v0.17.0 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/ryanuber/go-glob v1.0.0 // indirect
|
||||
github.com/sirupsen/logrus v1.9.3 // indirect
|
||||
|
@ -217,42 +222,44 @@ require (
|
|||
github.com/zeebo/errs v1.4.0 // indirect
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
|
||||
go.opentelemetry.io/contrib/detectors/gcp v1.35.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 // indirect
|
||||
go.opentelemetry.io/otel v1.35.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.35.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk v1.35.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk/metric v1.35.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.35.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 // indirect
|
||||
go.opentelemetry.io/otel v1.37.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.37.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk v1.36.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk/metric v1.36.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.37.0 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
go.uber.org/zap v1.27.0 // indirect
|
||||
golang.org/x/crypto v0.38.0 // indirect
|
||||
go.yaml.in/yaml/v2 v2.4.2 // indirect
|
||||
go.yaml.in/yaml/v3 v3.0.4 // indirect
|
||||
golang.org/x/crypto v0.40.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 // indirect
|
||||
golang.org/x/sync v0.14.0 // indirect
|
||||
golang.org/x/sys v0.33.0 // indirect
|
||||
golang.org/x/term v0.32.0 // indirect
|
||||
golang.org/x/text v0.25.0 // indirect
|
||||
golang.org/x/time v0.11.0 // indirect
|
||||
golang.org/x/sync v0.16.0 // indirect
|
||||
golang.org/x/sys v0.34.0 // indirect
|
||||
golang.org/x/term v0.33.0 // indirect
|
||||
golang.org/x/text v0.27.0 // indirect
|
||||
golang.org/x/time v0.12.0 // indirect
|
||||
gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect
|
||||
google.golang.org/api v0.230.0 // indirect
|
||||
google.golang.org/genproto v0.0.0-20250425173222-7b384671a197 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250425173222-7b384671a197 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250425173222-7b384671a197 // indirect
|
||||
google.golang.org/grpc v1.72.0 // indirect
|
||||
google.golang.org/api v0.241.0 // indirect
|
||||
google.golang.org/genproto v0.0.0-20250505200425-f936aa4a68b2 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250505200425-f936aa4a68b2 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 // indirect
|
||||
google.golang.org/grpc v1.73.0 // indirect
|
||||
google.golang.org/protobuf v1.36.6 // indirect
|
||||
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
gopkg.in/warnings.v0 v0.1.2 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
k8s.io/apiextensions-apiserver v0.33.0 // indirect
|
||||
k8s.io/cli-runtime v0.33.0 // indirect
|
||||
k8s.io/component-base v0.33.0 // indirect
|
||||
k8s.io/apiextensions-apiserver v0.33.2 // indirect
|
||||
k8s.io/cli-runtime v0.33.2 // indirect
|
||||
k8s.io/component-base v0.33.2 // indirect
|
||||
k8s.io/klog/v2 v2.130.1 // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff // indirect
|
||||
k8s.io/kubectl v0.33.0 // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20250701173324-9bd5c66d9911 // indirect
|
||||
k8s.io/kubectl v0.33.2 // indirect
|
||||
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect
|
||||
sigs.k8s.io/kustomize/kyaml v0.19.0 // indirect
|
||||
sigs.k8s.io/kustomize/kyaml v0.20.0 // indirect
|
||||
sigs.k8s.io/randfill v1.0.0 // indirect
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.7.0 // indirect
|
||||
)
|
||||
|
|
336
go.sum
336
go.sum
|
@ -1,19 +1,19 @@
|
|||
c2sp.org/CCTV/age v0.0.0-20240306222714-3ec4d716e805 h1:u2qwJeEvnypw+OCPUHmoZE3IqwfuN5kgDfo5MLzpNM0=
|
||||
c2sp.org/CCTV/age v0.0.0-20240306222714-3ec4d716e805/go.mod h1:FomMrUJ2Lxt5jCLmZkG3FHa72zUprnhd3v/Z18Snm4w=
|
||||
cel.dev/expr v0.22.1 h1:xoFEsNh972Yzey8N9TCPx2nDvMN7TMhQEzxLuj/iRrI=
|
||||
cel.dev/expr v0.22.1/go.mod h1:MrpN08Q+lEBs+bGYdLxxHkZoUSsCp0nSKTs0nTymJgw=
|
||||
cel.dev/expr v0.23.0 h1:wUb94w6OYQS4uXraxo9U+wUAs9jT47Xvl4iPgAwM2ss=
|
||||
cel.dev/expr v0.23.0/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw=
|
||||
cloud.google.com/go v0.120.1 h1:Z+5V7yd383+9617XDCyszmK5E4wJRJL+tquMfDj9hLM=
|
||||
cloud.google.com/go v0.120.1/go.mod h1:56Vs7sf/i2jYM6ZL9NYlC82r04PThNcPS5YgFmb0rp8=
|
||||
cloud.google.com/go/auth v0.16.1 h1:XrXauHMd30LhQYVRHLGvJiYeczweKQXZxsTbV9TiguU=
|
||||
cloud.google.com/go/auth v0.16.1/go.mod h1:1howDHJ5IETh/LwYs3ZxvlkXF48aSqqJUM+5o02dNOI=
|
||||
cloud.google.com/go/auth v0.16.2 h1:QvBAGFPLrDeoiNjyfVunhQ10HKNYuOwZ5noee0M5df4=
|
||||
cloud.google.com/go/auth v0.16.2/go.mod h1:sRBas2Y1fB1vZTdurouM0AzuYQBMZinrUYL8EufhtEA=
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc=
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c=
|
||||
cloud.google.com/go/compute/metadata v0.6.0 h1:A6hENjEsCDtC1k8byVsgwvVcioamEHvZ4j01OwKxG9I=
|
||||
cloud.google.com/go/compute/metadata v0.6.0/go.mod h1:FjyFAW1MW0C203CEOMDTu3Dk1FlqW3Rga40jzHL4hfg=
|
||||
cloud.google.com/go/compute/metadata v0.7.0 h1:PBWF+iiAerVNe8UCHxdOt6eHLVc3ydFeOCw78U8ytSU=
|
||||
cloud.google.com/go/compute/metadata v0.7.0/go.mod h1:j5MvL9PprKL39t166CoB1uVHfQMs4tFQZZcKwksXUjo=
|
||||
cloud.google.com/go/iam v1.5.2 h1:qgFRAGEmd8z6dJ/qyEchAuL9jpswyODjA2lS+w234g8=
|
||||
cloud.google.com/go/iam v1.5.2/go.mod h1:SE1vg0N81zQqLzQEwxL2WI6yhetBdbNQuTvIKCSkUHE=
|
||||
cloud.google.com/go/kms v1.21.2 h1:c/PRUSMNQ8zXrc1sdAUnsenWWaNXN+PzTXfXOcSFdoE=
|
||||
cloud.google.com/go/kms v1.21.2/go.mod h1:8wkMtHV/9Z8mLXEXr1GK7xPSBdi6knuLXIhqjuWcI6w=
|
||||
cloud.google.com/go/kms v1.22.0 h1:dBRIj7+GDeeEvatJeTB19oYZNV0aj6wEqSIT/7gLqtk=
|
||||
cloud.google.com/go/kms v1.22.0/go.mod h1:U7mf8Sva5jpOb4bxYZdtw/9zsbIjrklYwPcvMk34AL8=
|
||||
cloud.google.com/go/logging v1.13.0 h1:7j0HgAp0B94o1YRDqiqm26w4q1rDMH7XNRU34lJXHYc=
|
||||
cloud.google.com/go/logging v1.13.0/go.mod h1:36CoKh6KA/M0PbhPKMq6/qety2DCAErbhXT62TuXALA=
|
||||
cloud.google.com/go/longrunning v0.6.7 h1:IGtfDWHhQCgCjwQjV9iiLnUta9LBCo8R9QmAFsS/PrE=
|
||||
|
@ -32,14 +32,18 @@ filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
|
|||
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
|
||||
github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6 h1:He8afgbRMd7mFxO99hRNu+6tazq8nFF9lIwo9JFroBk=
|
||||
github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.0 h1:Gt0j3wceWMwPmiazCa8MzMA0MfhmPIz0Qp0FJ6qcM0U=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.0/go.mod h1:Ot/6aikWnKWi4l9QB7qVSwa8iMphQNqkWALMoNT3rzM=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.9.0 h1:OVoM452qUFBrX+URdH3VpR299ma4kfom0yB0URYky9g=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.9.0/go.mod h1:kUjrAo8bgEwLeZ/CmHqNl3Z/kPm7y6FKfxxK0izYUg4=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.1 h1:Wc1ml6QlJs2BHQ/9Bqu1jiyggbsSjramq2oUmp5WeIo=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.1/go.mod h1:Ot/6aikWnKWi4l9QB7qVSwa8iMphQNqkWALMoNT3rzM=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.10.1 h1:B+blDbyVIG3WaikNxPnhPiJ1MThR03b3vKGtER95TP4=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.10.1/go.mod h1:JdM5psgjfBf5fo2uWOZhflPWyDBZ/O/CNAH9CtsuZE4=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.2 h1:yz1bePFlP5Vws5+8ez6T3HWXPmwOK7Yvq8QxDBD3SKY=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.2/go.mod h1:Pa9ZNPuoNu/GztvBSKk9J1cDJW6vk/n0zLtV4mgd8N8=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/containers/azcontainerregistry v0.2.3 h1:ldKsKtEIblsgsr6mPwrd9yRntoX6uLz/K89wsldwx/k=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/containers/azcontainerregistry v0.2.3/go.mod h1:MAm7bk0oDLmD8yIkvfbxPW04fxzphPyL+7GzwHxOp6Y=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1 h1:FPKJS1T+clwv+OLGt13a8UjqeRuh0O4SJ3lUriThc+4=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1/go.mod h1:j2chePtV91HrC22tGoRX3sGY42uF13WzmmV80/OdVAA=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/containerservice/armcontainerservice v1.0.0 h1:figxyQZXzZQIcP3njhC68bYUiTw45J8/SsHaLW8Ax0M=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/containerservice/armcontainerservice v1.0.0/go.mod h1:TmlMW4W5OvXOmOyKNnor8nlMMiO1ctIyzmHme/VHsrA=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.3.1 h1:Wgf5rZba3YZqeTNJPtvqZoBu1sBN/L4sry+u2U3Y75w=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.3.1/go.mod h1:xxCBG/f/4Vbmh2XQJBsOmNdxWUY5j/s27jujKPbQf14=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.1.1 h1:bFWuoEKg+gImo7pvkiQEFAc8ocibADgXeiLAxWhWmkI=
|
||||
|
@ -71,54 +75,60 @@ github.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8
|
|||
github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g=
|
||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
|
||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
|
||||
github.com/aws/aws-sdk-go-v2 v1.36.3 h1:mJoei2CxPutQVxaATCzDUjcZEjVRdpsiiXi2o38yqWM=
|
||||
github.com/aws/aws-sdk-go-v2 v1.36.3/go.mod h1:LLXuLpgzEbD766Z5ECcRmi8AzSwfZItDtmABVkRLGzg=
|
||||
github.com/aws/aws-sdk-go-v2 v1.36.5 h1:0OF9RiEMEdDdZEMqF9MRjevyxAQcf6gY+E7vwBILFj0=
|
||||
github.com/aws/aws-sdk-go-v2 v1.36.5/go.mod h1:EYrzvCCN9CMUTa5+6lf6MM4tq3Zjp8UhSGR/cBsjai0=
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.10 h1:zAybnyUQXIZ5mok5Jqwlf58/TFE7uvd3IAsa1aF9cXs=
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.10/go.mod h1:qqvMj6gHLR/EXWZw4ZbqlPbQUyenf4h82UQUlKc+l14=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.29.14 h1:f+eEi/2cKCg9pqKBoAIwRGzVb70MRKqWX4dg1BDcSJM=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.29.14/go.mod h1:wVPHWcIFv3WO89w0rE10gzf17ZYy+UVS1Geq8Iei34g=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.67 h1:9KxtdcIA/5xPNQyZRgUSpYOE6j9Bc4+D7nZua0KGYOM=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.67/go.mod h1:p3C44m+cfnbv763s52gCqrjaqyPikj9Sg47kUVaNZQQ=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.30 h1:x793wxmUWVDhshP8WW2mlnXuFrO4cOd3HLBroh1paFw=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.30/go.mod h1:Jpne2tDnYiFascUEs2AWHJL9Yp7A5ZVy3TNyxaAjD6M=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.29.17 h1:jSuiQ5jEe4SAMH6lLRMY9OVC+TqJLP5655pBGjmnjr0=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.29.17/go.mod h1:9P4wwACpbeXs9Pm9w1QTh6BwWwJjwYvJ1iCt5QbCXh8=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.70 h1:ONnH5CM16RTXRkS8Z1qg7/s2eDOhHhaXVd72mmyv4/0=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.70/go.mod h1:M+lWhhmomVGgtuPOhO85u4pEa3SmssPTdcYpP/5J/xc=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.32 h1:KAXP9JSHO1vKGCr5f4O6WmlVKLFFXgWYAGoJosorxzU=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.32/go.mod h1:h4Sg6FQdexC1yYG9RDnOvLbW1a/P986++/Y/a+GyEM8=
|
||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.72 h1:PcKMOZfp+kNtJTw2HF2op6SjDvwPBYRvz0Y24PQLUR4=
|
||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.72/go.mod h1:vq7/m7dahFXcdzWVOvvjasDI9RcsD3RsTfHmDundJYg=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34 h1:ZK5jHhnrioRkUNOc+hOgQKlUL5JeC3S6JgLxtQ+Rm0Q=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34/go.mod h1:p4VfIceZokChbA9FzMbRGz5OV+lekcVtHlPKEO0gSZY=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34 h1:SZwFm17ZUNNg5Np0ioo/gq8Mn6u9w19Mri8DnJ15Jf0=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34/go.mod h1:dFZsC0BLo346mvKQLWmoJxT+Sjp+qcVR1tRVHQGOH9Q=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.36 h1:SsytQyTMHMDPspp+spo7XwXTP44aJZZAC7fBV2C5+5s=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.36/go.mod h1:Q1lnJArKRXkenyog6+Y+zr7WDpk4e6XlR6gs20bbeNo=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.36 h1:i2vNHQiXUvKhs3quBR6aqlgJaiaexz/aNvdCktW/kAM=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.36/go.mod h1:UdyGa7Q91id/sdyHPwth+043HhmP6yP9MBHgbZM0xo8=
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 h1:bIqFDwgGXXN1Kpp99pDOdKMTTb5d2KyU5X/BZxjOkRo=
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3/go.mod h1:H5O/EsxDWyU+LP/V8i5sm8cxoZgc2fdNR9bxlOFrQTo=
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.34 h1:ZNTqv4nIdE/DiBfUUfXcLZ/Spcuz+RjeziUtNJackkM=
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.34/go.mod h1:zf7Vcd1ViW7cPqYWEHLHJkS50X0JS2IKz9Cgaj6ugrs=
|
||||
github.com/aws/aws-sdk-go-v2/service/ecr v1.43.3 h1:YyH8Hk73bYzdbvf6S8NF5z/fb/1stpiMnFSfL6jSfRA=
|
||||
github.com/aws/aws-sdk-go-v2/service/ecr v1.43.3/go.mod h1:iQ1skgw1XRK+6Lgkb0I9ODatAP72WoTILh0zXQ5DtbU=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3 h1:eAh2A4b5IzM/lum78bZ590jy36+d/aFLgKF/4Vd1xPE=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3/go.mod h1:0yKJC/kb8sAnmlYa6Zs3QVYqaC8ug2AbnNChv5Ox3uA=
|
||||
github.com/aws/aws-sdk-go-v2/service/ecr v1.45.1 h1:Bwzh202Aq7/MYnAjXA9VawCf6u+hjwMdoYmZ4HYsdf8=
|
||||
github.com/aws/aws-sdk-go-v2/service/ecr v1.45.1/go.mod h1:xZzWl9AXYa6zsLLH41HBFW8KRKJRIzlGmvSM0mVMIX4=
|
||||
github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.33.2 h1:XJ/AEFYj9VFPJdF+VFi4SUPEDfz1akHwxxm07JfZJcs=
|
||||
github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.33.2/go.mod h1:JUBHdhvKbbKmhaHjLsKJAWnQL80T6nURmhB/LEprV+4=
|
||||
github.com/aws/aws-sdk-go-v2/service/eks v1.66.1 h1:sD1y3G4WXw1GjK95L5dBXPFXNWl/O8GMradUojUYqCg=
|
||||
github.com/aws/aws-sdk-go-v2/service/eks v1.66.1/go.mod h1:Qj90srO2HigGG5x8Ro6RxixxqiSjZjF91WTEVpnsjAs=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.4 h1:CXV68E2dNqhuynZJPB80bhPQwAKqBWVer887figW6Jc=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.4/go.mod h1:/xFi9KtvBXP97ppCz1TAEvU1Uf66qvid89rbem3wCzQ=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.7.0 h1:lguz0bmOoGzozP9XfRJR1QIayEYo+2vP/No3OfLF0pU=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.7.0/go.mod h1:iu6FSzgt+M2/x3Dk8zhycdIcHjEFb36IS8HVUVFoMg0=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.15 h1:dM9/92u2F1JbDaGooxTq18wmmFzbJRfXfVfy96/1CXM=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.15/go.mod h1:SwFBy2vjtA0vZbjjaFtfN045boopadnoVPhu4Fv66vY=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.17 h1:t0E6FzREdtCsiLIoLCWsYliNsRBgyGD/MCK571qk4MI=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.17/go.mod h1:ygpklyoaypuyDvOM5ujWGrYWpAK3h7ugnmKCU/76Ys4=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.15 h1:moLQUoVq91LiqT1nbvzDukyqAlCv89ZmwaHw/ZFlFZg=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.15/go.mod h1:ZH34PJUc8ApjBIfgQCFvkWcUDBtl/WTD+uiYHjd8igA=
|
||||
github.com/aws/aws-sdk-go-v2/service/kms v1.38.3 h1:RivOtUH3eEu6SWnUMFHKAW4MqDOzWn1vGQ3S38Y5QMg=
|
||||
github.com/aws/aws-sdk-go-v2/service/kms v1.38.3/go.mod h1:cQn6tAF77Di6m4huxovNM7NVAozWTZLsDRp9t8Z/WYk=
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.79.2 h1:tWUG+4wZqdMl/znThEk9tcCy8tTMxq8dW0JTgamohrY=
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.79.2/go.mod h1:U5SNqwhXB3Xe6F47kXvWihPl/ilGaEDe8HD/50Z9wxc=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.25.3 h1:1Gw+9ajCV1jogloEv1RRnvfRFia2cL6c9cuKV2Ps+G8=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.25.3/go.mod h1:qs4a9T5EMLl/Cajiw2TcbNt2UNo/Hqlyp+GiuG4CFDI=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.1 h1:hXmVKytPfTy5axZ+fYbR5d0cFmC3JvwLm5kM83luako=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.1/go.mod h1:MlYRNmYu/fGPoxBQVvBYr9nyr948aY/WLUvwBMBJubs=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.33.19 h1:1XuUZ8mYJw9B6lzAkXhqHlJd/XvaX32evhproijJEZY=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.33.19/go.mod h1:cQnB8CUnxbMU82JvlqjKR2HBOm3fe9pWorWBza6MBJ4=
|
||||
github.com/aws/smithy-go v1.22.3 h1:Z//5NuZCSW6R4PhQ93hShNbyBbn8BWCmCVCt+Q8Io5k=
|
||||
github.com/aws/smithy-go v1.22.3/go.mod h1:t1ufH5HMublsJYulve2RKmHDC15xu1f26kHCp/HgceI=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.25.5 h1:AIRJ3lfb2w/1/8wOOSqYb9fUKGwQbtysJ2H1MofRUPg=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.25.5/go.mod h1:b7SiVprpU+iGazDUqvRSLf5XmCdn+JtT1on7uNL6Ipc=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.3 h1:BpOxT3yhLwSJ77qIY3DoHAQjZsc4HEGfMCE4NGy3uFg=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.3/go.mod h1:vq/GQR1gOFLquZMSrxUK/cpvKCNVYibNyJ1m7JrU88E=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.34.0 h1:NFOJ/NXEGV4Rq//71Hs1jC/NvPs1ezajK+yQmkwnPV0=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.34.0/go.mod h1:7ph2tGpfQvwzgistp2+zga9f+bCjlQJPkPUmMgDSD7w=
|
||||
github.com/aws/smithy-go v1.22.4 h1:uqXzVZNuNexwc/xrh6Tb56u89WDlJY6HS+KC0S4QSjw=
|
||||
github.com/aws/smithy-go v1.22.4/go.mod h1:t1ufH5HMublsJYulve2RKmHDC15xu1f26kHCp/HgceI=
|
||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ=
|
||||
github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
|
||||
github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM=
|
||||
github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ=
|
||||
github.com/carapace-sh/carapace-shlex v1.0.1 h1:ww0JCgWpOVuqWG7k3724pJ18Lq8gh5pHQs9j3ojUs1c=
|
||||
github.com/carapace-sh/carapace-shlex v1.0.1/go.mod h1:lJ4ZsdxytE0wHJ8Ta9S7Qq0XpjgjU0mdfCqiI2FHx7M=
|
||||
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
|
||||
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
|
||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||
|
@ -134,8 +144,9 @@ github.com/containerd/continuity v0.4.5/go.mod h1:/lNJvtJKUQStBzpVQ1+rasXO1LAWtU
|
|||
github.com/coreos/go-oidc/v3 v3.14.1 h1:9ePWwfdwC4QKRlCXsJGou56adA/owXczOzwKdOumLqk=
|
||||
github.com/coreos/go-oidc/v3 v3.14.1/go.mod h1:HaZ3szPaZ0e4r6ebqvsLWlk2Tn+aejfmrfah6hnSYEU=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.6 h1:XJtiaUW6dEEqVuZiMTn1ldk455QWwEIsMIJlo5vtkx0=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.7 h1:zbFlGlXEAKlwXpmvle3d8Oe3YnkKIK4xSRTd3sHPnBo=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.7/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
|
||||
github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=
|
||||
github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
|
||||
github.com/cyphar/filepath-securejoin v0.4.1 h1:JyxxyPEaktOD+GAnqIqTf9A8tHyAG22rowi7HkoSU1s=
|
||||
|
@ -148,12 +159,12 @@ github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/r
|
|||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
|
||||
github.com/dimchansky/utfbom v1.1.1 h1:vV6w1AhK4VMnhBno/TPVCoK9U/LP0PkLCS9tbxHdi/U=
|
||||
github.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/j0mACtrfE=
|
||||
github.com/docker/cli v28.1.1+incompatible h1:eyUemzeI45DY7eDPuwUcmDyDj1pM98oD5MdSpiItp8k=
|
||||
github.com/docker/cli v28.1.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
||||
github.com/docker/docker v28.1.1+incompatible h1:49M11BFLsVO1gxY9UX9p/zwkE/rswggs8AdFmXQw51I=
|
||||
github.com/docker/docker v28.1.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker-credential-helpers v0.8.2 h1:bX3YxiGzFP5sOXWc3bTPEXdEaZSeVMrFgOr3T+zrFAo=
|
||||
github.com/docker/docker-credential-helpers v0.8.2/go.mod h1:P3ci7E3lwkZg6XiHdRKft1KckHiO9a2rNtyFbZ/ry9M=
|
||||
github.com/docker/cli v28.2.2+incompatible h1:qzx5BNUDFqlvyq4AHzdNB7gSyVTmU4cgsyN9SdInc1A=
|
||||
github.com/docker/cli v28.2.2+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
||||
github.com/docker/docker v28.2.2+incompatible h1:CjwRSksz8Yo4+RmQ339Dp/D2tGO5JxwYeqtMOEe0LDw=
|
||||
github.com/docker/docker v28.2.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker-credential-helpers v0.9.3 h1:gAm/VtF9wgqJMoxzT3Gj5p4AqIjCBS4wrsOh9yRqcz8=
|
||||
github.com/docker/docker-credential-helpers v0.9.3/go.mod h1:x+4Gbw9aGmChi3qTLZj8Dfn0TD20M/fuWy0E5+WDeCo=
|
||||
github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
|
||||
github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
|
||||
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
|
||||
|
@ -178,34 +189,34 @@ github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
|
|||
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
|
||||
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
|
||||
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||
github.com/fluxcd/cli-utils v0.36.0-flux.13 h1:2X5yjz/rk9mg7+bMFBDZKGKzeZpAmY2s6iwbNZz7OzM=
|
||||
github.com/fluxcd/cli-utils v0.36.0-flux.13/go.mod h1:b2iSoIeDTtjfCB0IKtGgqlhhvWa1oux3e90CjOf81oA=
|
||||
github.com/fluxcd/pkg/apis/acl v0.7.0 h1:dMhZJH+g6ZRPjs4zVOAN9vHBd1DcavFgcIFkg5ooOE0=
|
||||
github.com/fluxcd/pkg/apis/acl v0.7.0/go.mod h1:uv7pXXR/gydiX4MUwlQa7vS8JONEDztynnjTvY3JxKQ=
|
||||
github.com/fluxcd/pkg/apis/event v0.17.0 h1:foEINE++pCJlWVhWjYDXfkVmGKu8mQ4BDBlbYi5NU7M=
|
||||
github.com/fluxcd/pkg/apis/event v0.17.0/go.mod h1:0fLhLFiHlRTDKPDXdRnv+tS7mCMIQ0fJxnEfmvGM/5A=
|
||||
github.com/fluxcd/pkg/apis/kustomize v1.10.0 h1:47EeSzkQvlQZdH92vHMe2lK2iR8aOSEJq95avw5idts=
|
||||
github.com/fluxcd/pkg/apis/kustomize v1.10.0/go.mod h1:UsqMV4sqNa1Yg0pmTsdkHRJr7bafBOENIJoAN+3ezaQ=
|
||||
github.com/fluxcd/pkg/apis/meta v1.12.0 h1:XW15TKZieC2b7MN8VS85stqZJOx+/b8jATQ/xTUhVYg=
|
||||
github.com/fluxcd/pkg/apis/meta v1.12.0/go.mod h1:+son1Va60x2eiDcTwd7lcctbI6C+K3gM7R+ULmEq1SI=
|
||||
github.com/fluxcd/pkg/auth v0.16.0 h1:YEjSaNqlpYoXfoFAGhU/Z8y0322nGsT24W6zCh+sbGw=
|
||||
github.com/fluxcd/pkg/auth v0.16.0/go.mod h1:+BRnAO61Nr6fACEjJS6eNRdOk1nXhX/FCPylYn1ypNc=
|
||||
github.com/fluxcd/pkg/cache v0.9.0 h1:EGKfOLMG3fOwWnH/4Axl5xd425mxoQbZzlZoLfd8PDk=
|
||||
github.com/fluxcd/pkg/cache v0.9.0/go.mod h1:jMwabjWfsC5lW8hE7NM3wtGNwSJ38Javx6EKbEi7INU=
|
||||
github.com/fluxcd/cli-utils v0.36.0-flux.14 h1:I//AMVUXTc+M04UtIXArMXQZCazGMwfemodV1j/yG8c=
|
||||
github.com/fluxcd/cli-utils v0.36.0-flux.14/go.mod h1:uDo7BYOfbdmk/asnHuI0IQPl6u0FCgcN54AHDu3Y5As=
|
||||
github.com/fluxcd/pkg/apis/acl v0.8.0 h1:mZNl4mOQQf5/cdMCYgKcrZTZRndCtMtkI0BDfNO5kfo=
|
||||
github.com/fluxcd/pkg/apis/acl v0.8.0/go.mod h1:uv7pXXR/gydiX4MUwlQa7vS8JONEDztynnjTvY3JxKQ=
|
||||
github.com/fluxcd/pkg/apis/event v0.18.0 h1:PNbWk9gvX8gMIi6VsJapnuDO+giLEeY+6olLVXvXFkk=
|
||||
github.com/fluxcd/pkg/apis/event v0.18.0/go.mod h1:7S/DGboLolfbZ6stO6dcDhG1SfkPWQ9foCULvbiYpiA=
|
||||
github.com/fluxcd/pkg/apis/kustomize v1.11.0 h1:0IzDgxZkc4v+5SDNCvgZhfwfkdkQLPXCner7TNaJFWE=
|
||||
github.com/fluxcd/pkg/apis/kustomize v1.11.0/go.mod h1:j302mJGDww8cn9qvMsRQ0LJ1HPAPs/IlX7CSsoJV7BI=
|
||||
github.com/fluxcd/pkg/apis/meta v1.18.0 h1:ACHrMIjlcioE9GKS7NGk62KX4NshqNewr8sBwMcXABs=
|
||||
github.com/fluxcd/pkg/apis/meta v1.18.0/go.mod h1:97l3hTwBpJbXBY+wetNbqrUsvES8B1jGioKcBUxmqd8=
|
||||
github.com/fluxcd/pkg/auth v0.23.0 h1:Xt89QO1Hzh7X0JFwCeONyxMlgOX/zOPx0eyIyFoKyF0=
|
||||
github.com/fluxcd/pkg/auth v0.23.0/go.mod h1:YEAHpBFuW5oLlH9ekuJaQdnJ2Q3A7Ny8kha3WY7QMnY=
|
||||
github.com/fluxcd/pkg/cache v0.10.0 h1:M+OGDM4da1cnz7q+sZSBtkBJHpiJsLnKVmR9OdMWxEY=
|
||||
github.com/fluxcd/pkg/cache v0.10.0/go.mod h1:pPXRzQUDQagsCniuOolqVhnAkbNgYOg8d2cTliPs7ME=
|
||||
github.com/fluxcd/pkg/envsubst v1.4.0 h1:pYsb6wrmXOSfHXuXQHaaBBMt3LumhgCb8SMdBNAwV/U=
|
||||
github.com/fluxcd/pkg/envsubst v1.4.0/go.mod h1:zSDFO3Wawi+vI2NPxsMQp+EkIsz/85MNg/s1Wzmqt+s=
|
||||
github.com/fluxcd/pkg/http/fetch v0.16.0 h1:XzhBTSK5HNdAPEnEGMJHwtoN2LfqQ9QFDsu3DGzl908=
|
||||
github.com/fluxcd/pkg/http/fetch v0.16.0/go.mod h1:+A+yrOzwA5436ufD8NPeCCQFNzk4metoPUgRVCozvzw=
|
||||
github.com/fluxcd/pkg/kustomize v1.18.0 h1:wWK+qYwmBmba3N3VAqZ9ijnfVGGaIjcaHWo033URZTw=
|
||||
github.com/fluxcd/pkg/kustomize v1.18.0/go.mod h1:Ij9722MdWIE6B1EPg2ZJUf6npycgfRfN4Lohi7D/Kic=
|
||||
github.com/fluxcd/pkg/runtime v0.60.0 h1:d++EkV3FlycB+bzakB5NumwY4J8xts8i7lbvD6jBLeU=
|
||||
github.com/fluxcd/pkg/runtime v0.60.0/go.mod h1:UeU0/eZLErYC/1bTmgzBfNXhiHy9fuQzjfLK0HxRgxY=
|
||||
github.com/fluxcd/pkg/sourceignore v0.12.0 h1:jCIe6d50rQ3wdXPF0+PhhqN0XrTRIq3upMomPelI8Mw=
|
||||
github.com/fluxcd/pkg/sourceignore v0.12.0/go.mod h1:dc0zvkuXM5OgL/b3IkrVuwvPjj1zJn4NBUMH45uJ4Y0=
|
||||
github.com/fluxcd/pkg/ssa v0.48.0 h1:DW+4DG8L/yZEi30UltOEXPB1d/ZFn4HfVhpJQp5oc2o=
|
||||
github.com/fluxcd/pkg/ssa v0.48.0/go.mod h1:T50TO0U2obLodZnrFgOrxollfBEy4V673OkM2aTUF1c=
|
||||
github.com/fluxcd/pkg/tar v0.12.0 h1:og6F+ivnWNRbNJSq0ukCTVs7YrGIlzjxSVZU+E8NprM=
|
||||
github.com/fluxcd/pkg/tar v0.12.0/go.mod h1:Ra5Cj++MD5iCy7bZGKJJX3GpOeMPv+ZDkPO9bBwpDeU=
|
||||
github.com/fluxcd/pkg/http/fetch v0.17.0 h1:U/Fuh+H1cRL2d/EOfdsjJPaPDPtL3pFanPSE3HtVU1s=
|
||||
github.com/fluxcd/pkg/http/fetch v0.17.0/go.mod h1:nMozZtiSKtPGwMrR5wGjIJoQmhvFqZ5P4UsM/Lqza2I=
|
||||
github.com/fluxcd/pkg/kustomize v1.19.0 h1:2eO8lMx0/H/Yyq35LMTAMhxEElOzMW0Yi9zUNZoimlU=
|
||||
github.com/fluxcd/pkg/kustomize v1.19.0/go.mod h1:OCCW9vU3lStDh3jyg9MM/a29MSdNAVk2wjl0lDos5Fs=
|
||||
github.com/fluxcd/pkg/runtime v0.72.0 h1:9JCto84iL2FziuTuuvDwvS+cfIzGhHOk25y8ulXpNOs=
|
||||
github.com/fluxcd/pkg/runtime v0.72.0/go.mod h1:iGhdaEq+lMJQTJNAFEPOU4gUJ7kt3yeDcJPZy7O9IUw=
|
||||
github.com/fluxcd/pkg/sourceignore v0.13.0 h1:ZvkzX2WsmyZK9cjlqOFFW1onHVzhPZIqDbCh96rPqbU=
|
||||
github.com/fluxcd/pkg/sourceignore v0.13.0/go.mod h1:Z9H1GoBx0ljOhptnzoV0PL6Nd/UzwKcSphP27lqb4xI=
|
||||
github.com/fluxcd/pkg/ssa v0.51.0 h1:sFarxKZcS0J8sjq9qvs/r+1XiJqNgRodEiPjV75F8R4=
|
||||
github.com/fluxcd/pkg/ssa v0.51.0/go.mod h1:v+h9RC0JxWIqMTK2Eo+8Nh700AXyZChZ2TiLVj4tf3M=
|
||||
github.com/fluxcd/pkg/tar v0.13.0 h1:AS3FdsoJfweNQ+hZQQ3AgNPBeEEd4kKFQpR0c3lCF24=
|
||||
github.com/fluxcd/pkg/tar v0.13.0/go.mod h1:qTuvFVsL0TcYSB5kw89p7elKP307Zge7ZtWXmuEEF2s=
|
||||
github.com/fluxcd/pkg/testserver v0.11.0 h1:a/kxpFqv7XQxZjwVPP3voooRmSd/3ipLVolK0xUIxXQ=
|
||||
github.com/fluxcd/pkg/testserver v0.11.0/go.mod h1:E8LAH1jW9uClFjTRN27Y/gCCSrzNVx1/w/0NxKuNcas=
|
||||
github.com/fluxcd/source-controller/api v1.6.0 h1:IxfjUczJ2pzbXIef6iQ0RHEH4AYA9anJfTGK8dzwODM=
|
||||
|
@ -224,13 +235,13 @@ github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66D
|
|||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic=
|
||||
github.com/go-git/go-billy/v5 v5.6.2 h1:6Q86EsPXMa7c3YZ3aLAQsMA0VlWmy43r6FHqa/UNbRM=
|
||||
github.com/go-git/go-billy/v5 v5.6.2/go.mod h1:rcFC2rAsp/erv7CMz9GczHcuD0D32fWzH+MJAU+jaUU=
|
||||
github.com/go-git/go-git/v5 v5.16.0 h1:k3kuOEpkc0DeY7xlL6NaaNg39xdgQbtH5mwCafHO9AQ=
|
||||
github.com/go-git/go-git/v5 v5.16.0/go.mod h1:4Ge4alE/5gPs30F2H1esi2gPd69R0C39lolkucHBOp8=
|
||||
github.com/go-git/go-git/v5 v5.16.2 h1:fT6ZIOjE5iEnkzKyxTHK1W4HGAsPhqEqiSAssSO77hM=
|
||||
github.com/go-git/go-git/v5 v5.16.2/go.mod h1:4Ge4alE/5gPs30F2H1esi2gPd69R0C39lolkucHBOp8=
|
||||
github.com/go-jose/go-jose/v4 v4.1.0 h1:cYSYxd3pw5zd2FSXk2vGdn9igQU2PS8MuxrCOCl0FdY=
|
||||
github.com/go-jose/go-jose/v4 v4.1.0/go.mod h1:GG/vqmYm3Von2nYiB2vGTXzdoNKE5tix5tuc6iAd+sw=
|
||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
||||
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
||||
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||
github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ=
|
||||
|
@ -247,8 +258,8 @@ github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1v
|
|||
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
|
||||
github.com/go-test/deep v1.0.2 h1:onZX1rnHT3Wv6cqNgYyFOOlgVKJrksuCMCRvJStbMYw=
|
||||
github.com/go-test/deep v1.0.2/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
|
||||
github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss=
|
||||
github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
|
||||
github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs=
|
||||
github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
|
||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8=
|
||||
|
@ -259,20 +270,20 @@ github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg=
|
|||
github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
|
||||
github.com/google/cel-go v0.23.2 h1:UdEe3CvQh3Nv+E/j9r1Y//WO0K0cSyD7/y0bzyLIMI4=
|
||||
github.com/google/cel-go v0.23.2/go.mod h1:52Pb6QsDbC5kvgxvZhiL9QX1oZEkcUF/ZqaPx1J5Wwo=
|
||||
github.com/google/gnostic-models v0.6.9 h1:MU/8wDLif2qCXZmzncUQ/BOfxWfthHi63KqpoNbWqVw=
|
||||
github.com/google/gnostic-models v0.6.9/go.mod h1:CiWsm0s6BSQd1hRn8/QmxqB6BesYcbSZxsz9b0KuDBw=
|
||||
github.com/google/gnostic-models v0.7.0 h1:qwTtogB15McXDaNqTZdzPJRHvaVJlAl+HVQnLmJEJxo=
|
||||
github.com/google/gnostic-models v0.7.0/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7OUGxBlw57miDrQ=
|
||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
github.com/google/go-containerregistry v0.20.3 h1:oNx7IdTI936V8CQRveCjaxOiegWwvM7kqkbXTpyiovI=
|
||||
github.com/google/go-containerregistry v0.20.3/go.mod h1:w00pIgBRDVUDFM6bq+Qx8lwNWK+cxgCuX1vd3PIBDNI=
|
||||
github.com/google/go-containerregistry v0.20.6 h1:cvWX87UxxLgaH76b4hIvya6Dzz9qHB31qAwjAohdSTU=
|
||||
github.com/google/go-containerregistry v0.20.6/go.mod h1:T0x8MuoAoKX/873bkeSfLD2FAkwCDf9/HZgsFJ02E2Y=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
|
||||
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/martian/v3 v3.3.3 h1:DIhPTQrbPkgs2yJYdXU/eNACCG5DVQjySNRNlflZ9Fc=
|
||||
github.com/google/martian/v3 v3.3.3/go.mod h1:iEPrYcgCF7jA9OtScMFQyAlZZ4YXTKEtJ1E6RWzmBA0=
|
||||
github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 h1:BHT72Gu3keYf3ZEu2J0b1vyeLSOYI8bm5wbJM/8yDe8=
|
||||
github.com/google/pprof v0.0.0-20250403155104-27863c87afa6/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA=
|
||||
github.com/google/pprof v0.0.0-20250630185457-6e76a2b096b5 h1:xhMrHhTJ6zxu3gA4enFM9MLn9AY7613teCdFnlUVbSQ=
|
||||
github.com/google/pprof v0.0.0-20250630185457-6e76a2b096b5/go.mod h1:5hDyRhoBCxViHszMt12TnOpEI4VVi+U8Gm9iphldiMA=
|
||||
github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0=
|
||||
github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM=
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
|
||||
|
@ -281,8 +292,8 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
|||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.6 h1:GW/XbdyBFQ8Qe+YAmFU9uHLo7OnF5tL52HFAgMmyrf4=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.6/go.mod h1:MkHOF77EYAE7qfSuSS9PU6g4Nt4e11cnsDUowfwewLA=
|
||||
github.com/googleapis/gax-go/v2 v2.14.1 h1:hb0FFeiPaQskmvakKu5EbCbpntQn48jyHuvrkurSS/Q=
|
||||
github.com/googleapis/gax-go/v2 v2.14.1/go.mod h1:Hb/NubMaVM88SrNkvl8X/o8XWwDJEPqouaLeN2IUxoA=
|
||||
github.com/googleapis/gax-go/v2 v2.14.2 h1:eBLnkZ9635krYIPD+ag1USrOAI0Nr0QYF3+/3GqO0k0=
|
||||
github.com/googleapis/gax-go/v2 v2.14.2/go.mod h1:ON64QhlJkhVtSqp4v1uaK92VyZ2gmvDQsweuyLV+8+w=
|
||||
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 h1:JeSE6pjso5THxAzdVpqr6/geYxZytqFMBCOtn/ujyeo=
|
||||
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674/go.mod h1:r4w70xmWCQKmi1ONH4KIaBptdivuRPyosB9RmPlGEwA=
|
||||
github.com/goware/prefixer v0.0.0-20160118172347-395022866408 h1:Y9iQJfEqnN3/Nce9cOegemcy/9Ai5k3huT6E80F3zaw=
|
||||
|
@ -298,8 +309,8 @@ github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB1
|
|||
github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
|
||||
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
|
||||
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
|
||||
github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU=
|
||||
github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk=
|
||||
github.com/hashicorp/go-retryablehttp v0.7.8 h1:ylXZWnqa7Lhqpk0L1P1LzDtGcCR0rPVUrx/c8Unxc48=
|
||||
github.com/hashicorp/go-retryablehttp v0.7.8/go.mod h1:rjiScheydd+CxvumBsIrFKlx3iS0jrZ7LvzFGFmuKbw=
|
||||
github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc=
|
||||
github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=
|
||||
github.com/hashicorp/go-secure-stdlib/parseutil v0.2.0 h1:U+kC2dOhMFQctRfhK0gRctKAPTloZdMU5ZJxaesJ/VM=
|
||||
|
@ -308,10 +319,10 @@ github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9
|
|||
github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4=
|
||||
github.com/hashicorp/go-sockaddr v1.0.7 h1:G+pTkSO01HpR5qCxg7lxfsFEZaG+C0VssTy/9dbT+Fw=
|
||||
github.com/hashicorp/go-sockaddr v1.0.7/go.mod h1:FZQbEYa1pxkQ7WLpyXJ6cbjpT8q0YgQaK/JakXqGyWw=
|
||||
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/hashicorp/vault/api v1.16.0 h1:nbEYGJiAPGzT9U4oWgaaB0g+Rj8E59QuHKyA5LhwQN4=
|
||||
github.com/hashicorp/vault/api v1.16.0/go.mod h1:KhuUhzOD8lDSk29AtzNjgAu2kxRA9jL9NAbkFlqvkBA=
|
||||
github.com/hashicorp/hcl v1.0.1-vault-7 h1:ag5OxFVy3QYTFTJODRzTKVZ6xvdfLLCA1cy/Y6xGI0I=
|
||||
github.com/hashicorp/hcl v1.0.1-vault-7/go.mod h1:XYhtn6ijBSAj6n4YqAaf7RBPS4I06AItNorpy+MoQNM=
|
||||
github.com/hashicorp/vault/api v1.20.0 h1:KQMHElgudOsr+IbJgmbjHnCTxEpKs9LnozA1D3nozU4=
|
||||
github.com/hashicorp/vault/api v1.20.0/go.mod h1:GZ4pcjfzoOWpkJ3ijHNpEoAxKEsBJnVljyTe3jM2Sms=
|
||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
|
||||
|
@ -402,12 +413,12 @@ github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/
|
|||
github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0=
|
||||
github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
|
||||
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
|
||||
github.com/prometheus/common v0.63.0 h1:YR/EIY1o3mEFP/kZCD7iDMnLPlGyuU2Gb3HIcXnA98k=
|
||||
github.com/prometheus/common v0.63.0/go.mod h1:VVFF/fBIoToEnWRVkYoXEkq3R3paCoxG9PXP74SnV18=
|
||||
github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg=
|
||||
github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is=
|
||||
github.com/redis/go-redis/v9 v9.7.3 h1:YpPyAayJV+XErNsatSElgRZZVCwXX9QzkKYNvO7x0wM=
|
||||
github.com/redis/go-redis/v9 v9.7.3/go.mod h1:bGUrSggJ9X9GUmZpZNEOQKaANxSGgOEBRltRTZHSvrA=
|
||||
github.com/prometheus/common v0.65.0 h1:QDwzd+G1twt//Kwj/Ww6E9FQq1iVMmODnILtW1t2VzE=
|
||||
github.com/prometheus/common v0.65.0/go.mod h1:0gZns+BLRQ3V6NdaerOhMbwwRbNh9hkGINtQAsP5GS8=
|
||||
github.com/prometheus/procfs v0.17.0 h1:FuLQ+05u4ZI+SS/w9+BWEM2TXiHKsUQ9TADiRH7DuK0=
|
||||
github.com/prometheus/procfs v0.17.0/go.mod h1:oPQLaDAMRbA+u8H5Pbfq+dl3VDAvHxMUOVhe0wYB2zw=
|
||||
github.com/redis/go-redis/v9 v9.8.0 h1:q3nRvjrlge/6UD7eTu/DSg2uYiU2mCL0G/uzBWqhicI=
|
||||
github.com/redis/go-redis/v9 v9.8.0/go.mod h1:huWgSWd8mW6+m0VPhJjSSQ+d6Nh1VICQ6Q5lHuCH/Iw=
|
||||
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
|
||||
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
|
||||
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
||||
|
@ -468,22 +479,22 @@ go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJyS
|
|||
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
|
||||
go.opentelemetry.io/contrib/detectors/gcp v1.35.0 h1:bGvFt68+KTiAKFlacHW6AhA56GF2rS0bdD3aJYEnmzA=
|
||||
go.opentelemetry.io/contrib/detectors/gcp v1.35.0/go.mod h1:qGWP8/+ILwMRIUf9uIVLloR1uo5ZYAslM4O6OqUi1DA=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0 h1:x7wzEgXfnzJcHDwStJT+mxOz4etr2EcexjqhBvmoakw=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0/go.mod h1:rg+RlpR5dKwaS95IyyZqj5Wd4E13lk/msnTS0Xl9lJM=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 h1:sbiXRNDSWJOTobXh5HyQKjq6wUC5tNybqjIqDpAY4CU=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0/go.mod h1:69uWxva0WgAA/4bu2Yy70SLDBwZXuQ6PbBpbsa5iZrQ=
|
||||
go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ=
|
||||
go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 h1:q4XOmH/0opmeuJtPsbFNivyl7bCt7yRBbeEm2sC/XtQ=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0/go.mod h1:snMWehoOh2wsEwnvvwtDyFCxVeDAODenXHtn5vzrKjo=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 h1:F7Jx+6hwnZ41NSFTO5q4LYDtJRXBf2PD0rNBkeB/lus=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0/go.mod h1:UHB22Z8QsdRDrnAtX4PntOl36ajSxcdUMt1sF7Y6E7Q=
|
||||
go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ=
|
||||
go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I=
|
||||
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.29.0 h1:WDdP9acbMYjbKIyJUhTvtzj601sVJOqgWdUxSdR/Ysc=
|
||||
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.29.0/go.mod h1:BLbf7zbNIONBLPwvFnwNHGj4zge8uTCM/UPIVW1Mq2I=
|
||||
go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M=
|
||||
go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE=
|
||||
go.opentelemetry.io/otel/sdk v1.35.0 h1:iPctf8iprVySXSKJffSS79eOjl9pvxV9ZqOWT0QejKY=
|
||||
go.opentelemetry.io/otel/sdk v1.35.0/go.mod h1:+ga1bZliga3DxJ3CQGg3updiaAJoNECOgJREo9KHGQg=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.35.0 h1:1RriWBmCKgkeHEhM7a2uMjMUfP7MsOF5JpUCaEqEI9o=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.35.0/go.mod h1:is6XYCUMpcKi+ZsOvfluY5YstFnhW0BidkR+gL+qN+w=
|
||||
go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs=
|
||||
go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc=
|
||||
go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE=
|
||||
go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E=
|
||||
go.opentelemetry.io/otel/sdk v1.36.0 h1:b6SYIuLRs88ztox4EyrvRti80uXIFy+Sqzoh9kFULbs=
|
||||
go.opentelemetry.io/otel/sdk v1.36.0/go.mod h1:+lC+mTgD+MUWfjJubi2vvXWcVxyr9rmlshZni72pXeY=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.36.0 h1:r0ntwwGosWGaa0CrSt8cuNuTcccMXERFwHX4dThiPis=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.36.0/go.mod h1:qTNOhFDfKRwX0yXOqJYegL5WRaW376QbB7P4Pb0qva4=
|
||||
go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4=
|
||||
go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0=
|
||||
go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs=
|
||||
go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8=
|
||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
|
@ -492,11 +503,15 @@ go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
|||
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
|
||||
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
|
||||
go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI=
|
||||
go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU=
|
||||
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
|
||||
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8=
|
||||
golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw=
|
||||
golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM=
|
||||
golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY=
|
||||
golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 h1:e66Fs6Z+fZTbFBAxKfP3PALWBtpfqks2bwGcexMxgtk=
|
||||
golang.org/x/exp v0.0.0-20240909161429-701f63a606c0/go.mod h1:2TbTHSBQa924w8M6Xs1QcRcFwyucIwBGpK1p2f1YFFY=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
|
@ -505,15 +520,15 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn
|
|||
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=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=
|
||||
golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=
|
||||
golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs=
|
||||
golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8=
|
||||
golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI=
|
||||
golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ=
|
||||
golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=
|
||||
golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
|
@ -521,38 +536,38 @@ golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
|
||||
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg=
|
||||
golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ=
|
||||
golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA=
|
||||
golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/term v0.33.0 h1:NuFncQrRcaRvVmgRkvM3j/F00gWIAlcmlB8ACEKmGIg=
|
||||
golang.org/x/term v0.33.0/go.mod h1:s18+ql9tYWp1IfpV9DmCtQDDSRBUjKaw9M1eAv5UeF0=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=
|
||||
golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=
|
||||
golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0=
|
||||
golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
|
||||
golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4=
|
||||
golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU=
|
||||
golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE=
|
||||
golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.33.0 h1:4qz2S3zmRxbGIhDIAgjxvFutSvH5EfnsYrRBj0UI0bc=
|
||||
golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI=
|
||||
golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo=
|
||||
golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg=
|
||||
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=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gomodules.xyz/jsonpatch/v2 v2.5.0 h1:JELs8RLM12qJGXU4u/TO3V25KW8GreMKl9pdkk14RM0=
|
||||
gomodules.xyz/jsonpatch/v2 v2.5.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY=
|
||||
google.golang.org/api v0.230.0 h1:2u1hni3E+UXAXrONrrkfWpi/V6cyKVAbfGVeGtC3OxM=
|
||||
google.golang.org/api v0.230.0/go.mod h1:aqvtoMk7YkiXx+6U12arQFExiRV9D/ekvMCwCd/TksQ=
|
||||
google.golang.org/genproto v0.0.0-20250425173222-7b384671a197 h1:qWb9n6MA4nHA/g2varvEG/jTCs8zUuSa+5VqFgX2K+0=
|
||||
google.golang.org/genproto v0.0.0-20250425173222-7b384671a197/go.mod h1:Cej/8iHf9mPl71o/a+R1rrvSFrAAVCUFX9s/sbNttBc=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250425173222-7b384671a197 h1:9DuBh3k1jUho2DHdxH+kbJwthIAq02vGvZNrD2ggF+Y=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250425173222-7b384671a197/go.mod h1:Cd8IzgPo5Akum2c9R6FsXNaZbH3Jpa2gpHlW89FqlyQ=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250425173222-7b384671a197 h1:29cjnHVylHwTzH66WfFZqgSQgnxzvWE+jvBwpZCLRxY=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250425173222-7b384671a197/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
|
||||
google.golang.org/grpc v1.72.0 h1:S7UkcVa60b5AAQTaO6ZKamFp1zMZSU0fGDK2WZLbBnM=
|
||||
google.golang.org/grpc v1.72.0/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM=
|
||||
google.golang.org/api v0.241.0 h1:QKwqWQlkc6O895LchPEDUSYr22Xp3NCxpQRiWTB6avE=
|
||||
google.golang.org/api v0.241.0/go.mod h1:cOVEm2TpdAGHL2z+UwyS+kmlGr3bVWQQ6sYEqkKje50=
|
||||
google.golang.org/genproto v0.0.0-20250505200425-f936aa4a68b2 h1:1tXaIXCracvtsRxSBsYDiSBN0cuJvM7QYW+MrpIRY78=
|
||||
google.golang.org/genproto v0.0.0-20250505200425-f936aa4a68b2/go.mod h1:49MsLSx0oWMOZqcpB3uL8ZOkAh1+TndpJ8ONoCBWiZk=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250505200425-f936aa4a68b2 h1:vPV0tzlsK6EzEDHNNH5sa7Hs9bd7iXR7B1tSiPepkV0=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250505200425-f936aa4a68b2/go.mod h1:pKLAc5OolXC3ViWGI62vvC0n10CpwAtRcTNCFwTKBEw=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 h1:fc6jSaCT0vBduLYZHYrBBNY4dsWuvgyff9noRNDdBeE=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
|
||||
google.golang.org/grpc v1.73.0 h1:VIWSmpI2MegBtTuFt5/JWy2oXxtjJ/e89Z70ImfD2ok=
|
||||
google.golang.org/grpc v1.73.0/go.mod h1:50sbHOUqWoCQGI8V2HQLJM0B+LMlIUjNSZmow7EVBQc=
|
||||
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
|
||||
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
@ -571,38 +586,39 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
|||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU=
|
||||
gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU=
|
||||
k8s.io/api v0.33.0 h1:yTgZVn1XEe6opVpP1FylmNrIFWuDqe2H0V8CT5gxfIU=
|
||||
k8s.io/api v0.33.0/go.mod h1:CTO61ECK/KU7haa3qq8sarQ0biLq2ju405IZAd9zsiM=
|
||||
k8s.io/apiextensions-apiserver v0.33.0 h1:d2qpYL7Mngbsc1taA4IjJPRJ9ilnsXIrndH+r9IimOs=
|
||||
k8s.io/apiextensions-apiserver v0.33.0/go.mod h1:VeJ8u9dEEN+tbETo+lFkwaaZPg6uFKLGj5vyNEwwSzc=
|
||||
k8s.io/apimachinery v0.33.0 h1:1a6kHrJxb2hs4t8EE5wuR/WxKDwGN1FKH3JvDtA0CIQ=
|
||||
k8s.io/apimachinery v0.33.0/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM=
|
||||
k8s.io/cli-runtime v0.33.0 h1:Lbl/pq/1o8BaIuyn+aVLdEPHVN665tBAXUePs8wjX7c=
|
||||
k8s.io/cli-runtime v0.33.0/go.mod h1:QcA+r43HeUM9jXFJx7A+yiTPfCooau/iCcP1wQh4NFw=
|
||||
k8s.io/client-go v0.33.0 h1:UASR0sAYVUzs2kYuKn/ZakZlcs2bEHaizrrHUZg0G98=
|
||||
k8s.io/client-go v0.33.0/go.mod h1:kGkd+l/gNGg8GYWAPr0xF1rRKvVWvzh9vmZAMXtaKOg=
|
||||
k8s.io/component-base v0.33.0 h1:Ot4PyJI+0JAD9covDhwLp9UNkUja209OzsJ4FzScBNk=
|
||||
k8s.io/component-base v0.33.0/go.mod h1:aXYZLbw3kihdkOPMDhWbjGCO6sg+luw554KP51t8qCU=
|
||||
k8s.io/api v0.33.2 h1:YgwIS5jKfA+BZg//OQhkJNIfie/kmRsO0BmNaVSimvY=
|
||||
k8s.io/api v0.33.2/go.mod h1:fhrbphQJSM2cXzCWgqU29xLDuks4mu7ti9vveEnpSXs=
|
||||
k8s.io/apiextensions-apiserver v0.33.2 h1:6gnkIbngnaUflR3XwE1mCefN3YS8yTD631JXQhsU6M8=
|
||||
k8s.io/apiextensions-apiserver v0.33.2/go.mod h1:IvVanieYsEHJImTKXGP6XCOjTwv2LUMos0YWc9O+QP8=
|
||||
k8s.io/apimachinery v0.33.2 h1:IHFVhqg59mb8PJWTLi8m1mAoepkUNYmptHsV+Z1m5jY=
|
||||
k8s.io/apimachinery v0.33.2/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM=
|
||||
k8s.io/cli-runtime v0.33.2 h1:koNYQKSDdq5AExa/RDudXMhhtFasEg48KLS2KSAU74Y=
|
||||
k8s.io/cli-runtime v0.33.2/go.mod h1:gnhsAWpovqf1Zj5YRRBBU7PFsRc6NkEkwYNQE+mXL88=
|
||||
k8s.io/client-go v0.33.2 h1:z8CIcc0P581x/J1ZYf4CNzRKxRvQAwoAolYPbtQes+E=
|
||||
k8s.io/client-go v0.33.2/go.mod h1:9mCgT4wROvL948w6f6ArJNb7yQd7QsvqavDeZHvNmHo=
|
||||
k8s.io/component-base v0.33.2 h1:sCCsn9s/dG3ZrQTX/Us0/Sx2R0G5kwa0wbZFYoVp/+0=
|
||||
k8s.io/component-base v0.33.2/go.mod h1:/41uw9wKzuelhN+u+/C59ixxf4tYQKW7p32ddkYNe2k=
|
||||
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
|
||||
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
|
||||
k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff h1:/usPimJzUKKu+m+TE36gUyGcf03XZEP0ZIKgKj35LS4=
|
||||
k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff/go.mod h1:5jIi+8yX4RIb8wk3XwBo5Pq2ccx4FP10ohkbSKCZoK8=
|
||||
k8s.io/kubectl v0.33.0 h1:HiRb1yqibBSCqic4pRZP+viiOBAnIdwYDpzUFejs07g=
|
||||
k8s.io/kubectl v0.33.0/go.mod h1:gAlGBuS1Jq1fYZ9AjGWbI/5Vk3M/VW2DK4g10Fpyn/0=
|
||||
k8s.io/utils v0.0.0-20250321185631-1f6e0b77f77e h1:KqK5c/ghOm8xkHYhlodbp6i6+r+ChV2vuAuVRdFbLro=
|
||||
k8s.io/utils v0.0.0-20250321185631-1f6e0b77f77e/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
|
||||
k8s.io/kube-openapi v0.0.0-20250701173324-9bd5c66d9911 h1:gAXU86Fmbr/ktY17lkHwSjw5aoThQvhnstGGIYKlKYc=
|
||||
k8s.io/kube-openapi v0.0.0-20250701173324-9bd5c66d9911/go.mod h1:GLOk5B+hDbRROvt0X2+hqX64v/zO3vXN7J78OUmBSKw=
|
||||
k8s.io/kubectl v0.33.2 h1:7XKZ6DYCklu5MZQzJe+CkCjoGZwD1wWl7t/FxzhMz7Y=
|
||||
k8s.io/kubectl v0.33.2/go.mod h1:8rC67FB8tVTYraovAGNi/idWIK90z2CHFNMmGJZJ3KI=
|
||||
k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 h1:hwvWFiBzdWw1FhfY1FooPn3kzWuJ8tmbZBHi4zVsl1Y=
|
||||
k8s.io/utils v0.0.0-20250604170112-4c0f3b243397/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
|
||||
sigs.k8s.io/controller-runtime v0.21.0 h1:CYfjpEuicjUecRk+KAeyYh+ouUBn4llGyDYytIGcJS8=
|
||||
sigs.k8s.io/controller-runtime v0.21.0/go.mod h1:OSg14+F65eWqIu4DceX7k/+QRAbTTvxeQSNSOQpukWM=
|
||||
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 h1:gBQPwqORJ8d8/YNZWEjoZs7npUVDpVXUUOFfW6CgAqE=
|
||||
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg=
|
||||
sigs.k8s.io/kustomize/api v0.19.0 h1:F+2HB2mU1MSiR9Hp1NEgoU2q9ItNOaBJl0I4Dlus5SQ=
|
||||
sigs.k8s.io/kustomize/api v0.19.0/go.mod h1:/BbwnivGVcBh1r+8m3tH1VNxJmHSk1PzP5fkP6lbL1o=
|
||||
sigs.k8s.io/kustomize/kyaml v0.19.0 h1:RFge5qsO1uHhwJsu3ipV7RNolC7Uozc0jUBC/61XSlA=
|
||||
sigs.k8s.io/kustomize/kyaml v0.19.0/go.mod h1:FeKD5jEOH+FbZPpqUghBP8mrLjJ3+zD3/rf9NNu1cwY=
|
||||
sigs.k8s.io/kustomize/api v0.20.0 h1:xPLqcobHI0bThyRUteO+nCV8G4d1Rlo5HafO57VRcas=
|
||||
sigs.k8s.io/kustomize/api v0.20.0/go.mod h1:F6CfaV27oevRCMJgehLqyX81dlUnRX/Fc13Uo7+OSo4=
|
||||
sigs.k8s.io/kustomize/kyaml v0.20.0 h1:tT8KMKi4R3hCJ1+9HDdek2VoXpkerP92ZfF6fDgGw14=
|
||||
sigs.k8s.io/kustomize/kyaml v0.20.0/go.mod h1:0EmkQHRUsJxY8Ug9Niig1pUMSCGHxQ5RklbpV/Ri6po=
|
||||
sigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
|
||||
sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU=
|
||||
sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.7.0 h1:qPeWmscJcXP0snki5IYF79Z8xrl8ETFxgMd7wez1XkI=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.7.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps=
|
||||
sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
|
||||
sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=
|
||||
sigs.k8s.io/yaml v1.5.0 h1:M10b2U7aEUY6hRtU870n2VTPgR5RZiL/I6Lcc2F4NUQ=
|
||||
sigs.k8s.io/yaml v1.5.0/go.mod h1:wZs27Rbxoai4C0f8/9urLZtZtF3avA3gKvGyPdDqTO4=
|
||||
|
|
|
@ -14,15 +14,17 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
package intcache
|
||||
package cache
|
||||
|
||||
const (
|
||||
OperationFetchKubeConfig = "fetch_kubeconfig"
|
||||
OperationDecryptWithAWS = "decrypt_with_aws"
|
||||
OperationDecryptWithAzure = "decrypt_with_azure"
|
||||
OperationDecryptWithGCP = "decrypt_with_gcp"
|
||||
)
|
||||
|
||||
var AllOperations = []string{
|
||||
OperationFetchKubeConfig,
|
||||
OperationDecryptWithAWS,
|
||||
OperationDecryptWithAzure,
|
||||
OperationDecryptWithGCP,
|
||||
|
|
|
@ -16,4 +16,7 @@ limitations under the License.
|
|||
|
||||
package controller
|
||||
|
||||
const OCIArtifactOriginRevisionAnnotation = "org.opencontainers.image.revision"
|
||||
const (
|
||||
OCIArtifactOriginRevisionAnnotation = "org.opencontainers.image.revision"
|
||||
TerminalErrorMessage = "Reconciliation failed terminally due to configuration error"
|
||||
)
|
||||
|
|
|
@ -90,7 +90,7 @@ stringData:
|
|||
Interval: metav1.Duration{Duration: reconciliationInterval},
|
||||
Path: "./",
|
||||
KubeConfig: &meta.KubeConfigReference{
|
||||
SecretRef: meta.SecretKeyReference{
|
||||
SecretRef: &meta.SecretKeyReference{
|
||||
Name: "kubeconfig",
|
||||
},
|
||||
},
|
||||
|
|
|
@ -22,11 +22,11 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
securejoin "github.com/cyphar/filepath-securejoin"
|
||||
celtypes "github.com/google/cel-go/common/types"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
apimeta "k8s.io/apimachinery/pkg/api/meta"
|
||||
|
@ -36,14 +36,9 @@ import (
|
|||
"k8s.io/apimachinery/pkg/types"
|
||||
kerrors "k8s.io/apimachinery/pkg/util/errors"
|
||||
kuberecorder "k8s.io/client-go/tools/record"
|
||||
"k8s.io/client-go/util/workqueue"
|
||||
ctrl "sigs.k8s.io/controller-runtime"
|
||||
"sigs.k8s.io/controller-runtime/pkg/builder"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/controller"
|
||||
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
|
||||
"sigs.k8s.io/controller-runtime/pkg/handler"
|
||||
"sigs.k8s.io/controller-runtime/pkg/predicate"
|
||||
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
||||
|
||||
"github.com/fluxcd/cli-utils/pkg/kstatus/polling"
|
||||
|
@ -53,6 +48,7 @@ import (
|
|||
eventv1 "github.com/fluxcd/pkg/apis/event/v1beta1"
|
||||
"github.com/fluxcd/pkg/apis/meta"
|
||||
"github.com/fluxcd/pkg/auth"
|
||||
authutils "github.com/fluxcd/pkg/auth/utils"
|
||||
"github.com/fluxcd/pkg/cache"
|
||||
"github.com/fluxcd/pkg/http/fetch"
|
||||
generator "github.com/fluxcd/pkg/kustomize"
|
||||
|
@ -63,7 +59,6 @@ import (
|
|||
runtimeCtrl "github.com/fluxcd/pkg/runtime/controller"
|
||||
"github.com/fluxcd/pkg/runtime/jitter"
|
||||
"github.com/fluxcd/pkg/runtime/patch"
|
||||
"github.com/fluxcd/pkg/runtime/predicates"
|
||||
"github.com/fluxcd/pkg/runtime/statusreaders"
|
||||
"github.com/fluxcd/pkg/ssa"
|
||||
"github.com/fluxcd/pkg/ssa/normalize"
|
||||
|
@ -75,6 +70,7 @@ import (
|
|||
intcache "github.com/fluxcd/kustomize-controller/internal/cache"
|
||||
"github.com/fluxcd/kustomize-controller/internal/decryptor"
|
||||
"github.com/fluxcd/kustomize-controller/internal/inventory"
|
||||
intruntime "github.com/fluxcd/kustomize-controller/internal/runtime"
|
||||
)
|
||||
|
||||
// +kubebuilder:rbac:groups=kustomize.toolkit.fluxcd.io,resources=kustomizations,verbs=get;list;watch;create;update;patch;delete
|
||||
|
@ -95,82 +91,23 @@ type KustomizationReconciler struct {
|
|||
artifactFetchRetries int
|
||||
requeueDependency time.Duration
|
||||
|
||||
Mapper apimeta.RESTMapper
|
||||
APIReader client.Reader
|
||||
ClusterReader engine.ClusterReaderFactory
|
||||
ControllerName string
|
||||
statusManager string
|
||||
NoCrossNamespaceRefs bool
|
||||
NoRemoteBases bool
|
||||
FailFast bool
|
||||
DefaultServiceAccount string
|
||||
KubeConfigOpts runtimeClient.KubeConfigOptions
|
||||
ConcurrentSSA int
|
||||
DisallowedFieldManagers []string
|
||||
StrictSubstitutions bool
|
||||
GroupChangeLog bool
|
||||
TokenCache *cache.TokenCache
|
||||
}
|
||||
|
||||
// KustomizationReconcilerOptions contains options for the KustomizationReconciler.
|
||||
type KustomizationReconcilerOptions struct {
|
||||
HTTPRetry int
|
||||
DependencyRequeueInterval time.Duration
|
||||
RateLimiter workqueue.TypedRateLimiter[reconcile.Request]
|
||||
}
|
||||
|
||||
func (r *KustomizationReconciler) SetupWithManager(ctx context.Context, mgr ctrl.Manager, opts KustomizationReconcilerOptions) error {
|
||||
const (
|
||||
ociRepositoryIndexKey string = ".metadata.ociRepository"
|
||||
gitRepositoryIndexKey string = ".metadata.gitRepository"
|
||||
bucketIndexKey string = ".metadata.bucket"
|
||||
)
|
||||
|
||||
// Index the Kustomizations by the OCIRepository references they (may) point at.
|
||||
if err := mgr.GetCache().IndexField(ctx, &kustomizev1.Kustomization{}, ociRepositoryIndexKey,
|
||||
r.indexBy(sourcev1.OCIRepositoryKind)); err != nil {
|
||||
return fmt.Errorf("failed setting index fields: %w", err)
|
||||
}
|
||||
|
||||
// Index the Kustomizations by the GitRepository references they (may) point at.
|
||||
if err := mgr.GetCache().IndexField(ctx, &kustomizev1.Kustomization{}, gitRepositoryIndexKey,
|
||||
r.indexBy(sourcev1.GitRepositoryKind)); err != nil {
|
||||
return fmt.Errorf("failed setting index fields: %w", err)
|
||||
}
|
||||
|
||||
// Index the Kustomizations by the Bucket references they (may) point at.
|
||||
if err := mgr.GetCache().IndexField(ctx, &kustomizev1.Kustomization{}, bucketIndexKey,
|
||||
r.indexBy(sourcev1.BucketKind)); err != nil {
|
||||
return fmt.Errorf("failed setting index fields: %w", err)
|
||||
}
|
||||
|
||||
r.requeueDependency = opts.DependencyRequeueInterval
|
||||
r.statusManager = fmt.Sprintf("gotk-%s", r.ControllerName)
|
||||
r.artifactFetchRetries = opts.HTTPRetry
|
||||
|
||||
return ctrl.NewControllerManagedBy(mgr).
|
||||
For(&kustomizev1.Kustomization{}, builder.WithPredicates(
|
||||
predicate.Or(predicate.GenerationChangedPredicate{}, predicates.ReconcileRequestedPredicate{}),
|
||||
)).
|
||||
Watches(
|
||||
&sourcev1.OCIRepository{},
|
||||
handler.EnqueueRequestsFromMapFunc(r.requestsForRevisionChangeOf(ociRepositoryIndexKey)),
|
||||
builder.WithPredicates(SourceRevisionChangePredicate{}),
|
||||
).
|
||||
Watches(
|
||||
&sourcev1.GitRepository{},
|
||||
handler.EnqueueRequestsFromMapFunc(r.requestsForRevisionChangeOf(gitRepositoryIndexKey)),
|
||||
builder.WithPredicates(SourceRevisionChangePredicate{}),
|
||||
).
|
||||
Watches(
|
||||
&sourcev1.Bucket{},
|
||||
handler.EnqueueRequestsFromMapFunc(r.requestsForRevisionChangeOf(bucketIndexKey)),
|
||||
builder.WithPredicates(SourceRevisionChangePredicate{}),
|
||||
).
|
||||
WithOptions(controller.Options{
|
||||
RateLimiter: opts.RateLimiter,
|
||||
}).
|
||||
Complete(r)
|
||||
Mapper apimeta.RESTMapper
|
||||
APIReader client.Reader
|
||||
ClusterReader engine.ClusterReaderFactory
|
||||
ControllerName string
|
||||
statusManager string
|
||||
NoCrossNamespaceRefs bool
|
||||
NoRemoteBases bool
|
||||
FailFast bool
|
||||
DefaultServiceAccount string
|
||||
SOPSAgeSecret string
|
||||
KubeConfigOpts runtimeClient.KubeConfigOptions
|
||||
ConcurrentSSA int
|
||||
DisallowedFieldManagers []string
|
||||
StrictSubstitutions bool
|
||||
GroupChangeLog bool
|
||||
AdditiveCELDependencyCheck bool
|
||||
TokenCache *cache.TokenCache
|
||||
}
|
||||
|
||||
func (r *KustomizationReconciler) Reconcile(ctx context.Context, req ctrl.Request) (result ctrl.Result, retErr error) {
|
||||
|
@ -236,17 +173,15 @@ func (r *KustomizationReconciler) Reconcile(ctx context.Context, req ctrl.Reques
|
|||
// Configure custom health checks.
|
||||
statusReaders, err := cel.PollerWithCustomHealthChecks(ctx, obj.Spec.HealthCheckExprs)
|
||||
if err != nil {
|
||||
const msg = "Reconciliation failed terminally due to configuration error"
|
||||
errMsg := fmt.Sprintf("%s: %v", msg, err)
|
||||
errMsg := fmt.Sprintf("%s: %v", TerminalErrorMessage, err)
|
||||
conditions.MarkFalse(obj, meta.ReadyCondition, meta.InvalidCELExpressionReason, "%s", errMsg)
|
||||
conditions.MarkStalled(obj, meta.InvalidCELExpressionReason, "%s", errMsg)
|
||||
obj.Status.ObservedGeneration = obj.Generation
|
||||
log.Error(err, msg)
|
||||
r.event(obj, "", "", eventv1.EventSeverityError, errMsg, nil)
|
||||
return ctrl.Result{}, nil
|
||||
return ctrl.Result{}, reconcile.TerminalError(err)
|
||||
}
|
||||
|
||||
// Check object-level workload identity feature gate.
|
||||
// Check object-level workload identity feature gate and decryption with service account.
|
||||
if d := obj.Spec.Decryption; d != nil && d.ServiceAccountName != "" && !auth.IsObjectLevelWorkloadIdentityEnabled() {
|
||||
const gate = auth.FeatureGateObjectLevelWorkloadIdentity
|
||||
const msgFmt = "to use spec.decryption.serviceAccountName for decryption authentication please enable the %s feature gate in the controller"
|
||||
|
@ -293,6 +228,17 @@ func (r *KustomizationReconciler) Reconcile(ctx context.Context, req ctrl.Reques
|
|||
// Check dependencies and requeue the reconciliation if the check fails.
|
||||
if len(obj.Spec.DependsOn) > 0 {
|
||||
if err := r.checkDependencies(ctx, obj, artifactSource); err != nil {
|
||||
// Check if this is a terminal error that should not trigger retries
|
||||
if errors.Is(err, reconcile.TerminalError(nil)) {
|
||||
errMsg := fmt.Sprintf("%s: %v", TerminalErrorMessage, err)
|
||||
conditions.MarkFalse(obj, meta.ReadyCondition, meta.InvalidCELExpressionReason, "%s", errMsg)
|
||||
conditions.MarkStalled(obj, meta.InvalidCELExpressionReason, "%s", errMsg)
|
||||
obj.Status.ObservedGeneration = obj.Generation
|
||||
r.event(obj, revision, originRevision, eventv1.EventSeverityError, errMsg, nil)
|
||||
return ctrl.Result{}, err
|
||||
}
|
||||
|
||||
// Retry on transient errors.
|
||||
conditions.MarkFalse(obj, meta.ReadyCondition, meta.DependencyNotReadyReason, "%s", err)
|
||||
msg := fmt.Sprintf("Dependencies do not meet ready condition, retrying in %s", r.requeueDependency.String())
|
||||
log.Info(msg)
|
||||
|
@ -410,8 +356,9 @@ func (r *KustomizationReconciler) reconcile(
|
|||
}
|
||||
if obj.Spec.KubeConfig != nil {
|
||||
mustImpersonate = true
|
||||
provider := r.getProviderRESTConfigFetcher(obj)
|
||||
impersonatorOpts = append(impersonatorOpts,
|
||||
runtimeClient.WithKubeConfig(obj.Spec.KubeConfig, r.KubeConfigOpts, obj.GetNamespace()))
|
||||
runtimeClient.WithKubeConfig(obj.Spec.KubeConfig, r.KubeConfigOpts, obj.GetNamespace(), provider))
|
||||
}
|
||||
if r.ClusterReader != nil || len(statusReaders) > 0 {
|
||||
impersonatorOpts = append(impersonatorOpts,
|
||||
|
@ -532,51 +479,120 @@ func (r *KustomizationReconciler) reconcile(
|
|||
return nil
|
||||
}
|
||||
|
||||
// checkDependencies checks if the dependencies of the current Kustomization are ready.
|
||||
// To be considered ready, a dependencies must meet the following criteria:
|
||||
// - The dependency exists in the API server.
|
||||
// - The CEL expression (if provided) must evaluate to true.
|
||||
// - The dependency observed generation must match the current generation.
|
||||
// - The dependency Ready condition must be true.
|
||||
// - The dependency last applied revision must match the current source artifact revision.
|
||||
func (r *KustomizationReconciler) checkDependencies(ctx context.Context,
|
||||
obj *kustomizev1.Kustomization,
|
||||
source sourcev1.Source) error {
|
||||
for _, d := range obj.Spec.DependsOn {
|
||||
if d.Namespace == "" {
|
||||
d.Namespace = obj.GetNamespace()
|
||||
|
||||
// Convert the Kustomization object to Unstructured for CEL evaluation.
|
||||
objMap, err := runtime.DefaultUnstructuredConverter.ToUnstructured(obj)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to convert Kustomization to unstructured: %w", err)
|
||||
}
|
||||
|
||||
for _, depRef := range obj.Spec.DependsOn {
|
||||
// Check if the dependency exists by querying
|
||||
// the API server bypassing the cache.
|
||||
if depRef.Namespace == "" {
|
||||
depRef.Namespace = obj.GetNamespace()
|
||||
}
|
||||
dName := types.NamespacedName{
|
||||
Namespace: d.Namespace,
|
||||
Name: d.Name,
|
||||
depName := types.NamespacedName{
|
||||
Namespace: depRef.Namespace,
|
||||
Name: depRef.Name,
|
||||
}
|
||||
var k kustomizev1.Kustomization
|
||||
err := r.APIReader.Get(ctx, dName, &k)
|
||||
var dep kustomizev1.Kustomization
|
||||
err := r.APIReader.Get(ctx, depName, &dep)
|
||||
if err != nil {
|
||||
return fmt.Errorf("dependency '%s' not found: %w", dName, err)
|
||||
return fmt.Errorf("dependency '%s' not found: %w", depName, err)
|
||||
}
|
||||
|
||||
if len(k.Status.Conditions) == 0 || k.Generation != k.Status.ObservedGeneration {
|
||||
return fmt.Errorf("dependency '%s' is not ready", dName)
|
||||
// Evaluate the CEL expression (if specified) to determine if the dependency is ready.
|
||||
if depRef.ReadyExpr != "" {
|
||||
ready, err := r.evalReadyExpr(ctx, depRef.ReadyExpr, objMap, &dep)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !ready {
|
||||
return fmt.Errorf("dependency '%s' is not ready according to readyExpr eval", depName)
|
||||
}
|
||||
}
|
||||
|
||||
if !apimeta.IsStatusConditionTrue(k.Status.Conditions, meta.ReadyCondition) {
|
||||
return fmt.Errorf("dependency '%s' is not ready", dName)
|
||||
// Skip the built-in readiness check if the CEL expression is provided
|
||||
// and the AdditiveCELDependencyCheck feature gate is not enabled.
|
||||
if depRef.ReadyExpr != "" && !r.AdditiveCELDependencyCheck {
|
||||
continue
|
||||
}
|
||||
|
||||
srcNamespace := k.Spec.SourceRef.Namespace
|
||||
// Check if the dependency observed generation is up to date
|
||||
// and if the dependency is in a ready state.
|
||||
if len(dep.Status.Conditions) == 0 || dep.Generation != dep.Status.ObservedGeneration {
|
||||
return fmt.Errorf("dependency '%s' is not ready", depName)
|
||||
}
|
||||
if !apimeta.IsStatusConditionTrue(dep.Status.Conditions, meta.ReadyCondition) {
|
||||
return fmt.Errorf("dependency '%s' is not ready", depName)
|
||||
}
|
||||
|
||||
// Check if the dependency source matches the current source
|
||||
// and if so, verify that the last applied revision of the dependency
|
||||
// matches the current source artifact revision.
|
||||
srcNamespace := dep.Spec.SourceRef.Namespace
|
||||
if srcNamespace == "" {
|
||||
srcNamespace = k.GetNamespace()
|
||||
srcNamespace = dep.GetNamespace()
|
||||
}
|
||||
dSrcNamespace := obj.Spec.SourceRef.Namespace
|
||||
if dSrcNamespace == "" {
|
||||
dSrcNamespace = obj.GetNamespace()
|
||||
depSrcNamespace := obj.Spec.SourceRef.Namespace
|
||||
if depSrcNamespace == "" {
|
||||
depSrcNamespace = obj.GetNamespace()
|
||||
}
|
||||
|
||||
if k.Spec.SourceRef.Name == obj.Spec.SourceRef.Name &&
|
||||
srcNamespace == dSrcNamespace &&
|
||||
k.Spec.SourceRef.Kind == obj.Spec.SourceRef.Kind &&
|
||||
!source.GetArtifact().HasRevision(k.Status.LastAppliedRevision) {
|
||||
return fmt.Errorf("dependency '%s' revision is not up to date", dName)
|
||||
if dep.Spec.SourceRef.Name == obj.Spec.SourceRef.Name &&
|
||||
srcNamespace == depSrcNamespace &&
|
||||
dep.Spec.SourceRef.Kind == obj.Spec.SourceRef.Kind &&
|
||||
!source.GetArtifact().HasRevision(dep.Status.LastAppliedRevision) {
|
||||
return fmt.Errorf("dependency '%s' revision is not up to date", depName)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// evalReadyExpr evaluates the CEL expression for the dependency readiness check.
|
||||
func (r *KustomizationReconciler) evalReadyExpr(
|
||||
ctx context.Context,
|
||||
expr string,
|
||||
selfMap map[string]any,
|
||||
dep *kustomizev1.Kustomization,
|
||||
) (bool, error) {
|
||||
const (
|
||||
selfName = "self"
|
||||
depName = "dep"
|
||||
)
|
||||
|
||||
celExpr, err := cel.NewExpression(expr,
|
||||
cel.WithCompile(),
|
||||
cel.WithOutputType(celtypes.BoolType),
|
||||
cel.WithStructVariables(selfName, depName))
|
||||
if err != nil {
|
||||
return false, reconcile.TerminalError(fmt.Errorf("failed to evaluate dependency %s: %w", dep.Name, err))
|
||||
}
|
||||
|
||||
depMap, err := runtime.DefaultUnstructuredConverter.ToUnstructured(dep)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("failed to convert %s object to map: %w", depName, err)
|
||||
}
|
||||
|
||||
vars := map[string]any{
|
||||
selfName: selfMap,
|
||||
depName: depMap,
|
||||
}
|
||||
|
||||
return celExpr.EvaluateBoolean(ctx, vars)
|
||||
}
|
||||
|
||||
func (r *KustomizationReconciler) getSource(ctx context.Context,
|
||||
obj *kustomizev1.Kustomization) (sourcev1.Source, error) {
|
||||
var src sourcev1.Source
|
||||
|
@ -642,7 +658,18 @@ func (r *KustomizationReconciler) generate(obj unstructured.Unstructured,
|
|||
func (r *KustomizationReconciler) build(ctx context.Context,
|
||||
obj *kustomizev1.Kustomization, u unstructured.Unstructured,
|
||||
workDir, dirPath string) ([]byte, error) {
|
||||
dec, cleanup, err := decryptor.NewTempDecryptor(workDir, r.Client, obj, r.TokenCache)
|
||||
|
||||
// Build decryptor.
|
||||
decryptorOpts := []decryptor.Option{
|
||||
decryptor.WithRoot(workDir),
|
||||
}
|
||||
if r.TokenCache != nil {
|
||||
decryptorOpts = append(decryptorOpts, decryptor.WithTokenCache(*r.TokenCache))
|
||||
}
|
||||
if name, ns := r.SOPSAgeSecret, intruntime.Namespace(); name != "" && ns != "" {
|
||||
decryptorOpts = append(decryptorOpts, decryptor.WithSOPSAgeSecret(name, ns))
|
||||
}
|
||||
dec, cleanup, err := decryptor.New(r.Client, obj, decryptorOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -794,120 +821,44 @@ func (r *KustomizationReconciler) apply(ctx context.Context,
|
|||
},
|
||||
}
|
||||
|
||||
// contains only CRDs and Namespaces
|
||||
var defStage []*unstructured.Unstructured
|
||||
|
||||
// contains only Kubernetes Class types e.g.: RuntimeClass, PriorityClass,
|
||||
// StorageClass, VolumeSnapshotClass, IngressClass, GatewayClass, ClusterClass, etc
|
||||
var classStage []*unstructured.Unstructured
|
||||
|
||||
// contains all objects except for CRDs, Namespaces and Class type objects
|
||||
var resStage []*unstructured.Unstructured
|
||||
|
||||
// contains the objects' metadata after apply
|
||||
resultSet := ssa.NewChangeSet()
|
||||
|
||||
for _, u := range objects {
|
||||
if decryptor.IsEncryptedSecret(u) {
|
||||
return false, nil,
|
||||
fmt.Errorf("%s is SOPS encrypted, configuring decryption is required for this secret to be reconciled",
|
||||
ssautil.FmtUnstructured(u))
|
||||
}
|
||||
|
||||
switch {
|
||||
case ssautil.IsClusterDefinition(u):
|
||||
defStage = append(defStage, u)
|
||||
case strings.HasSuffix(u.GetKind(), "Class"):
|
||||
classStage = append(classStage, u)
|
||||
default:
|
||||
resStage = append(resStage, u)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// contains the objects' metadata after apply
|
||||
resultSet := ssa.NewChangeSet()
|
||||
var changeSetLog strings.Builder
|
||||
|
||||
// validate, apply and wait for CRDs and Namespaces to register
|
||||
if len(defStage) > 0 {
|
||||
changeSet, err := manager.ApplyAll(ctx, defStage, applyOpts)
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
if len(objects) > 0 {
|
||||
changeSet, err := manager.ApplyAllStaged(ctx, objects, applyOpts)
|
||||
|
||||
if changeSet != nil && len(changeSet.Entries) > 0 {
|
||||
resultSet.Append(changeSet.Entries)
|
||||
|
||||
if r.GroupChangeLog {
|
||||
log.Info("server-side apply for cluster definitions completed", "output", changeSet.ToGroupedMap())
|
||||
} else {
|
||||
log.Info("server-side apply for cluster definitions completed", "output", changeSet.ToMap())
|
||||
}
|
||||
// filter out the objects that have not changed
|
||||
for _, change := range changeSet.Entries {
|
||||
if HasChanged(change.Action) {
|
||||
changeSetLog.WriteString(change.String() + "\n")
|
||||
}
|
||||
}
|
||||
|
||||
if err := manager.WaitForSet(changeSet.ToObjMetadataSet(), ssa.WaitOptions{
|
||||
Interval: 2 * time.Second,
|
||||
Timeout: obj.GetTimeout(),
|
||||
}); err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// validate, apply and wait for Class type objects to register
|
||||
if len(classStage) > 0 {
|
||||
changeSet, err := manager.ApplyAll(ctx, classStage, applyOpts)
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
|
||||
if changeSet != nil && len(changeSet.Entries) > 0 {
|
||||
resultSet.Append(changeSet.Entries)
|
||||
|
||||
if r.GroupChangeLog {
|
||||
log.Info("server-side apply for cluster definitions completed", "output", changeSet.ToGroupedMap())
|
||||
} else {
|
||||
log.Info("server-side apply for cluster class types completed", "output", changeSet.ToMap())
|
||||
}
|
||||
for _, change := range changeSet.Entries {
|
||||
if HasChanged(change.Action) {
|
||||
changeSetLog.WriteString(change.String() + "\n")
|
||||
}
|
||||
}
|
||||
|
||||
if err := manager.WaitForSet(changeSet.ToObjMetadataSet(), ssa.WaitOptions{
|
||||
Interval: 2 * time.Second,
|
||||
Timeout: obj.GetTimeout(),
|
||||
}); err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// sort by kind, validate and apply all the others objects
|
||||
sort.Sort(ssa.SortableUnstructureds(resStage))
|
||||
if len(resStage) > 0 {
|
||||
changeSet, err := manager.ApplyAll(ctx, resStage, applyOpts)
|
||||
// include the change log in the error message in case af a partial apply
|
||||
if err != nil {
|
||||
return false, nil, fmt.Errorf("%w\n%s", err, changeSetLog.String())
|
||||
}
|
||||
|
||||
// log all applied objects
|
||||
if changeSet != nil && len(changeSet.Entries) > 0 {
|
||||
resultSet.Append(changeSet.Entries)
|
||||
|
||||
if r.GroupChangeLog {
|
||||
log.Info("server-side apply for cluster definitions completed", "output", changeSet.ToGroupedMap())
|
||||
log.Info("server-side apply completed", "output", changeSet.ToGroupedMap(), "revision", revision)
|
||||
} else {
|
||||
log.Info("server-side apply completed", "output", changeSet.ToMap(), "revision", revision)
|
||||
}
|
||||
for _, change := range changeSet.Entries {
|
||||
if HasChanged(change.Action) {
|
||||
changeSetLog.WriteString(change.String() + "\n")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1076,8 +1027,9 @@ func (r *KustomizationReconciler) finalize(ctx context.Context,
|
|||
}
|
||||
if obj.Spec.KubeConfig != nil {
|
||||
mustImpersonate = true
|
||||
provider := r.getProviderRESTConfigFetcher(obj)
|
||||
impersonatorOpts = append(impersonatorOpts,
|
||||
runtimeClient.WithKubeConfig(obj.Spec.KubeConfig, r.KubeConfigOpts, obj.GetNamespace()))
|
||||
runtimeClient.WithKubeConfig(obj.Spec.KubeConfig, r.KubeConfigOpts, obj.GetNamespace(), provider))
|
||||
}
|
||||
if r.ClusterReader != nil {
|
||||
impersonatorOpts = append(impersonatorOpts, runtimeClient.WithPolling(r.ClusterReader))
|
||||
|
@ -1262,6 +1214,27 @@ func (r *KustomizationReconciler) getClientAndPoller(
|
|||
return r.Client, poller
|
||||
}
|
||||
|
||||
// getProviderRESTConfigFetcher returns a ProviderRESTConfigFetcher for the
|
||||
// Kustomization object, which is used to fetch the kubeconfig for a ConfigMap
|
||||
// reference in the Kustomization spec.
|
||||
func (r *KustomizationReconciler) getProviderRESTConfigFetcher(obj *kustomizev1.Kustomization) runtimeClient.ProviderRESTConfigFetcher {
|
||||
var provider runtimeClient.ProviderRESTConfigFetcher
|
||||
if kc := obj.Spec.KubeConfig; kc != nil && kc.SecretRef == nil && kc.ConfigMapRef != nil {
|
||||
var opts []auth.Option
|
||||
if r.TokenCache != nil {
|
||||
involvedObject := cache.InvolvedObject{
|
||||
Kind: kustomizev1.KustomizationKind,
|
||||
Name: obj.GetName(),
|
||||
Namespace: obj.GetNamespace(),
|
||||
Operation: intcache.OperationFetchKubeConfig,
|
||||
}
|
||||
opts = append(opts, auth.WithCache(*r.TokenCache, involvedObject))
|
||||
}
|
||||
provider = runtimeClient.ProviderRESTConfigFetcher(authutils.GetRESTConfigFetcher(opts...))
|
||||
}
|
||||
return provider
|
||||
}
|
||||
|
||||
// getOriginRevision returns the origin revision of the source artifact,
|
||||
// or the empty string if it's not present, or if the artifact itself
|
||||
// is not present.
|
||||
|
|
|
@ -76,7 +76,7 @@ func TestKustomizationReconciler_StagedApply(t *testing.T) {
|
|||
Kind: sourcev1.GitRepositoryKind,
|
||||
},
|
||||
KubeConfig: &meta.KubeConfigReference{
|
||||
SecretRef: meta.SecretKeyReference{
|
||||
SecretRef: &meta.SecretKeyReference{
|
||||
Name: "kubeconfig",
|
||||
},
|
||||
},
|
||||
|
|
|
@ -114,7 +114,7 @@ func TestKustomizationReconciler_Decryptor(t *testing.T) {
|
|||
Interval: metav1.Duration{Duration: 2 * time.Minute},
|
||||
Path: "./",
|
||||
KubeConfig: &meta.KubeConfigReference{
|
||||
SecretRef: meta.SecretKeyReference{
|
||||
SecretRef: &meta.SecretKeyReference{
|
||||
Name: "kubeconfig",
|
||||
},
|
||||
},
|
||||
|
@ -194,4 +194,172 @@ func TestKustomizationReconciler_Decryptor(t *testing.T) {
|
|||
g.Expect(events[0].Message).Should(ContainSubstring("Reconciliation finished"))
|
||||
g.Expect(events[0].Message).ShouldNot(ContainSubstring("configured"))
|
||||
})
|
||||
|
||||
t.Run("global SOPS age secret as fallback", func(t *testing.T) {
|
||||
g := NewWithT(t)
|
||||
|
||||
namespace := "global-sops-" + randStringRunes(5)
|
||||
t.Setenv("RUNTIME_NAMESPACE", namespace)
|
||||
|
||||
err := createNamespace(namespace)
|
||||
g.Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
// Create the global SOPS age secret with the private key
|
||||
ageKey, err := os.ReadFile("testdata/sops/keys/age-global.txt")
|
||||
g.Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
globalSOPSSecret := &corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: sopsAgeSecret,
|
||||
Namespace: namespace,
|
||||
},
|
||||
StringData: map[string]string{
|
||||
"identity.agekey": string(ageKey),
|
||||
},
|
||||
}
|
||||
g.Expect(k8sClient.Create(context.Background(), globalSOPSSecret)).To(Succeed())
|
||||
|
||||
artifactName := "global-sops-" + randStringRunes(5)
|
||||
artifactChecksum, err := testServer.ArtifactFromDir("testdata/sops/global", artifactName)
|
||||
g.Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
repositoryName := types.NamespacedName{
|
||||
Name: fmt.Sprintf("global-sops-%s", randStringRunes(5)),
|
||||
Namespace: namespace,
|
||||
}
|
||||
|
||||
err = applyGitRepository(repositoryName, artifactName, "main/"+artifactChecksum)
|
||||
g.Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
// Create Kustomization WITHOUT spec.decryption.secretRef
|
||||
kustomizationKey := types.NamespacedName{
|
||||
Name: fmt.Sprintf("global-sops-%s", randStringRunes(5)),
|
||||
Namespace: namespace,
|
||||
}
|
||||
kustomization := &kustomizev1.Kustomization{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: kustomizationKey.Name,
|
||||
Namespace: kustomizationKey.Namespace,
|
||||
},
|
||||
Spec: kustomizev1.KustomizationSpec{
|
||||
Interval: metav1.Duration{Duration: 2 * time.Minute},
|
||||
Path: "./",
|
||||
SourceRef: kustomizev1.CrossNamespaceSourceReference{
|
||||
Name: repositoryName.Name,
|
||||
Namespace: repositoryName.Namespace,
|
||||
Kind: sourcev1.GitRepositoryKind,
|
||||
},
|
||||
TargetNamespace: namespace,
|
||||
Decryption: &kustomizev1.Decryption{
|
||||
Provider: "sops",
|
||||
},
|
||||
},
|
||||
}
|
||||
g.Expect(k8sClient.Create(context.TODO(), kustomization)).To(Succeed())
|
||||
|
||||
g.Eventually(func() bool {
|
||||
var obj kustomizev1.Kustomization
|
||||
_ = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(kustomization), &obj)
|
||||
return obj.Status.LastAppliedRevision == "main/"+artifactChecksum
|
||||
}, timeout, time.Second).Should(BeTrue())
|
||||
|
||||
// Verify the SOPS encrypted secret was decrypted using the global secret
|
||||
var secret corev1.Secret
|
||||
g.Expect(k8sClient.Get(context.TODO(), types.NamespacedName{Name: "global-age-secret", Namespace: namespace}, &secret)).To(Succeed())
|
||||
g.Expect(string(secret.Data["key"])).To(Equal("global-value"))
|
||||
})
|
||||
|
||||
t.Run("spec.decryption.secretRef takes precedence over global secret", func(t *testing.T) {
|
||||
g := NewWithT(t)
|
||||
|
||||
namespace := "precedence-" + randStringRunes(5)
|
||||
t.Setenv("RUNTIME_NAMESPACE", namespace)
|
||||
|
||||
err := createNamespace(namespace)
|
||||
g.Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
// Create global SOPS secret
|
||||
ageGlobalKey, err := os.ReadFile("testdata/sops/keys/age-global.txt")
|
||||
g.Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
globalSOPSSecret := &corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: sopsAgeSecret,
|
||||
Namespace: namespace,
|
||||
},
|
||||
StringData: map[string]string{
|
||||
"identity.agekey": string(ageGlobalKey),
|
||||
},
|
||||
}
|
||||
g.Expect(k8sClient.Create(context.Background(), globalSOPSSecret)).To(Succeed())
|
||||
|
||||
localSOPSSecretKey := types.NamespacedName{
|
||||
Name: "local-sops-" + randStringRunes(5),
|
||||
Namespace: namespace,
|
||||
}
|
||||
localSOPSSecret := &corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: localSOPSSecretKey.Name,
|
||||
Namespace: localSOPSSecretKey.Namespace,
|
||||
},
|
||||
StringData: map[string]string{
|
||||
"pgp.asc": string(pgpKey),
|
||||
"age.agekey": string(ageKey),
|
||||
"sops.vault-token": "secret",
|
||||
},
|
||||
}
|
||||
g.Expect(k8sClient.Create(context.Background(), localSOPSSecret)).To(Succeed())
|
||||
|
||||
artifactName := "precedence-" + randStringRunes(5)
|
||||
artifactChecksum, err := testServer.ArtifactFromDir("testdata/sops/algorithms", artifactName)
|
||||
g.Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
repositoryName := types.NamespacedName{
|
||||
Name: fmt.Sprintf("precedence-%s", randStringRunes(5)),
|
||||
Namespace: namespace,
|
||||
}
|
||||
|
||||
err = applyGitRepository(repositoryName, artifactName, "main/"+artifactChecksum)
|
||||
g.Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
// Create Kustomization WITH spec.decryption.secretRef
|
||||
kustomizationKey := types.NamespacedName{
|
||||
Name: fmt.Sprintf("precedence-%s", randStringRunes(5)),
|
||||
Namespace: namespace,
|
||||
}
|
||||
kustomization := &kustomizev1.Kustomization{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: kustomizationKey.Name,
|
||||
Namespace: kustomizationKey.Namespace,
|
||||
},
|
||||
Spec: kustomizev1.KustomizationSpec{
|
||||
Interval: metav1.Duration{Duration: 2 * time.Minute},
|
||||
Path: "./",
|
||||
SourceRef: kustomizev1.CrossNamespaceSourceReference{
|
||||
Name: repositoryName.Name,
|
||||
Namespace: repositoryName.Namespace,
|
||||
Kind: sourcev1.GitRepositoryKind,
|
||||
},
|
||||
Decryption: &kustomizev1.Decryption{
|
||||
Provider: "sops",
|
||||
SecretRef: &meta.LocalObjectReference{
|
||||
Name: localSOPSSecretKey.Name,
|
||||
},
|
||||
},
|
||||
TargetNamespace: namespace,
|
||||
},
|
||||
}
|
||||
g.Expect(k8sClient.Create(context.TODO(), kustomization)).To(Succeed())
|
||||
|
||||
g.Eventually(func() bool {
|
||||
var obj kustomizev1.Kustomization
|
||||
_ = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(kustomization), &obj)
|
||||
return obj.Status.LastAppliedRevision == "main/"+artifactChecksum
|
||||
}, timeout, time.Second).Should(BeTrue())
|
||||
|
||||
// Verify the secret was decrypted using the local secret (not the global one)
|
||||
var secret corev1.Secret
|
||||
g.Expect(k8sClient.Get(context.TODO(), types.NamespacedName{Name: "algo-age", Namespace: namespace}, &secret)).To(Succeed())
|
||||
g.Expect(string(secret.Data["key"])).To(Equal("value"))
|
||||
})
|
||||
}
|
||||
|
|
|
@ -125,7 +125,7 @@ data:
|
|||
Interval: metav1.Duration{Duration: reconciliationInterval},
|
||||
Path: "./",
|
||||
KubeConfig: &meta.KubeConfigReference{
|
||||
SecretRef: meta.SecretKeyReference{
|
||||
SecretRef: &meta.SecretKeyReference{
|
||||
Name: "kubeconfig",
|
||||
},
|
||||
},
|
||||
|
|
|
@ -19,14 +19,16 @@ package controller
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/fluxcd/pkg/apis/meta"
|
||||
"github.com/fluxcd/pkg/runtime/conditions"
|
||||
"github.com/fluxcd/pkg/testserver"
|
||||
sourcev1 "github.com/fluxcd/source-controller/api/v1"
|
||||
. "github.com/onsi/gomega"
|
||||
apimeta "k8s.io/apimachinery/pkg/api/meta"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
@ -117,10 +119,10 @@ spec:
|
|||
Namespace: kustomizationKey.Namespace,
|
||||
},
|
||||
Spec: kustomizev1.KustomizationSpec{
|
||||
Interval: metav1.Duration{Duration: reconciliationInterval},
|
||||
Interval: metav1.Duration{Duration: time.Hour},
|
||||
Path: "./",
|
||||
KubeConfig: &meta.KubeConfigReference{
|
||||
SecretRef: meta.SecretKeyReference{
|
||||
SecretRef: &meta.SecretKeyReference{
|
||||
Name: "kubeconfig",
|
||||
},
|
||||
},
|
||||
|
@ -140,15 +142,14 @@ spec:
|
|||
|
||||
g.Eventually(func() bool {
|
||||
_ = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(kustomization), resultK)
|
||||
return apimeta.FindStatusCondition(resultK.Status.Conditions, meta.ReadyCondition) != nil
|
||||
return conditions.Has(resultK, meta.ReadyCondition)
|
||||
}, timeout, time.Second).Should(BeTrue())
|
||||
|
||||
t.Run("fails due to source not found", func(t *testing.T) {
|
||||
g := NewWithT(t)
|
||||
g.Eventually(func() bool {
|
||||
_ = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(kustomization), resultK)
|
||||
ready := apimeta.FindStatusCondition(resultK.Status.Conditions, meta.ReadyCondition)
|
||||
return ready.Reason == meta.ArtifactFailedReason
|
||||
return conditions.HasAnyReason(resultK, meta.ReadyCondition, meta.ArtifactFailedReason)
|
||||
}, timeout, time.Second).Should(BeTrue())
|
||||
})
|
||||
|
||||
|
@ -159,8 +160,7 @@ spec:
|
|||
|
||||
g.Eventually(func() bool {
|
||||
_ = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(kustomization), resultK)
|
||||
ready := apimeta.FindStatusCondition(resultK.Status.Conditions, meta.ReadyCondition)
|
||||
return ready.Reason == meta.ReconciliationSucceededReason
|
||||
return conditions.IsReady(resultK)
|
||||
}, timeout, time.Second).Should(BeTrue())
|
||||
})
|
||||
|
||||
|
@ -168,7 +168,7 @@ spec:
|
|||
g := NewWithT(t)
|
||||
g.Eventually(func() error {
|
||||
_ = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(kustomization), resultK)
|
||||
resultK.Spec.DependsOn = []meta.NamespacedObjectReference{
|
||||
resultK.Spec.DependsOn = []kustomizev1.DependencyReference{
|
||||
{
|
||||
Namespace: id,
|
||||
Name: "root",
|
||||
|
@ -179,8 +179,203 @@ spec:
|
|||
|
||||
g.Eventually(func() bool {
|
||||
_ = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(kustomization), resultK)
|
||||
ready := apimeta.FindStatusCondition(resultK.Status.Conditions, meta.ReadyCondition)
|
||||
return ready.Reason == meta.DependencyNotReadyReason
|
||||
return conditions.HasAnyReason(resultK, meta.ReadyCondition, meta.DependencyNotReadyReason)
|
||||
}, timeout, time.Second).Should(BeTrue())
|
||||
})
|
||||
}
|
||||
|
||||
func TestKustomizationReconciler_DependsOn_CEL(t *testing.T) {
|
||||
g := NewWithT(t)
|
||||
id := "dep-cel" + randStringRunes(5)
|
||||
depID := "test-dep-" + randStringRunes(5)
|
||||
revision := "v1.0.0"
|
||||
|
||||
err := createNamespace(id)
|
||||
g.Expect(err).NotTo(HaveOccurred(), "failed to create test namespace")
|
||||
|
||||
err = createKubeConfigSecret(id)
|
||||
g.Expect(err).NotTo(HaveOccurred(), "failed to create kubeconfig secret")
|
||||
|
||||
manifests := func(name string, data string) []testserver.File {
|
||||
return []testserver.File{
|
||||
{
|
||||
Name: "config.yaml",
|
||||
Body: fmt.Sprintf(`---
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: %[1]s
|
||||
data:
|
||||
key: "%[2]s"
|
||||
`, name, data),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
artifact, err := testServer.ArtifactFromFiles(manifests(id, id))
|
||||
g.Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
repositoryName := types.NamespacedName{
|
||||
Name: fmt.Sprintf("dep-%s", randStringRunes(5)),
|
||||
Namespace: id,
|
||||
}
|
||||
err = applyGitRepository(repositoryName, artifact, revision)
|
||||
g.Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
kustomizationKey := types.NamespacedName{
|
||||
Name: fmt.Sprintf("dep-%s", randStringRunes(5)),
|
||||
Namespace: id,
|
||||
}
|
||||
kustomization := &kustomizev1.Kustomization{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: kustomizationKey.Name,
|
||||
Namespace: kustomizationKey.Namespace,
|
||||
},
|
||||
Spec: kustomizev1.KustomizationSpec{
|
||||
Interval: metav1.Duration{Duration: time.Hour},
|
||||
Path: "./",
|
||||
KubeConfig: &meta.KubeConfigReference{
|
||||
SecretRef: &meta.SecretKeyReference{
|
||||
Name: "kubeconfig",
|
||||
},
|
||||
},
|
||||
SourceRef: kustomizev1.CrossNamespaceSourceReference{
|
||||
Name: repositoryName.Name,
|
||||
Namespace: repositoryName.Namespace,
|
||||
Kind: sourcev1.GitRepositoryKind,
|
||||
},
|
||||
TargetNamespace: id,
|
||||
Prune: true,
|
||||
},
|
||||
}
|
||||
|
||||
g.Expect(k8sClient.Create(context.Background(), kustomization)).To(Succeed())
|
||||
|
||||
resultK := &kustomizev1.Kustomization{}
|
||||
|
||||
g.Eventually(func() bool {
|
||||
_ = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(kustomization), resultK)
|
||||
return conditions.Has(resultK, meta.ReadyCondition)
|
||||
}, timeout, time.Second).Should(BeTrue())
|
||||
|
||||
t.Run("succeeds with readyExpr dependency check", func(t *testing.T) {
|
||||
g := NewWithT(t)
|
||||
|
||||
// Create a dependency Kustomization with matching annotations
|
||||
dependency := &kustomizev1.Kustomization{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: depID,
|
||||
Namespace: id,
|
||||
Annotations: map[string]string{
|
||||
"app/version": "v1.2.3",
|
||||
},
|
||||
},
|
||||
Spec: kustomizev1.KustomizationSpec{
|
||||
Suspend: true, // Suspended dependency should work with readyExpr and AdditiveCELDependencyCheck disabled
|
||||
Interval: metav1.Duration{Duration: reconciliationInterval},
|
||||
Path: "./",
|
||||
KubeConfig: &meta.KubeConfigReference{
|
||||
SecretRef: &meta.SecretKeyReference{
|
||||
Name: "kubeconfig",
|
||||
},
|
||||
},
|
||||
SourceRef: kustomizev1.CrossNamespaceSourceReference{
|
||||
Name: repositoryName.Name,
|
||||
Namespace: repositoryName.Namespace,
|
||||
Kind: sourcev1.GitRepositoryKind,
|
||||
},
|
||||
Prune: true,
|
||||
},
|
||||
}
|
||||
|
||||
g.Expect(k8sClient.Create(context.Background(), dependency)).To(Succeed())
|
||||
|
||||
// Update the main Kustomization with matching annotations and readyExpr
|
||||
g.Eventually(func() error {
|
||||
_ = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(kustomization), resultK)
|
||||
resultK.ObjectMeta.Annotations = map[string]string{
|
||||
"app/version": "v1.2.3",
|
||||
}
|
||||
resultK.Spec.DependsOn = []kustomizev1.DependencyReference{
|
||||
{
|
||||
Name: dependency.Name,
|
||||
ReadyExpr: `self.metadata.annotations['app/version'] == dep.metadata.annotations['app/version']`,
|
||||
},
|
||||
}
|
||||
return k8sClient.Update(context.Background(), resultK)
|
||||
}, timeout, time.Second).Should(BeNil())
|
||||
|
||||
// Should succeed because CEL expression evaluates to true
|
||||
g.Eventually(func() bool {
|
||||
_ = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(kustomization), resultK)
|
||||
return conditions.IsReady(resultK)
|
||||
}, timeout, time.Second).Should(BeTrue())
|
||||
})
|
||||
|
||||
t.Run("fails with readyExpr when condition not met", func(t *testing.T) {
|
||||
g := NewWithT(t)
|
||||
|
||||
// Update the main kustomization with mismatched annotations
|
||||
g.Eventually(func() error {
|
||||
_ = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(kustomization), resultK)
|
||||
resultK.ObjectMeta.Annotations = map[string]string{
|
||||
"app/version": "v1.2.4",
|
||||
}
|
||||
resultK.Spec.DependsOn = []kustomizev1.DependencyReference{
|
||||
{
|
||||
Namespace: id,
|
||||
Name: depID,
|
||||
ReadyExpr: `self.metadata.annotations['app/version'] == dep.metadata.annotations['app/version']`,
|
||||
},
|
||||
}
|
||||
return k8sClient.Update(context.Background(), resultK)
|
||||
}, timeout, time.Second).Should(BeNil())
|
||||
|
||||
// Should fail because CEL expression evaluates to false
|
||||
g.Eventually(func() bool {
|
||||
_ = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(kustomization), resultK)
|
||||
ready := conditions.Get(resultK, meta.ReadyCondition)
|
||||
return ready.Reason == meta.DependencyNotReadyReason &&
|
||||
strings.Contains(ready.Message, "not ready according to readyExpr")
|
||||
}, timeout, time.Second).Should(BeTrue())
|
||||
|
||||
g.Expect(conditions.IsStalled(resultK)).Should(BeFalse())
|
||||
})
|
||||
|
||||
t.Run("fails terminally with invalid readyExpr", func(t *testing.T) {
|
||||
g := NewWithT(t)
|
||||
|
||||
// Update the main kustomization with invalid CEL expression
|
||||
g.Eventually(func() error {
|
||||
_ = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(kustomization), resultK)
|
||||
resultK.Spec.DependsOn = []kustomizev1.DependencyReference{
|
||||
{
|
||||
Name: depID,
|
||||
ReadyExpr: `self.generation == deps.generation`, // Invalid vars
|
||||
},
|
||||
}
|
||||
return k8sClient.Update(context.Background(), resultK)
|
||||
}, timeout, time.Second).Should(BeNil())
|
||||
|
||||
// Should be marked as stalled because CEL expression is invalid
|
||||
g.Eventually(func() bool {
|
||||
_ = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(kustomization), resultK)
|
||||
return conditions.IsStalled(resultK)
|
||||
}, timeout, time.Second).Should(BeTrue())
|
||||
|
||||
g.Expect(conditions.IsReady(resultK)).Should(BeFalse())
|
||||
g.Expect(conditions.GetReason(resultK, meta.ReadyCondition)).Should(BeIdenticalTo(meta.InvalidCELExpressionReason))
|
||||
g.Expect(conditions.GetMessage(resultK, meta.ReadyCondition)).Should(ContainSubstring("failed to parse"))
|
||||
})
|
||||
|
||||
t.Run("GC works with failing dependency", func(t *testing.T) {
|
||||
g := NewWithT(t)
|
||||
|
||||
g.Expect(k8sClient.Delete(context.Background(), kustomization)).To(Succeed())
|
||||
|
||||
g.Eventually(func() bool {
|
||||
err = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(kustomization), resultK)
|
||||
return errors.IsNotFound(err)
|
||||
}, timeout, time.Second).Should(BeTrue())
|
||||
})
|
||||
}
|
||||
|
|
|
@ -86,7 +86,7 @@ data:
|
|||
Interval: metav1.Duration{Duration: reconciliationInterval},
|
||||
Path: "./",
|
||||
KubeConfig: &meta.KubeConfigReference{
|
||||
SecretRef: meta.SecretKeyReference{
|
||||
SecretRef: &meta.SecretKeyReference{
|
||||
Name: "kubeconfig",
|
||||
},
|
||||
},
|
||||
|
|
|
@ -86,7 +86,7 @@ stringData:
|
|||
Interval: metav1.Duration{Duration: reconciliationInterval},
|
||||
Path: "./",
|
||||
KubeConfig: &meta.KubeConfigReference{
|
||||
SecretRef: meta.SecretKeyReference{
|
||||
SecretRef: &meta.SecretKeyReference{
|
||||
Name: "kubeconfig",
|
||||
},
|
||||
},
|
||||
|
|
|
@ -87,7 +87,7 @@ stringData:
|
|||
Interval: metav1.Duration{Duration: reconciliationInterval},
|
||||
Path: "./",
|
||||
KubeConfig: &meta.KubeConfigReference{
|
||||
SecretRef: meta.SecretKeyReference{
|
||||
SecretRef: &meta.SecretKeyReference{
|
||||
Name: "kubeconfig",
|
||||
},
|
||||
},
|
||||
|
|
|
@ -232,7 +232,7 @@ func Fuzz_Controllers(f *testing.F) {
|
|||
Spec: kustomizev1.KustomizationSpec{
|
||||
Path: "./",
|
||||
KubeConfig: &meta.KubeConfigReference{
|
||||
SecretRef: meta.SecretKeyReference{
|
||||
SecretRef: &meta.SecretKeyReference{
|
||||
Name: "kubeconfig",
|
||||
},
|
||||
},
|
||||
|
|
|
@ -93,7 +93,7 @@ data:
|
|||
Interval: metav1.Duration{Duration: time.Minute},
|
||||
Path: "./",
|
||||
KubeConfig: &meta.KubeConfigReference{
|
||||
SecretRef: meta.SecretKeyReference{
|
||||
SecretRef: &meta.SecretKeyReference{
|
||||
Name: "kubeconfig",
|
||||
},
|
||||
},
|
||||
|
@ -261,7 +261,7 @@ data:
|
|||
Interval: metav1.Duration{Duration: time.Minute},
|
||||
Path: "./",
|
||||
KubeConfig: &meta.KubeConfigReference{
|
||||
SecretRef: meta.SecretKeyReference{
|
||||
SecretRef: &meta.SecretKeyReference{
|
||||
Name: secretName,
|
||||
Key: secretKey,
|
||||
},
|
||||
|
|
|
@ -64,16 +64,11 @@ func (r *KustomizationReconciler) requestsForRevisionChangeOf(indexKey string) h
|
|||
}
|
||||
dd = append(dd, d.DeepCopy())
|
||||
}
|
||||
sorted, err := dependency.Sort(dd)
|
||||
reqs, err := sortAndEnqueue(dd)
|
||||
if err != nil {
|
||||
log.Error(err, "failed to sort dependencies for revision change")
|
||||
return nil
|
||||
}
|
||||
reqs := make([]reconcile.Request, len(sorted))
|
||||
for i := range sorted {
|
||||
reqs[i].NamespacedName.Name = sorted[i].Name
|
||||
reqs[i].NamespacedName.Namespace = sorted[i].Namespace
|
||||
}
|
||||
return reqs
|
||||
}
|
||||
}
|
||||
|
@ -96,3 +91,54 @@ func (r *KustomizationReconciler) indexBy(kind string) func(o client.Object) []s
|
|||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// requestsForConfigDependency enqueues requests for watched ConfigMaps or Secrets
|
||||
// according to the specified index.
|
||||
func (r *KustomizationReconciler) requestsForConfigDependency(
|
||||
index string) func(ctx context.Context, o client.Object) []reconcile.Request {
|
||||
|
||||
return func(ctx context.Context, o client.Object) []reconcile.Request {
|
||||
log := ctrl.LoggerFrom(ctx).WithValues("index", index, "objectRef", map[string]string{
|
||||
"name": o.GetName(),
|
||||
"namespace": o.GetNamespace(),
|
||||
})
|
||||
|
||||
// List Kustomizations that have a dependency on the ConfigMap or Secret.
|
||||
var list kustomizev1.KustomizationList
|
||||
if err := r.List(ctx, &list, client.MatchingFields{
|
||||
index: client.ObjectKeyFromObject(o).String(),
|
||||
}); err != nil {
|
||||
log.Error(err, "failed to list Kustomizations for config dependency change")
|
||||
return nil
|
||||
}
|
||||
|
||||
// Sort the Kustomizations by their dependencies to ensure
|
||||
// that dependent Kustomizations are reconciled after their dependencies.
|
||||
dd := make([]dependency.Dependent, 0, len(list.Items))
|
||||
for i := range list.Items {
|
||||
dd = append(dd, &list.Items[i])
|
||||
}
|
||||
|
||||
// Enqueue requests for each Kustomization in the list.
|
||||
reqs, err := sortAndEnqueue(dd)
|
||||
if err != nil {
|
||||
log.Error(err, "failed to sort dependencies for config dependency change")
|
||||
return nil
|
||||
}
|
||||
return reqs
|
||||
}
|
||||
}
|
||||
|
||||
// sortAndEnqueue sorts the dependencies and returns a slice of reconcile.Requests.
|
||||
func sortAndEnqueue(dd []dependency.Dependent) ([]reconcile.Request, error) {
|
||||
sorted, err := dependency.Sort(dd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
reqs := make([]reconcile.Request, len(sorted))
|
||||
for i := range sorted {
|
||||
reqs[i].NamespacedName.Name = sorted[i].Name
|
||||
reqs[i].NamespacedName.Namespace = sorted[i].Namespace
|
||||
}
|
||||
return reqs, nil
|
||||
}
|
||||
|
|
|
@ -97,7 +97,7 @@ stringData:
|
|||
Interval: metav1.Duration{Duration: 2 * time.Minute},
|
||||
Path: "./",
|
||||
KubeConfig: &meta.KubeConfigReference{
|
||||
SecretRef: meta.SecretKeyReference{
|
||||
SecretRef: &meta.SecretKeyReference{
|
||||
Name: "kubeconfig",
|
||||
},
|
||||
},
|
||||
|
|
|
@ -0,0 +1,161 @@
|
|||
/*
|
||||
Copyright 2025 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 controller
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/fluxcd/pkg/runtime/predicates"
|
||||
sourcev1 "github.com/fluxcd/source-controller/api/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/client-go/util/workqueue"
|
||||
ctrl "sigs.k8s.io/controller-runtime"
|
||||
"sigs.k8s.io/controller-runtime/pkg/builder"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/controller"
|
||||
"sigs.k8s.io/controller-runtime/pkg/handler"
|
||||
"sigs.k8s.io/controller-runtime/pkg/predicate"
|
||||
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
||||
|
||||
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1"
|
||||
)
|
||||
|
||||
// KustomizationReconcilerOptions contains options for the KustomizationReconciler.
|
||||
type KustomizationReconcilerOptions struct {
|
||||
HTTPRetry int
|
||||
DependencyRequeueInterval time.Duration
|
||||
RateLimiter workqueue.TypedRateLimiter[reconcile.Request]
|
||||
WatchConfigsPredicate predicate.Predicate
|
||||
}
|
||||
|
||||
// SetupWithManager sets up the controller with the Manager.
|
||||
// It indexes the Kustomizations by the source references, and sets up watches for
|
||||
// changes in those sources, as well as for ConfigMaps and Secrets that the Kustomizations depend on.
|
||||
func (r *KustomizationReconciler) SetupWithManager(ctx context.Context, mgr ctrl.Manager, opts KustomizationReconcilerOptions) error {
|
||||
const (
|
||||
indexOCIRepository = ".metadata.ociRepository"
|
||||
indexGitRepository = ".metadata.gitRepository"
|
||||
indexBucket = ".metadata.bucket"
|
||||
indexConfigMap = ".metadata.configMap"
|
||||
indexSecret = ".metadata.secret"
|
||||
)
|
||||
|
||||
// Index the Kustomizations by the OCIRepository references they (may) point at.
|
||||
if err := mgr.GetCache().IndexField(ctx, &kustomizev1.Kustomization{}, indexOCIRepository,
|
||||
r.indexBy(sourcev1.OCIRepositoryKind)); err != nil {
|
||||
return fmt.Errorf("failed creating index %s: %w", indexOCIRepository, err)
|
||||
}
|
||||
|
||||
// Index the Kustomizations by the GitRepository references they (may) point at.
|
||||
if err := mgr.GetCache().IndexField(ctx, &kustomizev1.Kustomization{}, indexGitRepository,
|
||||
r.indexBy(sourcev1.GitRepositoryKind)); err != nil {
|
||||
return fmt.Errorf("failed creating index %s: %w", indexGitRepository, err)
|
||||
}
|
||||
|
||||
// Index the Kustomizations by the Bucket references they (may) point at.
|
||||
if err := mgr.GetCache().IndexField(ctx, &kustomizev1.Kustomization{}, indexBucket,
|
||||
r.indexBy(sourcev1.BucketKind)); err != nil {
|
||||
return fmt.Errorf("failed creating index %s: %w", indexBucket, err)
|
||||
}
|
||||
|
||||
// Index the Kustomization by the ConfigMap references they point to.
|
||||
if err := mgr.GetFieldIndexer().IndexField(ctx, &kustomizev1.Kustomization{}, indexConfigMap,
|
||||
func(o client.Object) []string {
|
||||
obj := o.(*kustomizev1.Kustomization)
|
||||
namespace := obj.GetNamespace()
|
||||
var keys []string
|
||||
if kc := obj.Spec.KubeConfig; kc != nil && kc.ConfigMapRef != nil {
|
||||
keys = append(keys, fmt.Sprintf("%s/%s", namespace, kc.ConfigMapRef.Name))
|
||||
}
|
||||
if pb := obj.Spec.PostBuild; pb != nil {
|
||||
for _, ref := range pb.SubstituteFrom {
|
||||
if ref.Kind == "ConfigMap" {
|
||||
keys = append(keys, fmt.Sprintf("%s/%s", namespace, ref.Name))
|
||||
}
|
||||
}
|
||||
}
|
||||
return keys
|
||||
},
|
||||
); err != nil {
|
||||
return fmt.Errorf("failed creating index %s: %w", indexConfigMap, err)
|
||||
}
|
||||
|
||||
// Index the Kustomization by the Secret references they point to.
|
||||
if err := mgr.GetFieldIndexer().IndexField(ctx, &kustomizev1.Kustomization{}, indexSecret,
|
||||
func(o client.Object) []string {
|
||||
obj := o.(*kustomizev1.Kustomization)
|
||||
namespace := obj.GetNamespace()
|
||||
var keys []string
|
||||
if dec := obj.Spec.Decryption; dec != nil && dec.SecretRef != nil {
|
||||
keys = append(keys, fmt.Sprintf("%s/%s", namespace, dec.SecretRef.Name))
|
||||
}
|
||||
if kc := obj.Spec.KubeConfig; kc != nil && kc.SecretRef != nil {
|
||||
keys = append(keys, fmt.Sprintf("%s/%s", namespace, kc.SecretRef.Name))
|
||||
}
|
||||
if pb := obj.Spec.PostBuild; pb != nil {
|
||||
for _, ref := range pb.SubstituteFrom {
|
||||
if ref.Kind == "Secret" {
|
||||
keys = append(keys, fmt.Sprintf("%s/%s", namespace, ref.Name))
|
||||
}
|
||||
}
|
||||
}
|
||||
return keys
|
||||
},
|
||||
); err != nil {
|
||||
return fmt.Errorf("failed creating index %s: %w", indexSecret, err)
|
||||
}
|
||||
|
||||
r.requeueDependency = opts.DependencyRequeueInterval
|
||||
r.statusManager = fmt.Sprintf("gotk-%s", r.ControllerName)
|
||||
r.artifactFetchRetries = opts.HTTPRetry
|
||||
|
||||
return ctrl.NewControllerManagedBy(mgr).
|
||||
For(&kustomizev1.Kustomization{}, builder.WithPredicates(
|
||||
predicate.Or(predicate.GenerationChangedPredicate{}, predicates.ReconcileRequestedPredicate{}),
|
||||
)).
|
||||
Watches(
|
||||
&sourcev1.OCIRepository{},
|
||||
handler.EnqueueRequestsFromMapFunc(r.requestsForRevisionChangeOf(indexOCIRepository)),
|
||||
builder.WithPredicates(SourceRevisionChangePredicate{}),
|
||||
).
|
||||
Watches(
|
||||
&sourcev1.GitRepository{},
|
||||
handler.EnqueueRequestsFromMapFunc(r.requestsForRevisionChangeOf(indexGitRepository)),
|
||||
builder.WithPredicates(SourceRevisionChangePredicate{}),
|
||||
).
|
||||
Watches(
|
||||
&sourcev1.Bucket{},
|
||||
handler.EnqueueRequestsFromMapFunc(r.requestsForRevisionChangeOf(indexBucket)),
|
||||
builder.WithPredicates(SourceRevisionChangePredicate{}),
|
||||
).
|
||||
WatchesMetadata(
|
||||
&corev1.ConfigMap{},
|
||||
handler.EnqueueRequestsFromMapFunc(r.requestsForConfigDependency(indexConfigMap)),
|
||||
builder.WithPredicates(predicate.ResourceVersionChangedPredicate{}, opts.WatchConfigsPredicate),
|
||||
).
|
||||
WatchesMetadata(
|
||||
&corev1.Secret{},
|
||||
handler.EnqueueRequestsFromMapFunc(r.requestsForConfigDependency(indexSecret)),
|
||||
builder.WithPredicates(predicate.ResourceVersionChangedPredicate{}, opts.WatchConfigsPredicate),
|
||||
).
|
||||
WithOptions(controller.Options{
|
||||
RateLimiter: opts.RateLimiter,
|
||||
}).
|
||||
Complete(r)
|
||||
}
|
|
@ -87,7 +87,7 @@ stringData:
|
|||
Interval: metav1.Duration{Duration: reconciliationInterval},
|
||||
Path: "./",
|
||||
KubeConfig: &meta.KubeConfigReference{
|
||||
SecretRef: meta.SecretKeyReference{
|
||||
SecretRef: &meta.SecretKeyReference{
|
||||
Name: "kubeconfig",
|
||||
},
|
||||
},
|
||||
|
|
|
@ -0,0 +1,243 @@
|
|||
/*
|
||||
Copyright 2025 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 controller
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/fluxcd/pkg/apis/kustomize"
|
||||
"github.com/fluxcd/pkg/apis/meta"
|
||||
"github.com/fluxcd/pkg/testserver"
|
||||
sourcev1 "github.com/fluxcd/source-controller/api/v1"
|
||||
. "github.com/onsi/gomega"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1"
|
||||
)
|
||||
|
||||
// TestKustomizationReconciler_MultiplePatchDelete tests the handling of multiple
|
||||
// $patch: delete directives in strategic merge patches.
|
||||
// This test ensures that the controller properly handles scenarios where multiple
|
||||
// resources are deleted using a single patch specification.
|
||||
func TestKustomizationReconciler_MultiplePatchDelete(t *testing.T) {
|
||||
g := NewWithT(t)
|
||||
id := "multi-patch-delete-" + randStringRunes(5)
|
||||
revision := "v1.0.0"
|
||||
|
||||
err := createNamespace(id)
|
||||
g.Expect(err).NotTo(HaveOccurred(), "failed to create test namespace")
|
||||
|
||||
err = createKubeConfigSecret(id)
|
||||
g.Expect(err).NotTo(HaveOccurred(), "failed to create kubeconfig secret")
|
||||
|
||||
// Create test files with multiple ConfigMaps
|
||||
manifests := func(name string, data string) []testserver.File {
|
||||
return []testserver.File{
|
||||
{
|
||||
Name: "configmaps.yaml",
|
||||
Body: `---
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: cm1
|
||||
namespace: ` + name + `
|
||||
data:
|
||||
key: ` + data + `1
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: cm2
|
||||
namespace: ` + name + `
|
||||
data:
|
||||
key: ` + data + `2
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: cm3
|
||||
namespace: ` + name + `
|
||||
data:
|
||||
key: ` + data + `3
|
||||
`,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
artifact, err := testServer.ArtifactFromFiles(manifests(id, randStringRunes(5)))
|
||||
g.Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
repositoryName := types.NamespacedName{
|
||||
Name: randStringRunes(5),
|
||||
Namespace: id,
|
||||
}
|
||||
|
||||
err = applyGitRepository(repositoryName, artifact, revision)
|
||||
g.Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
kustomizationKey := types.NamespacedName{
|
||||
Name: "patch-delete-" + randStringRunes(5),
|
||||
Namespace: id,
|
||||
}
|
||||
|
||||
t.Run("multiple patch delete in single patch should work", func(t *testing.T) {
|
||||
// This test verifies that multiple $patch: delete directives in a single patch work correctly
|
||||
// Ref: https://github.com/fluxcd/kustomize-controller/issues/1306
|
||||
kustomization := &kustomizev1.Kustomization{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: kustomizationKey.Name,
|
||||
Namespace: kustomizationKey.Namespace,
|
||||
},
|
||||
Spec: kustomizev1.KustomizationSpec{
|
||||
Interval: metav1.Duration{Duration: reconciliationInterval},
|
||||
Path: "./",
|
||||
KubeConfig: &meta.KubeConfigReference{
|
||||
SecretRef: &meta.SecretKeyReference{
|
||||
Name: "kubeconfig",
|
||||
},
|
||||
},
|
||||
SourceRef: kustomizev1.CrossNamespaceSourceReference{
|
||||
Name: repositoryName.Name,
|
||||
Namespace: repositoryName.Namespace,
|
||||
Kind: sourcev1.GitRepositoryKind,
|
||||
},
|
||||
Prune: true,
|
||||
Patches: []kustomize.Patch{
|
||||
{
|
||||
// Multiple $patch: delete in a single patch
|
||||
Patch: `$patch: delete
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: cm1
|
||||
namespace: ` + id + `
|
||||
---
|
||||
$patch: delete
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: cm2
|
||||
namespace: ` + id + ``,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
g.Expect(k8sClient.Create(context.Background(), kustomization)).To(Succeed())
|
||||
|
||||
// Wait for reconciliation and check that it succeeds without panic
|
||||
g.Eventually(func() bool {
|
||||
var obj kustomizev1.Kustomization
|
||||
_ = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(kustomization), &obj)
|
||||
return obj.Status.LastAppliedRevision == revision
|
||||
}, timeout, time.Second).Should(BeTrue())
|
||||
|
||||
// Verify that only cm3 ConfigMap exists (cm1 and cm2 should be deleted)
|
||||
var cm corev1.ConfigMap
|
||||
err := k8sClient.Get(context.Background(), client.ObjectKey{Name: "cm1", Namespace: id}, &cm)
|
||||
g.Expect(err).To(HaveOccurred(), "cm1 should have been deleted")
|
||||
|
||||
err = k8sClient.Get(context.Background(), client.ObjectKey{Name: "cm2", Namespace: id}, &cm)
|
||||
g.Expect(err).To(HaveOccurred(), "cm2 should have been deleted")
|
||||
|
||||
err = k8sClient.Get(context.Background(), client.ObjectKey{Name: "cm3", Namespace: id}, &cm)
|
||||
g.Expect(err).NotTo(HaveOccurred(), "cm3 should still exist")
|
||||
|
||||
// Cleanup
|
||||
g.Expect(k8sClient.Delete(context.Background(), kustomization)).To(Succeed())
|
||||
g.Eventually(func() bool {
|
||||
err := k8sClient.Get(context.Background(), client.ObjectKeyFromObject(kustomization), kustomization)
|
||||
return apierrors.IsNotFound(err)
|
||||
}, timeout, time.Second).Should(BeTrue())
|
||||
})
|
||||
|
||||
t.Run("multiple patch delete in separate patches should work", func(t *testing.T) {
|
||||
// This test verifies that separate patches (which was previously a workaround) still work correctly
|
||||
kustomizationSeparate := &kustomizev1.Kustomization{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: kustomizationKey.Name + "-separate",
|
||||
Namespace: kustomizationKey.Namespace,
|
||||
},
|
||||
Spec: kustomizev1.KustomizationSpec{
|
||||
Interval: metav1.Duration{Duration: reconciliationInterval},
|
||||
Path: "./",
|
||||
KubeConfig: &meta.KubeConfigReference{
|
||||
SecretRef: &meta.SecretKeyReference{
|
||||
Name: "kubeconfig",
|
||||
},
|
||||
},
|
||||
SourceRef: kustomizev1.CrossNamespaceSourceReference{
|
||||
Name: repositoryName.Name,
|
||||
Namespace: repositoryName.Namespace,
|
||||
Kind: sourcev1.GitRepositoryKind,
|
||||
},
|
||||
Prune: true,
|
||||
Patches: []kustomize.Patch{
|
||||
{
|
||||
Patch: `$patch: delete
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: cm1
|
||||
namespace: ` + id + ``,
|
||||
},
|
||||
{
|
||||
Patch: `$patch: delete
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: cm2
|
||||
namespace: ` + id + ``,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
g.Expect(k8sClient.Create(context.Background(), kustomizationSeparate)).To(Succeed())
|
||||
|
||||
// Wait for successful reconciliation
|
||||
g.Eventually(func() bool {
|
||||
var obj kustomizev1.Kustomization
|
||||
_ = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(kustomizationSeparate), &obj)
|
||||
return obj.Status.LastAppliedRevision == revision
|
||||
}, timeout, time.Second).Should(BeTrue())
|
||||
|
||||
// Verify that only cm3 ConfigMap exists
|
||||
var cm corev1.ConfigMap
|
||||
err := k8sClient.Get(context.Background(), client.ObjectKey{Name: "cm1", Namespace: id}, &cm)
|
||||
g.Expect(err).To(HaveOccurred(), "cm1 should have been deleted")
|
||||
|
||||
err = k8sClient.Get(context.Background(), client.ObjectKey{Name: "cm2", Namespace: id}, &cm)
|
||||
g.Expect(err).To(HaveOccurred(), "cm2 should have been deleted")
|
||||
|
||||
err = k8sClient.Get(context.Background(), client.ObjectKey{Name: "cm3", Namespace: id}, &cm)
|
||||
g.Expect(err).NotTo(HaveOccurred(), "cm3 should still exist")
|
||||
|
||||
// Cleanup
|
||||
g.Expect(k8sClient.Delete(context.Background(), kustomizationSeparate)).To(Succeed())
|
||||
g.Eventually(func() bool {
|
||||
err := k8sClient.Get(context.Background(), client.ObjectKeyFromObject(kustomizationSeparate), kustomizationSeparate)
|
||||
return apierrors.IsNotFound(err)
|
||||
}, timeout, time.Second).Should(BeTrue())
|
||||
})
|
||||
}
|
|
@ -99,7 +99,7 @@ data:
|
|||
Interval: metav1.Duration{Duration: reconciliationInterval},
|
||||
Path: "./",
|
||||
KubeConfig: &meta.KubeConfigReference{
|
||||
SecretRef: meta.SecretKeyReference{
|
||||
SecretRef: &meta.SecretKeyReference{
|
||||
Name: "kubeconfig",
|
||||
},
|
||||
},
|
||||
|
@ -227,7 +227,7 @@ data:
|
|||
Interval: metav1.Duration{Duration: reconciliationInterval},
|
||||
Path: "./",
|
||||
KubeConfig: &meta.KubeConfigReference{
|
||||
SecretRef: meta.SecretKeyReference{
|
||||
SecretRef: &meta.SecretKeyReference{
|
||||
Name: "kubeconfig",
|
||||
},
|
||||
},
|
||||
|
@ -385,7 +385,7 @@ data:
|
|||
Interval: metav1.Duration{Duration: reconciliationInterval},
|
||||
Path: "./",
|
||||
KubeConfig: &meta.KubeConfigReference{
|
||||
SecretRef: meta.SecretKeyReference{
|
||||
SecretRef: &meta.SecretKeyReference{
|
||||
Name: "kubeconfig",
|
||||
},
|
||||
},
|
||||
|
|
|
@ -91,7 +91,7 @@ data:
|
|||
Interval: metav1.Duration{Duration: 2 * time.Minute},
|
||||
Path: "./",
|
||||
KubeConfig: &meta.KubeConfigReference{
|
||||
SecretRef: meta.SecretKeyReference{
|
||||
SecretRef: &meta.SecretKeyReference{
|
||||
Name: "kubeconfig",
|
||||
},
|
||||
},
|
||||
|
@ -200,7 +200,7 @@ data:
|
|||
Interval: metav1.Duration{Duration: 2 * time.Minute},
|
||||
Path: "./",
|
||||
KubeConfig: &meta.KubeConfigReference{
|
||||
SecretRef: meta.SecretKeyReference{
|
||||
SecretRef: &meta.SecretKeyReference{
|
||||
Name: "kubeconfig",
|
||||
},
|
||||
},
|
||||
|
@ -270,7 +270,7 @@ func TestKustomizationReconciler_KustomizeTransformer(t *testing.T) {
|
|||
Interval: metav1.Duration{Duration: reconciliationInterval},
|
||||
Path: "./",
|
||||
KubeConfig: &meta.KubeConfigReference{
|
||||
SecretRef: meta.SecretKeyReference{
|
||||
SecretRef: &meta.SecretKeyReference{
|
||||
Name: "kubeconfig",
|
||||
},
|
||||
},
|
||||
|
@ -393,7 +393,7 @@ func TestKustomizationReconciler_KustomizeTransformerFiles(t *testing.T) {
|
|||
Interval: metav1.Duration{Duration: reconciliationInterval},
|
||||
Path: "./",
|
||||
KubeConfig: &meta.KubeConfigReference{
|
||||
SecretRef: meta.SecretKeyReference{
|
||||
SecretRef: &meta.SecretKeyReference{
|
||||
Name: "kubeconfig",
|
||||
},
|
||||
},
|
||||
|
@ -512,7 +512,7 @@ func TestKustomizationReconciler_FluxTransformers(t *testing.T) {
|
|||
Interval: metav1.Duration{Duration: reconciliationInterval},
|
||||
Path: "./",
|
||||
KubeConfig: &meta.KubeConfigReference{
|
||||
SecretRef: meta.SecretKeyReference{
|
||||
SecretRef: &meta.SecretKeyReference{
|
||||
Name: "kubeconfig",
|
||||
},
|
||||
},
|
||||
|
|
|
@ -80,7 +80,7 @@ func TestKustomizationReconciler_Validation(t *testing.T) {
|
|||
Interval: metav1.Duration{Duration: 2 * time.Minute},
|
||||
Path: "./",
|
||||
KubeConfig: &meta.KubeConfigReference{
|
||||
SecretRef: meta.SecretKeyReference{
|
||||
SecretRef: &meta.SecretKeyReference{
|
||||
Name: "kubeconfig",
|
||||
},
|
||||
},
|
||||
|
|
|
@ -120,7 +120,7 @@ stringData:
|
|||
},
|
||||
Spec: kustomizev1.KustomizationSpec{
|
||||
KubeConfig: &meta.KubeConfigReference{
|
||||
SecretRef: meta.SecretKeyReference{
|
||||
SecretRef: &meta.SecretKeyReference{
|
||||
Name: "kubeconfig",
|
||||
},
|
||||
},
|
||||
|
@ -269,7 +269,7 @@ metadata:
|
|||
},
|
||||
Spec: kustomizev1.KustomizationSpec{
|
||||
KubeConfig: &meta.KubeConfigReference{
|
||||
SecretRef: meta.SecretKeyReference{
|
||||
SecretRef: &meta.SecretKeyReference{
|
||||
Name: "kubeconfig",
|
||||
},
|
||||
},
|
||||
|
@ -426,7 +426,7 @@ data:
|
|||
},
|
||||
Spec: kustomizev1.KustomizationSpec{
|
||||
KubeConfig: &meta.KubeConfigReference{
|
||||
SecretRef: meta.SecretKeyReference{
|
||||
SecretRef: &meta.SecretKeyReference{
|
||||
Name: "kubeconfig",
|
||||
},
|
||||
},
|
||||
|
@ -532,7 +532,7 @@ metadata:
|
|||
},
|
||||
Spec: kustomizev1.KustomizationSpec{
|
||||
KubeConfig: &meta.KubeConfigReference{
|
||||
SecretRef: meta.SecretKeyReference{
|
||||
SecretRef: &meta.SecretKeyReference{
|
||||
Name: "kubeconfig",
|
||||
},
|
||||
},
|
||||
|
|
|
@ -105,7 +105,7 @@ parameters:
|
|||
Interval: metav1.Duration{Duration: 2 * time.Minute},
|
||||
Path: "./",
|
||||
KubeConfig: &meta.KubeConfigReference{
|
||||
SecretRef: meta.SecretKeyReference{
|
||||
SecretRef: &meta.SecretKeyReference{
|
||||
Name: "kubeconfig",
|
||||
},
|
||||
},
|
||||
|
@ -331,7 +331,7 @@ data: {}
|
|||
Interval: metav1.Duration{Duration: 2 * time.Minute},
|
||||
Path: "./",
|
||||
KubeConfig: &meta.KubeConfigReference{
|
||||
SecretRef: meta.SecretKeyReference{
|
||||
SecretRef: &meta.SecretKeyReference{
|
||||
Name: "kubeconfig",
|
||||
},
|
||||
},
|
||||
|
@ -411,7 +411,7 @@ func TestKustomizationReconciler_RESTMapper(t *testing.T) {
|
|||
Kind: sourcev1.GitRepositoryKind,
|
||||
},
|
||||
KubeConfig: &meta.KubeConfigReference{
|
||||
SecretRef: meta.SecretKeyReference{
|
||||
SecretRef: &meta.SecretKeyReference{
|
||||
Name: "kubeconfig",
|
||||
},
|
||||
},
|
||||
|
|
|
@ -37,6 +37,7 @@ import (
|
|||
"sigs.k8s.io/controller-runtime/pkg/envtest"
|
||||
controllerLog "sigs.k8s.io/controller-runtime/pkg/log"
|
||||
"sigs.k8s.io/controller-runtime/pkg/log/zap"
|
||||
"sigs.k8s.io/controller-runtime/pkg/predicate"
|
||||
"sigs.k8s.io/yaml"
|
||||
|
||||
"github.com/fluxcd/pkg/apis/meta"
|
||||
|
@ -57,6 +58,7 @@ const (
|
|||
reconciliationInterval = time.Second * 5
|
||||
vaultVersion = "1.13.2"
|
||||
overrideManagerName = "node-fetch"
|
||||
sopsAgeSecret = "sops-age-secret"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -180,9 +182,11 @@ func TestMain(m *testing.M) {
|
|||
Metrics: testMetricsH,
|
||||
ConcurrentSSA: 4,
|
||||
DisallowedFieldManagers: []string{overrideManagerName},
|
||||
SOPSAgeSecret: sopsAgeSecret,
|
||||
}
|
||||
if err := (reconciler).SetupWithManager(ctx, testEnv, KustomizationReconcilerOptions{
|
||||
DependencyRequeueInterval: 2 * time.Second,
|
||||
WatchConfigsPredicate: predicate.Not(predicate.Funcs{}),
|
||||
}); err != nil {
|
||||
panic(fmt.Sprintf("Failed to start KustomizationReconciler: %v", err))
|
||||
}
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
resources:
|
||||
- secret.yaml
|
|
@ -0,0 +1,23 @@
|
|||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: global-age-secret
|
||||
namespace: default
|
||||
type: Opaque
|
||||
stringData:
|
||||
key: ENC[AES256_GCM,data:5d9WYyV8eyrOhF/m,iv:wuxE+q4pB+2cXBLcOy4/eZFSteLXJJDEI001UFAPd3A=,tag:EyM2zosBOv5/DnZMUqyNJg==,type:str]
|
||||
sops:
|
||||
age:
|
||||
- recipient: age1henwn645drkd3fa34t27t2w2x0nsgw3w4h62gmg5x5xflyjpy38s5cncph
|
||||
enc: |
|
||||
-----BEGIN AGE ENCRYPTED FILE-----
|
||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBhSEJIVUQrZXpkZmJ6ek1U
|
||||
enNmL2cycGJVTUp0bGJBQmhzUms5eENWd1MwCjZtUjMvT28zWU8wVHArNDdyNG1x
|
||||
RjJCK29jNEJ5bDc5M2pNVG0rcHhFQ2cKLS0tIDkzRk5zdTZ5ek4rNzNvT2l5VDJ1
|
||||
Sk01a05sV094UjFVbkhsVUhaOFhWa3MKwVILC0MO4CPlK0kniPTxOgMxej+E1NJ3
|
||||
d1vA+h/DFoHDV6fU63n/v0BLmi7q0x10pYj95u1Ef1cP24JC/G+M4g==
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
lastmodified: "2025-07-06T17:19:51Z"
|
||||
mac: ENC[AES256_GCM,data:5vkroTHj/9sLCEb+LHZEWwbrq9amLfU9QsDE6ZmpSDa/r7T2RGzX9cAhe73s2L7E5EZblsWOGLPdQCRXP/Llp19QzEU6dYs+n0IyFprjtYpL8VEB3S2aCPzdhOrN0o/pcHGmfvp4S9gXvwki1EIYhRL7ozBHNppxQGLOdVDigjg=,iv:dCzK0olxFn4QwknnYvO4LNo7SjuX04zF6saVRFQv7wY=,tag:GwL7WDw2IBxNUdGUBpBXEQ==,type:str]
|
||||
encrypted_regex: ^(data|stringData)$
|
||||
version: 3.10.2
|
|
@ -0,0 +1,3 @@
|
|||
# created: 2025-07-06T17:30:37+01:00
|
||||
# public key: age1henwn645drkd3fa34t27t2w2x0nsgw3w4h62gmg5x5xflyjpy38s5cncph
|
||||
AGE-SECRET-KEY-10U7MAELH09KZU63F65P2TYLN7TQM5X6GSDDCQ4YMUGDS3DS6XZMSTYY2PN
|
|
@ -162,32 +162,30 @@ type Decryptor struct {
|
|||
// decryptor.
|
||||
keyServices []keyservice.KeyServiceClient
|
||||
localServiceOnce sync.Once
|
||||
|
||||
// sopsAgeSecret is the NamespacedName of the Secret containing
|
||||
// a fallback SOPS age decryption key.
|
||||
sopsAgeSecret *types.NamespacedName
|
||||
}
|
||||
|
||||
// NewDecryptor creates a new Decryptor for the given kustomization.
|
||||
// gnuPGHome can be empty, in which case the systems' keyring is used.
|
||||
func NewDecryptor(root string, client client.Client, kustomization *kustomizev1.Kustomization,
|
||||
maxFileSize int64, gnuPGHome string, tokenCache *cache.TokenCache) *Decryptor {
|
||||
return &Decryptor{
|
||||
root: root,
|
||||
client: client,
|
||||
kustomization: kustomization,
|
||||
maxFileSize: maxFileSize,
|
||||
gnuPGHome: pgp.GnuPGHome(gnuPGHome),
|
||||
tokenCache: tokenCache,
|
||||
}
|
||||
}
|
||||
|
||||
// NewTempDecryptor creates a new Decryptor, with a temporary GnuPG
|
||||
// New creates a new Decryptor, with a temporary GnuPG
|
||||
// home directory to Decryptor.ImportKeys() into.
|
||||
func NewTempDecryptor(root string, client client.Client, kustomization *kustomizev1.Kustomization,
|
||||
tokenCache *cache.TokenCache) (*Decryptor, func(), error) {
|
||||
func New(client client.Client, kustomization *kustomizev1.Kustomization, opts ...Option) (*Decryptor, func(), error) {
|
||||
gnuPGHome, err := pgp.NewGnuPGHome()
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("cannot create decryptor: %w", err)
|
||||
}
|
||||
cleanup := func() { _ = os.RemoveAll(gnuPGHome.String()) }
|
||||
return NewDecryptor(root, client, kustomization, maxEncryptedFileSize, gnuPGHome.String(), tokenCache), cleanup, nil
|
||||
d := &Decryptor{
|
||||
client: client,
|
||||
kustomization: kustomization,
|
||||
maxFileSize: maxEncryptedFileSize,
|
||||
gnuPGHome: gnuPGHome,
|
||||
}
|
||||
for _, opt := range opts {
|
||||
opt(d)
|
||||
}
|
||||
return d, cleanup, nil
|
||||
}
|
||||
|
||||
// IsEncryptedSecret checks if the given object is a Kubernetes Secret encrypted
|
||||
|
@ -210,16 +208,43 @@ func IsEncryptedSecret(object *unstructured.Unstructured) bool {
|
|||
// For the import of PGP keys, the Decryptor must be configured with
|
||||
// an absolute GnuPG home directory path.
|
||||
func (d *Decryptor) ImportKeys(ctx context.Context) error {
|
||||
if d.kustomization.Spec.Decryption == nil || d.kustomization.Spec.Decryption.SecretRef == nil {
|
||||
if d.kustomization.Spec.Decryption == nil ||
|
||||
(d.kustomization.Spec.Decryption.SecretRef == nil && d.sopsAgeSecret == nil) {
|
||||
return nil
|
||||
}
|
||||
|
||||
provider := d.kustomization.Spec.Decryption.Provider
|
||||
switch provider {
|
||||
case DecryptionProviderSOPS:
|
||||
secretRef := d.kustomization.Spec.Decryption.SecretRef
|
||||
|
||||
// We handle the SOPS age global decryption separately, as most of the other
|
||||
// decryption providers already support global decryption in other ways, and
|
||||
// we don't want to introduce duplicate methods of achieving the same.
|
||||
// Furthermore, allowing e.g. cloud provider credentials to be fetched
|
||||
// from this global secret would prevent workload identity from working.
|
||||
if secretRef == nil && d.sopsAgeSecret != nil {
|
||||
var secret corev1.Secret
|
||||
if err := d.client.Get(ctx, *d.sopsAgeSecret, &secret); err != nil {
|
||||
if apierrors.IsNotFound(err) {
|
||||
return err
|
||||
}
|
||||
return fmt.Errorf("cannot get %s SOPS age decryption Secret '%s': %w", provider, *d.sopsAgeSecret, err)
|
||||
}
|
||||
for name, value := range secret.Data {
|
||||
if filepath.Ext(name) == DecryptionAgeExt {
|
||||
if err := d.ageIdentities.Import(string(value)); err != nil {
|
||||
return fmt.Errorf("failed to import '%s' data from %s SOPS age decryption Secret '%s': %w",
|
||||
name, provider, *d.sopsAgeSecret, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
secretName := types.NamespacedName{
|
||||
Namespace: d.kustomization.GetNamespace(),
|
||||
Name: d.kustomization.Spec.Decryption.SecretRef.Name,
|
||||
Name: secretRef.Name,
|
||||
}
|
||||
|
||||
var secret corev1.Secret
|
||||
|
|
|
@ -376,7 +376,7 @@ clientSecret: some-client-secret`),
|
|||
},
|
||||
}
|
||||
|
||||
d, cleanup, err := NewTempDecryptor("", cb.Build(), &kustomization, nil)
|
||||
d, cleanup, err := New(cb.Build(), &kustomization)
|
||||
g.Expect(err).ToNot(HaveOccurred())
|
||||
t.Cleanup(cleanup)
|
||||
|
||||
|
@ -605,7 +605,7 @@ func TestDecryptor_DecryptResource(t *testing.T) {
|
|||
Provider: DecryptionProviderSOPS,
|
||||
}
|
||||
|
||||
d, cleanup, err := NewTempDecryptor("", fake.NewClientBuilder().Build(), kus, nil)
|
||||
d, cleanup, err := New(fake.NewClientBuilder().Build(), kus)
|
||||
g.Expect(err).ToNot(HaveOccurred())
|
||||
t.Cleanup(cleanup)
|
||||
|
||||
|
@ -646,7 +646,7 @@ func TestDecryptor_DecryptResource(t *testing.T) {
|
|||
Provider: DecryptionProviderSOPS,
|
||||
}
|
||||
|
||||
d, cleanup, err := NewTempDecryptor("", fake.NewClientBuilder().Build(), kus, nil)
|
||||
d, cleanup, err := New(fake.NewClientBuilder().Build(), kus)
|
||||
g.Expect(err).ToNot(HaveOccurred())
|
||||
t.Cleanup(cleanup)
|
||||
|
||||
|
@ -681,7 +681,7 @@ func TestDecryptor_DecryptResource(t *testing.T) {
|
|||
Provider: DecryptionProviderSOPS,
|
||||
}
|
||||
|
||||
d, cleanup, err := NewTempDecryptor("", fake.NewClientBuilder().Build(), kus, nil)
|
||||
d, cleanup, err := New(fake.NewClientBuilder().Build(), kus)
|
||||
g.Expect(err).ToNot(HaveOccurred())
|
||||
t.Cleanup(cleanup)
|
||||
|
||||
|
@ -716,7 +716,7 @@ func TestDecryptor_DecryptResource(t *testing.T) {
|
|||
Provider: DecryptionProviderSOPS,
|
||||
}
|
||||
|
||||
d, cleanup, err := NewTempDecryptor("", fake.NewClientBuilder().Build(), kus, nil)
|
||||
d, cleanup, err := New(fake.NewClientBuilder().Build(), kus)
|
||||
g.Expect(err).ToNot(HaveOccurred())
|
||||
t.Cleanup(cleanup)
|
||||
|
||||
|
@ -765,7 +765,7 @@ func TestDecryptor_DecryptResource(t *testing.T) {
|
|||
t.Run("nil resource", func(t *testing.T) {
|
||||
g := NewWithT(t)
|
||||
|
||||
d, cleanup, err := NewTempDecryptor("", fake.NewClientBuilder().Build(), kustomization.DeepCopy(), nil)
|
||||
d, cleanup, err := New(fake.NewClientBuilder().Build(), kustomization.DeepCopy())
|
||||
g.Expect(err).ToNot(HaveOccurred())
|
||||
t.Cleanup(cleanup)
|
||||
|
||||
|
@ -777,7 +777,7 @@ func TestDecryptor_DecryptResource(t *testing.T) {
|
|||
t.Run("no decryption spec", func(t *testing.T) {
|
||||
g := NewWithT(t)
|
||||
|
||||
d, cleanup, err := NewTempDecryptor("", fake.NewClientBuilder().Build(), kustomization.DeepCopy(), nil)
|
||||
d, cleanup, err := New(fake.NewClientBuilder().Build(), kustomization.DeepCopy())
|
||||
g.Expect(err).ToNot(HaveOccurred())
|
||||
t.Cleanup(cleanup)
|
||||
|
||||
|
@ -793,7 +793,7 @@ func TestDecryptor_DecryptResource(t *testing.T) {
|
|||
kus.Spec.Decryption = &kustomizev1.Decryption{
|
||||
Provider: "not-supported",
|
||||
}
|
||||
d, cleanup, err := NewTempDecryptor("", fake.NewClientBuilder().Build(), kus, nil)
|
||||
d, cleanup, err := New(fake.NewClientBuilder().Build(), kus)
|
||||
g.Expect(err).ToNot(HaveOccurred())
|
||||
t.Cleanup(cleanup)
|
||||
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
Copyright 2025 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 decryptor
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
|
||||
"github.com/fluxcd/pkg/cache"
|
||||
)
|
||||
|
||||
// Option is a functional option for configuring the Decryptor.
|
||||
type Option func(o *Decryptor)
|
||||
|
||||
// WithRoot sets the root directory for the Decryptor.
|
||||
func WithRoot(root string) Option {
|
||||
return func(o *Decryptor) {
|
||||
o.root = root
|
||||
}
|
||||
}
|
||||
|
||||
// WithTokenCache sets the token cache for the Decryptor.
|
||||
func WithTokenCache(tokenCache cache.TokenCache) Option {
|
||||
return func(o *Decryptor) {
|
||||
o.tokenCache = &tokenCache
|
||||
}
|
||||
}
|
||||
|
||||
// WithSOPSAgeSecret sets the SOPSAgeSecret for the Decryptor.
|
||||
func WithSOPSAgeSecret(name, namespace string) Option {
|
||||
return func(o *Decryptor) {
|
||||
o.sopsAgeSecret = &types.NamespacedName{
|
||||
Name: name,
|
||||
Namespace: namespace,
|
||||
}
|
||||
}
|
||||
}
|
|
@ -48,9 +48,14 @@ const (
|
|||
// but is missing from the input vars.
|
||||
StrictPostBuildSubstitutions = "StrictPostBuildSubstitutions"
|
||||
|
||||
// GroupChangelog controls groups kubernetes objects names on log output
|
||||
// reduces cardinality of logs when logging to elasticsearch
|
||||
// GroupChangeLog controls whether to group Kubernetes objects names in log output
|
||||
// to reduce cardinality of logs.
|
||||
GroupChangeLog = "GroupChangeLog"
|
||||
|
||||
// AdditiveCELDependencyCheck controls whether the CEL dependency check
|
||||
// should be additive, meaning that the built-in readiness check will
|
||||
// be added to the user-defined CEL expressions.
|
||||
AdditiveCELDependencyCheck = "AdditiveCELDependencyCheck"
|
||||
)
|
||||
|
||||
var features = map[string]bool{
|
||||
|
@ -69,6 +74,9 @@ var features = map[string]bool{
|
|||
// GroupChangeLog
|
||||
// opt-in from v1.5
|
||||
GroupChangeLog: false,
|
||||
// AdditiveCELDependencyCheck
|
||||
// opt-in from v1.7
|
||||
AdditiveCELDependencyCheck: false,
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
Copyright 2025 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 runtime
|
||||
|
||||
import "os"
|
||||
|
||||
// Namespace returns the namespace where the controller is running.
|
||||
func Namespace() string {
|
||||
return os.Getenv("RUNTIME_NAMESPACE")
|
||||
}
|
|
@ -17,11 +17,25 @@ limitations under the License.
|
|||
package awskms
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
// arnRegex matches an AWS ARN, for example:
|
||||
// "arn:aws:kms:us-west-2:107501996527:key/612d5f0p-p1l3-45e6-aca6-a5b005693a48".
|
||||
// The regex matches both KMS keys and aliases, and supports different AWS partition names (aws, aws-cn, aws-us-gov).
|
||||
//
|
||||
// Copied from SOPS:
|
||||
// https://github.com/getsops/sops/blob/b2edaade23453c8774fc28ec491ddbe2b9a4c994/kms/keysource.go#L30-L32
|
||||
//
|
||||
// ref:
|
||||
// https://docs.aws.amazon.com/IAM/latest/UserGuide/reference-arns.html
|
||||
var arnRegex = regexp.MustCompile(`^arn:aws[\w-]*:kms:(.+):[0-9]+:(key|alias)/.+$`)
|
||||
|
||||
// GetRegionFromKMSARN extracts the region from a KMS ARN.
|
||||
func GetRegionFromKMSARN(arn string) string {
|
||||
arn = strings.TrimPrefix(arn, "arn:aws:kms:")
|
||||
return strings.SplitN(arn, ":", 2)[0]
|
||||
m := arnRegex.FindStringSubmatch(arn)
|
||||
if m == nil {
|
||||
return ""
|
||||
}
|
||||
return m[1]
|
||||
}
|
||||
|
|
|
@ -25,10 +25,70 @@ import (
|
|||
)
|
||||
|
||||
func TestGetRegionFromKMSARN(t *testing.T) {
|
||||
g := NewWithT(t)
|
||||
|
||||
arn := "arn:aws:kms:us-east-1:211125720409:key/mrk-3179bb7e88bc42ffb1a27d5038ceea25"
|
||||
|
||||
region := awskms.GetRegionFromKMSARN(arn)
|
||||
g.Expect(region).To(Equal("us-east-1"))
|
||||
for _, tt := range []struct {
|
||||
arn string
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
arn: "arn:aws:kms:us-west-2:107501996527:key/612d5f0p-p1l3-45e6-aca6-a5b005693a48",
|
||||
expected: "us-west-2",
|
||||
},
|
||||
{
|
||||
arn: "arn:aws-cn:kms:cn-north-1:123456789012:key/1234abcd-12ab-34cd-56ef-1234567890ab",
|
||||
expected: "cn-north-1",
|
||||
},
|
||||
{
|
||||
arn: "arn:aws-us-gov:kms:us-gov-west-1:123456789012:key/1234abcd-12ab-34cd-56ef-1234567890ab",
|
||||
expected: "us-gov-west-1",
|
||||
},
|
||||
{
|
||||
arn: "arn:aws:kms:us-west-2:107501996527:alias/my-key-alias",
|
||||
expected: "us-west-2",
|
||||
},
|
||||
{
|
||||
arn: "arn:aws:kms:us-west-2:107501996527:key/",
|
||||
expected: "",
|
||||
},
|
||||
{
|
||||
arn: "arn:aws:kms:us-west-2:107501996527:alias/",
|
||||
expected: "",
|
||||
},
|
||||
{
|
||||
arn: "not-an-arn",
|
||||
expected: "",
|
||||
},
|
||||
{
|
||||
arn: "arn:aws:s3:::my-bucket",
|
||||
expected: "",
|
||||
},
|
||||
{
|
||||
arn: "arn:aws:ec2:us-west-2:123456789012:instance/i-1234567890abcdef0",
|
||||
expected: "",
|
||||
},
|
||||
{
|
||||
arn: "arn:aws:iam::123456789012:user/David",
|
||||
expected: "",
|
||||
},
|
||||
{
|
||||
arn: "arn:aws:lambda:us-west-2:123456789012:function:my-function",
|
||||
expected: "",
|
||||
},
|
||||
{
|
||||
arn: "arn:aws:dynamodb:us-west-2:123456789012:table/my-table",
|
||||
expected: "",
|
||||
},
|
||||
{
|
||||
arn: "arn:aws:rds:us-west-2:123456789012:db:my-database",
|
||||
expected: "",
|
||||
},
|
||||
{
|
||||
arn: "arn:aws:sns:us-west-2:123456789012:my-topic",
|
||||
expected: "",
|
||||
},
|
||||
} {
|
||||
t.Run(tt.arn, func(t *testing.T) {
|
||||
g := NewWithT(t)
|
||||
g.Expect(awskms.GetRegionFromKMSARN(tt.arn)).To(Equal(tt.expected))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
54
main.go
54
main.go
|
@ -55,6 +55,7 @@ import (
|
|||
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1"
|
||||
"github.com/fluxcd/kustomize-controller/internal/controller"
|
||||
"github.com/fluxcd/kustomize-controller/internal/features"
|
||||
intruntime "github.com/fluxcd/kustomize-controller/internal/runtime"
|
||||
// +kubebuilder:scaffold:imports
|
||||
)
|
||||
|
||||
|
@ -96,6 +97,7 @@ func main() {
|
|||
noRemoteBases bool
|
||||
httpRetry int
|
||||
defaultServiceAccount string
|
||||
sopsAgeSecret string
|
||||
featureGates feathelper.FeatureGates
|
||||
disallowedFieldManagers []string
|
||||
tokenCacheOptions pkgcache.TokenFlags
|
||||
|
@ -111,6 +113,7 @@ func main() {
|
|||
"Disallow remote bases usage in Kustomize overlays. When this flag is enabled, all resources must refer to local files included in the source artifact.")
|
||||
flag.IntVar(&httpRetry, "http-retry", 9, "The maximum number of retries when failing to fetch artifacts over HTTP.")
|
||||
flag.StringVar(&defaultServiceAccount, "default-service-account", "", "Default service account used for impersonation.")
|
||||
flag.StringVar(&sopsAgeSecret, "sops-age-secret", "", "The name of a Kubernetes secret in the RUNTIME_NAMESPACE containing a SOPS age decryption key for fallback usage.")
|
||||
flag.StringArrayVar(&disallowedFieldManagers, "override-manager", []string{}, "Field manager disallowed to perform changes on managed resources.")
|
||||
|
||||
clientOptions.BindFlags(flag.CommandLine)
|
||||
|
@ -150,7 +153,7 @@ func main() {
|
|||
|
||||
watchNamespace := ""
|
||||
if !watchOptions.AllNamespaces {
|
||||
watchNamespace = os.Getenv("RUNTIME_NAMESPACE")
|
||||
watchNamespace = intruntime.Namespace()
|
||||
}
|
||||
|
||||
watchSelector, err := runtimeCtrl.GetWatchSelector(watchOptions)
|
||||
|
@ -159,6 +162,12 @@ func main() {
|
|||
os.Exit(1)
|
||||
}
|
||||
|
||||
watchConfigsPredicate, err := runtimeCtrl.GetWatchConfigsPredicate(watchOptions)
|
||||
if err != nil {
|
||||
setupLog.Error(err, "unable to configure watch configs label selector for controller")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
var disableCacheFor []ctrlclient.Object
|
||||
shouldCache, err := features.Enabled(features.CacheSecretsAndConfigMaps)
|
||||
if err != nil {
|
||||
|
@ -255,6 +264,12 @@ func main() {
|
|||
os.Exit(1)
|
||||
}
|
||||
|
||||
additiveCELDependencyCheck, err := features.Enabled(features.AdditiveCELDependencyCheck)
|
||||
if err != nil {
|
||||
setupLog.Error(err, "unable to check feature gate "+features.AdditiveCELDependencyCheck)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
var tokenCache *pkgcache.TokenCache
|
||||
if tokenCacheOptions.MaxSize > 0 {
|
||||
var err error
|
||||
|
@ -269,27 +284,30 @@ func main() {
|
|||
}
|
||||
|
||||
if err = (&controller.KustomizationReconciler{
|
||||
ControllerName: controllerName,
|
||||
DefaultServiceAccount: defaultServiceAccount,
|
||||
Client: mgr.GetClient(),
|
||||
Mapper: restMapper,
|
||||
APIReader: mgr.GetAPIReader(),
|
||||
Metrics: metricsH,
|
||||
EventRecorder: eventRecorder,
|
||||
NoCrossNamespaceRefs: aclOptions.NoCrossNamespaceRefs,
|
||||
NoRemoteBases: noRemoteBases,
|
||||
FailFast: failFast,
|
||||
ConcurrentSSA: concurrentSSA,
|
||||
KubeConfigOpts: kubeConfigOpts,
|
||||
ClusterReader: clusterReader,
|
||||
DisallowedFieldManagers: disallowedFieldManagers,
|
||||
StrictSubstitutions: strictSubstitutions,
|
||||
GroupChangeLog: groupChangeLog,
|
||||
TokenCache: tokenCache,
|
||||
ControllerName: controllerName,
|
||||
DefaultServiceAccount: defaultServiceAccount,
|
||||
SOPSAgeSecret: sopsAgeSecret,
|
||||
Client: mgr.GetClient(),
|
||||
Mapper: restMapper,
|
||||
APIReader: mgr.GetAPIReader(),
|
||||
Metrics: metricsH,
|
||||
EventRecorder: eventRecorder,
|
||||
NoCrossNamespaceRefs: aclOptions.NoCrossNamespaceRefs,
|
||||
NoRemoteBases: noRemoteBases,
|
||||
FailFast: failFast,
|
||||
ConcurrentSSA: concurrentSSA,
|
||||
KubeConfigOpts: kubeConfigOpts,
|
||||
ClusterReader: clusterReader,
|
||||
DisallowedFieldManagers: disallowedFieldManagers,
|
||||
StrictSubstitutions: strictSubstitutions,
|
||||
GroupChangeLog: groupChangeLog,
|
||||
AdditiveCELDependencyCheck: additiveCELDependencyCheck,
|
||||
TokenCache: tokenCache,
|
||||
}).SetupWithManager(ctx, mgr, controller.KustomizationReconcilerOptions{
|
||||
DependencyRequeueInterval: requeueDependency,
|
||||
HTTPRetry: httpRetry,
|
||||
RateLimiter: runtimeCtrl.GetRateLimiter(rateLimiterOptions),
|
||||
WatchConfigsPredicate: watchConfigsPredicate,
|
||||
}); err != nil {
|
||||
setupLog.Error(err, "unable to create controller", "controller", controllerName)
|
||||
os.Exit(1)
|
||||
|
|
Loading…
Reference in New Issue