mirror of https://github.com/crossplane/upjet.git
Compare commits
47 Commits
Author | SHA1 | Date |
---|---|---|
|
4c6bfc216d | |
|
8ff62171a7 | |
|
d1183ac46f | |
|
b4eb48bcba | |
|
cf5fef8c8a | |
|
4b39d500a1 | |
|
2c719f0b96 | |
|
3157e7da7e | |
|
b3b8ef0938 | |
|
88e0308220 | |
|
72f730ba32 | |
|
7e1dd50d8f | |
|
c4427804fd | |
|
0636518853 | |
|
a30bbb511d | |
|
b64c7f1799 | |
|
b20c833a70 | |
|
96746e6b15 | |
|
4b64e6ecb8 | |
|
6ea3bc96f2 | |
|
3d1ab3b9fb | |
|
9d7ed5871c | |
|
a0e93d3827 | |
|
a590156eb9 | |
|
76770f82b2 | |
|
8e9fcfd9c3 | |
|
387fb83493 | |
|
40bae8497f | |
|
96241b0ae5 | |
|
ffb68a034a | |
|
99c75ab7cb | |
|
766236448e | |
|
9505d31da7 | |
|
5ac5cb0b35 | |
|
0af42ca259 | |
|
f794e5eddf | |
|
c4332e6ed1 | |
|
dd08349e54 | |
|
c42638efc0 | |
|
9098842035 | |
|
c275d5ec5c | |
|
f6111127e7 | |
|
60517ef9af | |
|
55edf18c68 | |
|
fe88167010 | |
|
6fdbab083c | |
|
b8639959bc |
1
Makefile
1
Makefile
|
@ -8,6 +8,7 @@
|
|||
|
||||
PROJECT_NAME := upjet
|
||||
PROJECT_REPO := github.com/crossplane/$(PROJECT_NAME)
|
||||
GO_PROJECT := github.com/crossplane/$(PROJECT_NAME)/v2
|
||||
|
||||
# GOLANGCILINT_VERSION is inherited from build submodule by default.
|
||||
# Uncomment below if you need to override the version.
|
||||
|
|
|
@ -9,11 +9,11 @@ import (
|
|||
"path/filepath"
|
||||
|
||||
"github.com/alecthomas/kingpin/v2"
|
||||
"github.com/crossplane/crossplane-runtime/pkg/logging"
|
||||
"github.com/crossplane/crossplane-runtime/v2/pkg/logging"
|
||||
"github.com/spf13/afero"
|
||||
"sigs.k8s.io/controller-runtime/pkg/log/zap"
|
||||
|
||||
"github.com/crossplane/upjet/pkg/transformers"
|
||||
"github.com/crossplane/upjet/v2/pkg/transformers"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
|
|
@ -10,7 +10,7 @@ import (
|
|||
|
||||
"github.com/alecthomas/kingpin/v2"
|
||||
|
||||
"github.com/crossplane/upjet/pkg/registry"
|
||||
"github.com/crossplane/upjet/v2/pkg/registry"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
|
|
@ -116,7 +116,7 @@ conditions:
|
|||
|
||||
```go
|
||||
import (
|
||||
"github.com/crossplane/upjet/pkg/config"
|
||||
"github.com/crossplane/upjet/v2/pkg/config"
|
||||
...
|
||||
)
|
||||
|
||||
|
@ -143,7 +143,7 @@ also omit `bucket` and `bucket_prefix` arguments from the spec with
|
|||
|
||||
```go
|
||||
import (
|
||||
"github.com/crossplane/upjet/pkg/config"
|
||||
"github.com/crossplane/upjet/v2/pkg/config"
|
||||
...
|
||||
)
|
||||
|
||||
|
@ -175,7 +175,7 @@ Here, we can just use [IdentifierFromProvider] configuration:
|
|||
|
||||
```go
|
||||
import (
|
||||
"github.com/crossplane/upjet/pkg/config"
|
||||
"github.com/crossplane/upjet/v2/pkg/config"
|
||||
...
|
||||
)
|
||||
|
||||
|
@ -206,7 +206,7 @@ this id back (`GetIDFn`).
|
|||
|
||||
```go
|
||||
import (
|
||||
"github.com/crossplane/upjet/pkg/config"
|
||||
"github.com/crossplane/upjet/v2/pkg/config"
|
||||
...
|
||||
)
|
||||
|
||||
|
|
|
@ -141,7 +141,7 @@ variables in the `Makefile`:
|
|||
cat <<EOF > config/repository/config.go
|
||||
package repository
|
||||
|
||||
import "github.com/crossplane/upjet/pkg/config"
|
||||
import "github.com/crossplane/upjet/v2/pkg/config"
|
||||
|
||||
// Configure configures individual resources by adding custom ResourceConfigurators.
|
||||
func Configure(p *config.Provider) {
|
||||
|
@ -163,7 +163,7 @@ variables in the `Makefile`:
|
|||
cat <<EOF > config/branch/config.go
|
||||
package branch
|
||||
|
||||
import "github.com/crossplane/upjet/pkg/config"
|
||||
import "github.com/crossplane/upjet/v2/pkg/config"
|
||||
|
||||
func Configure(p *config.Provider) {
|
||||
p.AddResourceConfigurator("github_branch", func(r *config.Resource) {
|
||||
|
|
107
go.mod
107
go.mod
|
@ -2,52 +2,50 @@
|
|||
//
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
module github.com/crossplane/upjet
|
||||
module github.com/crossplane/upjet/v2
|
||||
|
||||
go 1.23.6
|
||||
go 1.24.0
|
||||
|
||||
toolchain go1.24.5
|
||||
|
||||
require (
|
||||
dario.cat/mergo v1.0.1
|
||||
dario.cat/mergo v1.0.2
|
||||
github.com/alecthomas/kingpin/v2 v2.4.0
|
||||
github.com/antchfx/htmlquery v1.2.4
|
||||
github.com/crossplane/crossplane v1.19.1
|
||||
github.com/crossplane/crossplane-runtime v1.19.0
|
||||
github.com/crossplane/crossplane-runtime/v2 v2.0.0-20250730220209-c306b1c8b181
|
||||
github.com/fatih/camelcase v1.0.0
|
||||
github.com/golang/mock v1.6.0
|
||||
github.com/google/go-cmp v0.7.0
|
||||
github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320
|
||||
github.com/hashicorp/hcl/v2 v2.19.1
|
||||
github.com/hashicorp/terraform-json v0.17.1
|
||||
github.com/hashicorp/terraform-plugin-framework v1.4.1
|
||||
github.com/hashicorp/terraform-plugin-go v0.19.0
|
||||
github.com/hashicorp/terraform-plugin-sdk/v2 v2.30.0
|
||||
github.com/hashicorp/go-cty v1.5.0
|
||||
github.com/hashicorp/hcl/v2 v2.23.0
|
||||
github.com/hashicorp/terraform-json v0.25.0
|
||||
github.com/hashicorp/terraform-plugin-framework v1.15.0
|
||||
github.com/hashicorp/terraform-plugin-go v0.28.0
|
||||
github.com/hashicorp/terraform-plugin-sdk/v2 v2.37.0
|
||||
github.com/iancoleman/strcase v0.2.0
|
||||
github.com/json-iterator/go v1.1.12
|
||||
github.com/mitchellh/go-ps v1.0.0
|
||||
github.com/muvaf/typewriter v0.0.0-20210910160850-80e49fe1eb32
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/prometheus/client_golang v1.20.2
|
||||
github.com/spf13/afero v1.11.0
|
||||
github.com/prometheus/client_golang v1.22.0
|
||||
github.com/spf13/afero v1.12.0
|
||||
github.com/tmccombs/hcl2json v0.3.3
|
||||
github.com/yuin/goldmark v1.4.13
|
||||
github.com/zclconf/go-cty v1.14.1
|
||||
github.com/zclconf/go-cty v1.16.2
|
||||
github.com/zclconf/go-cty-yaml v1.0.3
|
||||
golang.org/x/net v0.39.0
|
||||
golang.org/x/tools v0.32.0
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
k8s.io/api v0.32.3
|
||||
k8s.io/apimachinery v0.32.3
|
||||
k8s.io/cli-runtime v0.29.1
|
||||
k8s.io/client-go v0.32.3
|
||||
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
|
||||
sigs.k8s.io/controller-runtime v0.19.0
|
||||
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8
|
||||
sigs.k8s.io/yaml v1.4.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/Masterminds/semver v1.5.0 // indirect
|
||||
github.com/agext/levenshtein v1.2.3 // indirect
|
||||
github.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b // indirect
|
||||
github.com/antchfx/xpath v1.2.0 // indirect
|
||||
|
@ -57,12 +55,11 @@ require (
|
|||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/emicklei/go-restful/v3 v3.12.1 // indirect
|
||||
github.com/evanphx/json-patch v5.9.0+incompatible // indirect
|
||||
github.com/evanphx/json-patch v5.9.11+incompatible // indirect
|
||||
github.com/evanphx/json-patch/v5 v5.9.0 // indirect
|
||||
github.com/fatih/color v1.18.0 // indirect
|
||||
github.com/fsnotify/fsnotify v1.7.0 // indirect
|
||||
github.com/fsnotify/fsnotify v1.8.0 // indirect
|
||||
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
|
||||
github.com/go-errors/errors v1.4.2 // indirect
|
||||
github.com/go-logr/logr v1.4.2 // indirect
|
||||
github.com/go-logr/zapr v1.3.0 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.21.0 // indirect
|
||||
|
@ -72,25 +69,19 @@ require (
|
|||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/golang/protobuf v1.5.4 // indirect
|
||||
github.com/google/btree v1.1.2 // indirect
|
||||
github.com/google/gnostic-models v0.6.9-0.20230804172637-c7be7c783f49 // indirect
|
||||
github.com/google/gofuzz v1.2.0 // indirect
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
|
||||
github.com/google/gnostic-models v0.6.9 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect
|
||||
github.com/hashicorp/go-hclog v1.5.0 // indirect
|
||||
github.com/hashicorp/go-plugin v1.5.1 // indirect
|
||||
github.com/hashicorp/go-hclog v1.6.3 // indirect
|
||||
github.com/hashicorp/go-plugin v1.6.3 // indirect
|
||||
github.com/hashicorp/go-uuid v1.0.3 // indirect
|
||||
github.com/hashicorp/go-version v1.6.0 // indirect
|
||||
github.com/hashicorp/go-version v1.7.0 // indirect
|
||||
github.com/hashicorp/logutils v1.0.0 // indirect
|
||||
github.com/hashicorp/terraform-plugin-log v0.9.0 // indirect
|
||||
github.com/hashicorp/terraform-registry-address v0.2.2 // indirect
|
||||
github.com/hashicorp/terraform-registry-address v0.2.5 // indirect
|
||||
github.com/hashicorp/terraform-svchost v0.1.1 // indirect
|
||||
github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d // indirect
|
||||
github.com/imdario/mergo v0.3.16 // indirect
|
||||
github.com/hashicorp/yamux v0.1.1 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/klauspost/compress v1.17.9 // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
|
@ -101,47 +92,45 @@ require (
|
|||
github.com/mitchellh/reflectwalk v1.0.2 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/oklog/run v1.0.0 // indirect
|
||||
github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
|
||||
github.com/prometheus/client_model v0.6.1 // indirect
|
||||
github.com/prometheus/common v0.55.0 // indirect
|
||||
github.com/prometheus/common v0.62.0 // indirect
|
||||
github.com/prometheus/procfs v0.15.1 // indirect
|
||||
github.com/spf13/cobra v1.8.1 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/spf13/cobra v1.9.1 // indirect
|
||||
github.com/spf13/pflag v1.0.6 // indirect
|
||||
github.com/vmihailenco/msgpack v4.0.4+incompatible // indirect
|
||||
github.com/vmihailenco/msgpack/v5 v5.3.5 // indirect
|
||||
github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect
|
||||
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
|
||||
github.com/x448/float16 v0.8.4 // indirect
|
||||
github.com/xhit/go-str2duration/v2 v2.1.0 // indirect
|
||||
github.com/xlab/treeprint v1.2.0 // indirect
|
||||
go.opentelemetry.io/otel v1.33.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.33.0 // indirect
|
||||
go.starlark.net v0.0.0-20230525235612-a134d8f9ddca // indirect
|
||||
go.opentelemetry.io/otel v1.35.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.35.0 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
go.uber.org/zap v1.27.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa // indirect
|
||||
golang.org/x/mod v0.24.0 // indirect
|
||||
golang.org/x/oauth2 v0.28.0 // indirect
|
||||
golang.org/x/sync v0.13.0 // indirect
|
||||
golang.org/x/sys v0.32.0 // indirect
|
||||
golang.org/x/oauth2 v0.29.0 // indirect
|
||||
golang.org/x/sync v0.14.0 // indirect
|
||||
golang.org/x/sys v0.33.0 // indirect
|
||||
golang.org/x/term v0.31.0 // indirect
|
||||
golang.org/x/text v0.24.0 // indirect
|
||||
golang.org/x/time v0.7.0 // indirect
|
||||
golang.org/x/text v0.25.0 // indirect
|
||||
golang.org/x/time v0.11.0 // indirect
|
||||
gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect
|
||||
google.golang.org/appengine v1.6.8 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576 // indirect
|
||||
google.golang.org/grpc v1.68.0 // indirect
|
||||
google.golang.org/protobuf v1.35.2 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a // indirect
|
||||
google.golang.org/grpc v1.72.1 // 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
|
||||
k8s.io/apiextensions-apiserver v0.32.3 // indirect
|
||||
k8s.io/component-base v0.32.3 // indirect
|
||||
k8s.io/apiextensions-apiserver v0.33.0 // indirect
|
||||
k8s.io/code-generator v0.33.0 // indirect
|
||||
k8s.io/component-base v0.33.0 // indirect
|
||||
k8s.io/gengo/v2 v2.0.0-20250207200755-1244d31929d7 // indirect
|
||||
k8s.io/klog/v2 v2.130.1 // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f // indirect
|
||||
sigs.k8s.io/controller-tools v0.16.5 // indirect
|
||||
sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3 // indirect
|
||||
sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3 // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff // indirect
|
||||
sigs.k8s.io/controller-tools v0.18.0 // 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.6.0 // indirect
|
||||
)
|
||||
|
|
289
go.sum
289
go.sum
|
@ -1,11 +1,5 @@
|
|||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s=
|
||||
dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
|
||||
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 h1:bvDV9vkmnHYOMsOr4WLk+Vo07yKIzd94sVoIqshQ4bU=
|
||||
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww=
|
||||
github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
|
||||
dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8=
|
||||
dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA=
|
||||
github.com/agext/levenshtein v1.2.1/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558=
|
||||
github.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7lmo=
|
||||
github.com/agext/levenshtein v1.2.3/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558=
|
||||
|
@ -30,29 +24,20 @@ 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/bufbuild/protocompile v0.4.0 h1:LbFKd2XowZvQ/kajzguUp2DC9UEIQhIq77fZZlaQsNA=
|
||||
github.com/bufbuild/protocompile v0.4.0/go.mod h1:3v93+mbWn/v3xzN+31nwkJfrEpAUwp+BagBSZWx+TP8=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/crossplane/crossplane v1.19.1 h1:gSLvOeJ7IaOPAsX0hakgl4vYNJYkDlBDPMw4XvUPVZk=
|
||||
github.com/crossplane/crossplane v1.19.1/go.mod h1:ysqAAphb2yM1MLZbF6gOJOveK0fhM8ulAb5Ui+cLnio=
|
||||
github.com/crossplane/crossplane-runtime v1.19.0 h1:yZmF8cYy8/PYiA+aF3ONjVinfuV06Vi3hHQwjYR2Qak=
|
||||
github.com/crossplane/crossplane-runtime v1.19.0/go.mod h1:z8CV6dXxO5yxzfJGa4bgnWuyAnjZ3hY19cqGDcr5Bg0=
|
||||
github.com/crossplane/crossplane-runtime/v2 v2.0.0-20250730220209-c306b1c8b181 h1:yU9+BtCiiMmymYt499egG5FZ1IQ7WddSi1V6H0h0DTk=
|
||||
github.com/crossplane/crossplane-runtime/v2 v2.0.0-20250730220209-c306b1c8b181/go.mod h1:pkd5UzmE8esaZAApevMutR832GjJ1Qgc5Ngr78ByxrI=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/emicklei/go-restful/v3 v3.12.1 h1:PJMDIM/ak7btuL8Ex0iYET9hxM3CI2sjZtzpL63nKAU=
|
||||
github.com/emicklei/go-restful/v3 v3.12.1/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/evanphx/json-patch v5.9.0+incompatible h1:fBXyNpNMuTTDdquAq/uisOr2lShz4oaXpDTX2bLe7ls=
|
||||
github.com/evanphx/json-patch v5.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
||||
github.com/evanphx/json-patch v5.9.11+incompatible h1:ixHHqfcGvxhWkniF1tWxBHA0yb4Z+d1UQi45df52xW8=
|
||||
github.com/evanphx/json-patch v5.9.11+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
||||
github.com/evanphx/json-patch/v5 v5.9.0 h1:kcBlZQbplgElYIlo/n1hJbls2z/1awpXxpRi0/FOJfg=
|
||||
github.com/evanphx/json-patch/v5 v5.9.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ=
|
||||
github.com/fatih/camelcase v1.0.0 h1:hxNvNX/xYBp0ovncs8WyWZrOrpBNub/JfaMvbURyft8=
|
||||
|
@ -60,14 +45,14 @@ github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwo
|
|||
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
|
||||
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/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
|
||||
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
|
||||
github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M=
|
||||
github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
|
||||
github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E=
|
||||
github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ=
|
||||
github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
|
||||
github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
|
||||
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/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=
|
||||
github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg=
|
||||
github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
|
||||
|
@ -85,39 +70,22 @@ github.com/gobuffalo/flect v1.0.3 h1:xeWBM2nui+qnVvNM4S3foBhCAL2XgPU+a7FdpelbTq4
|
|||
github.com/gobuffalo/flect v1.0.3/go.mod h1:A5msMlrHtLqh9umBSnvabjsMrCcCpAyzglnDvkbYKHs=
|
||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
|
||||
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
|
||||
github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||
github.com/google/addlicense v0.0.0-20210428195630-6d92264d7170/go.mod h1:EMjYTRimagHs1FwlIqKyX3wAM0u3rA+McvlIIWmSamA=
|
||||
github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU=
|
||||
github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
|
||||
github.com/google/gnostic-models v0.6.9-0.20230804172637-c7be7c783f49 h1:0VpGH+cDhbDtdcweoyCVsF3fhN8kejK6rFe/2FFX2nU=
|
||||
github.com/google/gnostic-models v0.6.9-0.20230804172637-c7be7c783f49/go.mod h1:BkkQ4L1KS1xMt2aWSPStnn55ChGC0DPOn2FQYj+f25M=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
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/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
|
@ -128,47 +96,41 @@ 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/pprof v0.0.0-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgYQBbFN4U4JNXUNYpxael3UzMyo=
|
||||
github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
|
||||
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/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA=
|
||||
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
|
||||
github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320 h1:1/D3zfFHttUKaCaGKZ/dR2roBXv0vKbSCnssIldfQdI=
|
||||
github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320/go.mod h1:EiZBMaudVLy8fmjf9Npq1dq9RalhveqZG5w/yz3mHWs=
|
||||
github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c=
|
||||
github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
|
||||
github.com/hashicorp/go-plugin v1.5.1 h1:oGm7cWBaYIp3lJpx1RUEfLWophprE2EV/KUeqBYo+6k=
|
||||
github.com/hashicorp/go-plugin v1.5.1/go.mod h1:w1sAEES3g3PuV/RzUrgow20W2uErMly84hhD3um1WL4=
|
||||
github.com/hashicorp/go-cty v1.5.0 h1:EkQ/v+dDNUqnuVpmS5fPqyY71NXVgT5gf32+57xY8g0=
|
||||
github.com/hashicorp/go-cty v1.5.0/go.mod h1:lFUCG5kd8exDobgSfyj4ONE/dc822kiYMguVKdHGMLM=
|
||||
github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k=
|
||||
github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
|
||||
github.com/hashicorp/go-plugin v1.6.3 h1:xgHB+ZUSYeuJi96WtxEjzi23uh7YQpznjGh0U0UUrwg=
|
||||
github.com/hashicorp/go-plugin v1.6.3/go.mod h1:MRobyh+Wc/nYy1V4KAXUiYfzxoYhs7V1mlH1Z7iY2h0=
|
||||
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
|
||||
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek=
|
||||
github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||
github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY=
|
||||
github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||
github.com/hashicorp/hcl/v2 v2.9.1/go.mod h1:FwWsfWEjyV/CMj8s/gqAuiviY72rJ1/oayI9WftqcKg=
|
||||
github.com/hashicorp/hcl/v2 v2.19.1 h1://i05Jqznmb2EXqa39Nsvyan2o5XyMowW5fnCKW5RPI=
|
||||
github.com/hashicorp/hcl/v2 v2.19.1/go.mod h1:ThLC89FV4p9MPW804KVbe/cEXoQ8NZEh+JtMeeGErHE=
|
||||
github.com/hashicorp/hcl/v2 v2.23.0 h1:Fphj1/gCylPxHutVSEOf2fBOh1VE4AuLV7+kbJf3qos=
|
||||
github.com/hashicorp/hcl/v2 v2.23.0/go.mod h1:62ZYHrXgPoX8xBnzl8QzbWq4dyDsDtfCRgIq1rbJEvA=
|
||||
github.com/hashicorp/logutils v1.0.0 h1:dLEQVugN8vlakKOUE3ihGLTZJRB4j+M2cdTm/ORI65Y=
|
||||
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
|
||||
github.com/hashicorp/terraform-json v0.17.1 h1:eMfvh/uWggKmY7Pmb3T85u86E2EQg6EQHgyRwf3RkyA=
|
||||
github.com/hashicorp/terraform-json v0.17.1/go.mod h1:Huy6zt6euxaY9knPAFKjUITn8QxUFIe9VuSzb4zn/0o=
|
||||
github.com/hashicorp/terraform-plugin-framework v1.4.1 h1:ZC29MoB3Nbov6axHdgPbMz7799pT5H8kIrM8YAsaVrs=
|
||||
github.com/hashicorp/terraform-plugin-framework v1.4.1/go.mod h1:XC0hPcQbBvlbxwmjxuV/8sn8SbZRg4XwGMs22f+kqV0=
|
||||
github.com/hashicorp/terraform-plugin-go v0.19.0 h1:BuZx/6Cp+lkmiG0cOBk6Zps0Cb2tmqQpDM3iAtnhDQU=
|
||||
github.com/hashicorp/terraform-plugin-go v0.19.0/go.mod h1:EhRSkEPNoylLQntYsk5KrDHTZJh9HQoumZXbOGOXmec=
|
||||
github.com/hashicorp/terraform-json v0.25.0 h1:rmNqc/CIfcWawGiwXmRuiXJKEiJu1ntGoxseG1hLhoQ=
|
||||
github.com/hashicorp/terraform-json v0.25.0/go.mod h1:sMKS8fiRDX4rVlR6EJUMudg1WcanxCMoWwTLkgZP/vc=
|
||||
github.com/hashicorp/terraform-plugin-framework v1.15.0 h1:LQ2rsOfmDLxcn5EeIwdXFtr03FVsNktbbBci8cOKdb4=
|
||||
github.com/hashicorp/terraform-plugin-framework v1.15.0/go.mod h1:hxrNI/GY32KPISpWqlCoTLM9JZsGH3CyYlir09bD/fI=
|
||||
github.com/hashicorp/terraform-plugin-go v0.28.0 h1:zJmu2UDwhVN0J+J20RE5huiF3XXlTYVIleaevHZgKPA=
|
||||
github.com/hashicorp/terraform-plugin-go v0.28.0/go.mod h1:FDa2Bb3uumkTGSkTFpWSOwWJDwA7bf3vdP3ltLDTH6o=
|
||||
github.com/hashicorp/terraform-plugin-log v0.9.0 h1:i7hOA+vdAItN1/7UrfBqBwvYPQ9TFvymaRGZED3FCV0=
|
||||
github.com/hashicorp/terraform-plugin-log v0.9.0/go.mod h1:rKL8egZQ/eXSyDqzLUuwUYLVdlYeamldAHSxjUFADow=
|
||||
github.com/hashicorp/terraform-plugin-sdk/v2 v2.30.0 h1:X7vB6vn5tON2b49ILa4W7mFAsndeqJ7bZFOGbVO+0Cc=
|
||||
github.com/hashicorp/terraform-plugin-sdk/v2 v2.30.0/go.mod h1:ydFcxbdj6klCqYEPkPvdvFKiNGKZLUs+896ODUXCyao=
|
||||
github.com/hashicorp/terraform-registry-address v0.2.2 h1:lPQBg403El8PPicg/qONZJDC6YlgCVbWDtNmmZKtBno=
|
||||
github.com/hashicorp/terraform-registry-address v0.2.2/go.mod h1:LtwNbCihUoUZ3RYriyS2wF/lGPB6gF9ICLRtuDk7hSo=
|
||||
github.com/hashicorp/terraform-plugin-sdk/v2 v2.37.0 h1:NFPMacTrY/IdcIcnUB+7hsore1ZaRWU9cnB6jFoBnIM=
|
||||
github.com/hashicorp/terraform-plugin-sdk/v2 v2.37.0/go.mod h1:QYmYnLfsosrxjCnGY1p9c7Zj6n9thnEE+7RObeYs3fA=
|
||||
github.com/hashicorp/terraform-registry-address v0.2.5 h1:2GTftHqmUhVOeuu9CW3kwDkRe4pcBDq0uuK5VJngU1M=
|
||||
github.com/hashicorp/terraform-registry-address v0.2.5/go.mod h1:PpzXWINwB5kuVS5CA7m1+eO2f1jKb5ZDIxrOPfpnGkg=
|
||||
github.com/hashicorp/terraform-svchost v0.1.1 h1:EZZimZ1GxdqFRinZ1tpJwVxxt49xc/S52uzrw4x0jKQ=
|
||||
github.com/hashicorp/terraform-svchost v0.1.1/go.mod h1:mNsjQfZyf/Jhz35v6/0LWcv26+X7JPS+buii2c9/ctc=
|
||||
github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d h1:kJCB4vdITiW1eC1vq2e6IsrXKrZit1bv/TDYFGMp4BQ=
|
||||
github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
|
||||
github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE=
|
||||
github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ=
|
||||
github.com/iancoleman/strcase v0.2.0 h1:05I4QRnGpI0m37iZQRuskXh+w77mr6Z41lwQzuHLwW0=
|
||||
github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho=
|
||||
github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4=
|
||||
github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY=
|
||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
github.com/jhump/protoreflect v1.15.1 h1:HUMERORf3I3ZdX05WaQ6MIpd/NJ434hTp5YiKgfCL6c=
|
||||
|
@ -179,8 +141,8 @@ github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnr
|
|||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
|
||||
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
|
||||
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
|
||||
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
|
@ -221,8 +183,6 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w
|
|||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/2gBQ3RWajuToeY6ZtZTIKv2v7ThUy5KKusIT0yc0=
|
||||
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||
github.com/muvaf/typewriter v0.0.0-20210910160850-80e49fe1eb32 h1:yBQlHXLeUJL3TWVmzup5uT3wG5FLxhiTAiTsmNVocys=
|
||||
|
@ -235,38 +195,32 @@ github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
|
|||
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
|
||||
github.com/onsi/ginkgo/v2 v2.21.0 h1:7rg/4f3rB88pb5obDgNZrNHrQ4e6WpjonchcpuBRnZM=
|
||||
github.com/onsi/ginkgo/v2 v2.21.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo=
|
||||
github.com/onsi/gomega v1.35.1 h1:Cwbd75ZBPxFSuZ6T+rN/WCb/gOc6YgFBXLlZLhC7Ds4=
|
||||
github.com/onsi/gomega v1.35.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog=
|
||||
github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI=
|
||||
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
|
||||
github.com/onsi/gomega v1.37.0 h1:CdEG8g0S133B4OswTDC/5XPSzE1OeP29QOioj2PID2Y=
|
||||
github.com/onsi/gomega v1.37.0/go.mod h1:8D9+Txp43QWKhM24yyOBEdpkzN8FvJyAwecBgsU4KU0=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_golang v1.20.2 h1:5ctymQzZlyOON1666svgwn3s6IKWgfbjsejTMiXIyjg=
|
||||
github.com/prometheus/client_golang v1.20.2/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q=
|
||||
github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0=
|
||||
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
|
||||
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
|
||||
github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc=
|
||||
github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8=
|
||||
github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io=
|
||||
github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I=
|
||||
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
|
||||
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
|
||||
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
|
||||
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
|
||||
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
|
||||
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
||||
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8=
|
||||
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4=
|
||||
github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
|
||||
github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
|
||||
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
|
||||
github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
|
||||
github.com/spf13/afero v1.12.0 h1:UcOPyRBYczmFn6yvphxkn9ZEOY65cpwGKb5mL36mrqs=
|
||||
github.com/spf13/afero v1.12.0/go.mod h1:ZTlWwG4/ahT8W7T0WQ5uYmjI9duaLQGy3Q2OAl4sk/4=
|
||||
github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo=
|
||||
github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0=
|
||||
github.com/spf13/pflag v1.0.2/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
|
||||
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
|
@ -274,8 +228,6 @@ github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
|
|||
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
|
@ -290,8 +242,8 @@ github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6Ac
|
|||
github.com/vmihailenco/msgpack v4.0.4+incompatible h1:dSLoQfGFAo3F6OoNhwUmLwVgaUXK79GlxNBwueZn0xI=
|
||||
github.com/vmihailenco/msgpack v4.0.4+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk=
|
||||
github.com/vmihailenco/msgpack/v4 v4.3.12/go.mod h1:gborTTJjAo/GWTqqRjrLCn9pgNN+NXzzngzBKDPIqw4=
|
||||
github.com/vmihailenco/msgpack/v5 v5.3.5 h1:5gO0H1iULLWGhs2H5tbAHIZTV8/cYafcFOr9znI5mJU=
|
||||
github.com/vmihailenco/msgpack/v5 v5.3.5/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q/V5KbhBonMG9jc=
|
||||
github.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IUPn0Bjt8=
|
||||
github.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok=
|
||||
github.com/vmihailenco/tagparser v0.1.1/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI=
|
||||
github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g=
|
||||
github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds=
|
||||
|
@ -299,8 +251,6 @@ 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/xhit/go-str2duration/v2 v2.1.0 h1:lxklc02Drh6ynqX+DdPyp5pCKLUQpRT8bp8Ydu2Bstc=
|
||||
github.com/xhit/go-str2duration/v2 v2.1.0/go.mod h1:ohY8p+0f07DiV6Em5LKB0s2YpLtXVyJfNt1+BlmyAsU=
|
||||
github.com/xlab/treeprint v1.2.0 h1:HzHnuAF1plUN2zGlAFHbSQP2qJ0ZAD3XF5XD7OesXRQ=
|
||||
github.com/xlab/treeprint v1.2.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
|
@ -309,17 +259,25 @@ github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5t
|
|||
github.com/zclconf/go-cty v1.2.0/go.mod h1:hOPWgoHbaTUnI5k4D2ld+GRpFJSCe6bCM7m1q/N4PQ8=
|
||||
github.com/zclconf/go-cty v1.8.0/go.mod h1:vVKLxnk3puL4qRAv72AO+W99LUD4da90g3uUAzyuvAk=
|
||||
github.com/zclconf/go-cty v1.8.1/go.mod h1:vVKLxnk3puL4qRAv72AO+W99LUD4da90g3uUAzyuvAk=
|
||||
github.com/zclconf/go-cty v1.14.1 h1:t9fyA35fwjjUMcmL5hLER+e/rEPqrbCK1/OSE4SI9KA=
|
||||
github.com/zclconf/go-cty v1.14.1/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE=
|
||||
github.com/zclconf/go-cty v1.16.2 h1:LAJSwc3v81IRBZyUVQDUdZ7hs3SYs9jv0eZJDWHD/70=
|
||||
github.com/zclconf/go-cty v1.16.2/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE=
|
||||
github.com/zclconf/go-cty-debug v0.0.0-20191215020915-b22d67c1ba0b/go.mod h1:ZRKQfBXbGkpdV6QMzT3rU1kSTAnfu1dO8dPKjYprgj8=
|
||||
github.com/zclconf/go-cty-debug v0.0.0-20240509010212-0d6042c53940 h1:4r45xpDWB6ZMSMNJFMOjqrGHynW3DIBuR2H9j0ug+Mo=
|
||||
github.com/zclconf/go-cty-debug v0.0.0-20240509010212-0d6042c53940/go.mod h1:CmBdvvj3nqzfzJ6nTCIwDTPZ56aVGvDrmztiO5g3qrM=
|
||||
github.com/zclconf/go-cty-yaml v1.0.3 h1:og/eOQ7lvA/WWhHGFETVWNduJM7Rjsv2RRpx1sdFMLc=
|
||||
github.com/zclconf/go-cty-yaml v1.0.3/go.mod h1:9YLUH4g7lOhVWqUbctnVlZ5KLpg7JAprQNgxSZ1Gyxs=
|
||||
go.opentelemetry.io/otel v1.33.0 h1:/FerN9bax5LoK51X/sI0SVYrjSE0/yUL7DpxW4K3FWw=
|
||||
go.opentelemetry.io/otel v1.33.0/go.mod h1:SUUkR6csvUQl+yjReHu5uM3EtVV7MBm5FHKRlNx4I8I=
|
||||
go.opentelemetry.io/otel/trace v1.33.0 h1:cCJuF7LRjUFso9LPnEAHJDB2pqzp+hbO8eu1qqW2d/s=
|
||||
go.opentelemetry.io/otel/trace v1.33.0/go.mod h1:uIcdVUZMpTAmz0tI1z04GoVSezK37CbGV4fr1f2nBck=
|
||||
go.starlark.net v0.0.0-20230525235612-a134d8f9ddca h1:VdD38733bfYv5tUZwEIskMM93VanwNIi5bIKnDrJdEY=
|
||||
go.starlark.net v0.0.0-20230525235612-a134d8f9ddca/go.mod h1:jxU+3+j+71eXOW14274+SmmuW82qJzl6iZSeqEtTGds=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
|
||||
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/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.34.0 h1:95zS4k/2GOy069d321O8jWgYsW3MzVV+KuSPKp7Wr1A=
|
||||
go.opentelemetry.io/otel/sdk v1.34.0/go.mod h1:0e/pNiaMAqaykJGKbi+tSjWfNNHMTxoC9qANsCzbyxU=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.34.0 h1:5CeK9ujjbFVL5c1PhLuStg1wxA7vQv7ce1EK0Gyvahk=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.34.0/go.mod h1:jQ/r8Ze28zRKoNRdkjCZxfs6YvBTG1+YIqyFVFYec5w=
|
||||
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.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||
|
@ -331,23 +289,15 @@ golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8U
|
|||
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.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa h1:ELnwvuAXPNtPk1TJRuGkI9fDTwym6AYBu0qzT8AcHdI=
|
||||
golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU=
|
||||
golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180811021610-c39426892332/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
|
@ -360,19 +310,16 @@ golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96b
|
|||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY=
|
||||
golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.28.0 h1:CrgCKl8PPAVtLnU3c+EDw6x11699EWlsDeWNWKdIOkc=
|
||||
golang.org/x/oauth2 v0.28.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8=
|
||||
golang.org/x/oauth2 v0.29.0 h1:WdYw2tdTK1S8olAzWHdgeqfy+Mtm9XNhv/xJsY65d98=
|
||||
golang.org/x/oauth2 v0.29.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-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.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610=
|
||||
golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ=
|
||||
golang.org/x/sync v0.14.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-20190502175342-a43fa875dd82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
|
@ -389,15 +336,13 @@ golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
|
||||
golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
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.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.31.0 h1:erwDkOK1Msy6offm1mOgvspSkslFnIGsFnxOKoufg3o=
|
||||
golang.org/x/term v0.31.0/go.mod h1:R4BeIy7D95HzImkxGkTW1UQTtP54tio2RyHz7PwK0aw=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
|
@ -406,15 +351,11 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
|||
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
||||
golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0=
|
||||
golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU=
|
||||
golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ=
|
||||
golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
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/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
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=
|
||||
|
@ -430,32 +371,17 @@ golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8T
|
|||
gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw=
|
||||
gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM=
|
||||
google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576 h1:8ZmaLZE4XWrtU3MyClkYqqtl6Oegr3235h7jxsDyqCY=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.68.0 h1:aHQeeJbo8zAkAa3pRzrVjZlbz6uSfeOXlJNQM0RAbz0=
|
||||
google.golang.org/grpc v1.68.0/go.mod h1:fmSPC5AsjSBCK54MyHRx48kpOti1/jRfOlwEWywNjWA=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a h1:51aaUVRocpvUOSQKM6Q7VuoaktNIaMCLuhZB6DKksq4=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a/go.mod h1:uRxBH1mhmO8PGhU89cMcHaXKZqO+OfakD8QQO0oYwlQ=
|
||||
google.golang.org/grpc v1.72.1 h1:HR03wO6eyZ7lknl75XlxABNVLLFc2PAb6mHlYh756mA=
|
||||
google.golang.org/grpc v1.72.1/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.35.2 h1:8Ar7bF+apOIoThw1EdZl0p1oWvMqTHmpA2fRTyZO8io=
|
||||
google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||
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=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
|
@ -471,38 +397,35 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
|||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
k8s.io/api v0.32.3 h1:Hw7KqxRusq+6QSplE3NYG4MBxZw1BZnq4aP4cJVINls=
|
||||
k8s.io/api v0.32.3/go.mod h1:2wEDTXADtm/HA7CCMD8D8bK4yuBUptzaRhYcYEEYA3k=
|
||||
k8s.io/apiextensions-apiserver v0.32.3 h1:4D8vy+9GWerlErCwVIbcQjsWunF9SUGNu7O7hiQTyPY=
|
||||
k8s.io/apiextensions-apiserver v0.32.3/go.mod h1:8YwcvVRMVzw0r1Stc7XfGAzB/SIVLunqApySV5V7Dss=
|
||||
k8s.io/apimachinery v0.32.3 h1:JmDuDarhDmA/Li7j3aPrwhpNBA94Nvk5zLeOge9HH1U=
|
||||
k8s.io/apimachinery v0.32.3/go.mod h1:GpHVgxoKlTxClKcteaeuF1Ul/lDVb74KpZcxcmLDElE=
|
||||
k8s.io/cli-runtime v0.29.1 h1:By3WVOlEWYfyxhGko0f/IuAOLQcbBSMzwSaDren2JUs=
|
||||
k8s.io/cli-runtime v0.29.1/go.mod h1:vjEY9slFp8j8UoMhV5AlO8uulX9xk6ogfIesHobyBDU=
|
||||
k8s.io/client-go v0.32.3 h1:RKPVltzopkSgHS7aS98QdscAgtgah/+zmpAogooIqVU=
|
||||
k8s.io/client-go v0.32.3/go.mod h1:3v0+3k4IcT9bXTc4V2rt+d2ZPPG700Xy6Oi0Gdl2PaY=
|
||||
k8s.io/component-base v0.32.3 h1:98WJvvMs3QZ2LYHBzvltFSeJjEx7t5+8s71P7M74u8k=
|
||||
k8s.io/component-base v0.32.3/go.mod h1:LWi9cR+yPAv7cu2X9rZanTiFKB2kHA+JjmhkKjCZRpI=
|
||||
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/client-go v0.33.0 h1:UASR0sAYVUzs2kYuKn/ZakZlcs2bEHaizrrHUZg0G98=
|
||||
k8s.io/client-go v0.33.0/go.mod h1:kGkd+l/gNGg8GYWAPr0xF1rRKvVWvzh9vmZAMXtaKOg=
|
||||
k8s.io/code-generator v0.33.0 h1:B212FVl6EFqNmlgdOZYWNi77yBv+ed3QgQsMR8YQCw4=
|
||||
k8s.io/code-generator v0.33.0/go.mod h1:KnJRokGxjvbBQkSJkbVuBbu6z4B0rC7ynkpY5Aw6m9o=
|
||||
k8s.io/component-base v0.33.0 h1:Ot4PyJI+0JAD9covDhwLp9UNkUja209OzsJ4FzScBNk=
|
||||
k8s.io/component-base v0.33.0/go.mod h1:aXYZLbw3kihdkOPMDhWbjGCO6sg+luw554KP51t8qCU=
|
||||
k8s.io/gengo/v2 v2.0.0-20250207200755-1244d31929d7 h1:2OX19X59HxDprNCVrWi6jb7LW1PoqTlYqEq5H2oetog=
|
||||
k8s.io/gengo/v2 v2.0.0-20250207200755-1244d31929d7/go.mod h1:EJykeLsmFC60UQbYJezXkEsG2FLrt0GPNkU5iK5GWxU=
|
||||
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-20241105132330-32ad38e42d3f h1:GA7//TjRY9yWGy1poLzYYJJ4JRdzg3+O6e8I+e+8T5Y=
|
||||
k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f/go.mod h1:R/HEjbvWI0qdfb8viZUeVZm0X6IZnxAydC7YU42CMw4=
|
||||
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/utils v0.0.0-20250321185631-1f6e0b77f77e h1:KqK5c/ghOm8xkHYhlodbp6i6+r+ChV2vuAuVRdFbLro=
|
||||
k8s.io/utils v0.0.0-20250321185631-1f6e0b77f77e/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
|
||||
sigs.k8s.io/controller-runtime v0.19.0 h1:nWVM7aq+Il2ABxwiCizrVDSlmDcshi9llbaFbC0ji/Q=
|
||||
sigs.k8s.io/controller-runtime v0.19.0/go.mod h1:iRmWllt8IlaLjvTTDLhRBXIEtkCK6hwVBJJsYS9Ajf4=
|
||||
sigs.k8s.io/controller-tools v0.16.5 h1:5k9FNRqziBPwqr17AMEPPV/En39ZBplLAdOwwQHruP4=
|
||||
sigs.k8s.io/controller-tools v0.16.5/go.mod h1:8vztuRVzs8IuuJqKqbXCSlXcw+lkAv/M2sTpg55qjMY=
|
||||
sigs.k8s.io/controller-tools v0.18.0 h1:rGxGZCZTV2wJreeRgqVoWab/mfcumTMmSwKzoM9xrsE=
|
||||
sigs.k8s.io/controller-tools v0.18.0/go.mod h1:gLKoiGBriyNh+x1rWtUQnakUYEujErjXs9pf+x/8n1U=
|
||||
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.13.5-0.20230601165947-6ce0bf390ce3 h1:XX3Ajgzov2RKUdc5jW3t5jwY7Bo7dcRm+tFxT+NfgY0=
|
||||
sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3/go.mod h1:9n16EZKMhXBNSiUC5kSdFQJkdH3zbxS/JoO619G1VAY=
|
||||
sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3 h1:W6cLQc5pnqM7vh3b7HvGNfXrJ/xL6BDMS0v1V/HHg5U=
|
||||
sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3/go.mod h1:JWP1Fj0VWGHyw3YUPjXSQnRnrwezrZSrApfX5S0nIag=
|
||||
sigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016 h1:kXv6kKdoEtedwuqMmkqhbkgvYKeycVbC8+iPCP9j5kQ=
|
||||
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.6.0 h1:IUA9nvMmnKWcj5jl84xn+T5MnlZKThmUW1TdblaLVAc=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.6.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps=
|
||||
sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
|
||||
|
|
|
@ -7,7 +7,7 @@ package config
|
|||
import (
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/crossplane/upjet/pkg/resource/json"
|
||||
"github.com/crossplane/upjet/v2/pkg/resource/json"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
|
@ -10,9 +10,9 @@ import (
|
|||
fwresource "github.com/hashicorp/terraform-plugin-framework/resource"
|
||||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
|
||||
|
||||
"github.com/crossplane/upjet/pkg/config/conversion"
|
||||
"github.com/crossplane/upjet/pkg/registry"
|
||||
tjname "github.com/crossplane/upjet/pkg/types/name"
|
||||
"github.com/crossplane/upjet/v2/pkg/config/conversion"
|
||||
"github.com/crossplane/upjet/v2/pkg/registry"
|
||||
tjname "github.com/crossplane/upjet/v2/pkg/types/name"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -33,17 +33,17 @@ var (
|
|||
DefaultBasePackages = BasePackages{
|
||||
APIVersion: []string{
|
||||
// Default package for ProviderConfig APIs
|
||||
"apis/v1alpha1",
|
||||
"apis/v1beta1",
|
||||
"v1alpha1",
|
||||
"v1beta1",
|
||||
},
|
||||
|
||||
Controller: []string{
|
||||
// Default package for ProviderConfig controllers
|
||||
"internal/controller/providerconfig",
|
||||
"providerconfig",
|
||||
},
|
||||
ControllerMap: map[string]string{
|
||||
// Default package for ProviderConfig controllers
|
||||
"internal/controller/providerconfig": PackageNameConfig,
|
||||
"providerconfig": PackageNameConfig,
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
@ -13,8 +13,8 @@ import (
|
|||
fwresource "github.com/hashicorp/terraform-plugin-framework/resource"
|
||||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
|
||||
|
||||
"github.com/crossplane/upjet/pkg/config/conversion"
|
||||
"github.com/crossplane/upjet/pkg/registry"
|
||||
"github.com/crossplane/upjet/v2/pkg/config/conversion"
|
||||
"github.com/crossplane/upjet/v2/pkg/registry"
|
||||
)
|
||||
|
||||
func TestDefaultResource(t *testing.T) {
|
||||
|
|
|
@ -8,8 +8,8 @@ import (
|
|||
"fmt"
|
||||
"slices"
|
||||
|
||||
"github.com/crossplane/crossplane-runtime/pkg/fieldpath"
|
||||
"github.com/crossplane/crossplane-runtime/pkg/resource"
|
||||
"github.com/crossplane/crossplane-runtime/v2/pkg/fieldpath"
|
||||
"github.com/crossplane/crossplane-runtime/v2/pkg/resource"
|
||||
"github.com/pkg/errors"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
|
|
|
@ -9,10 +9,10 @@ import (
|
|||
"slices"
|
||||
"testing"
|
||||
|
||||
"github.com/crossplane/crossplane-runtime/pkg/fieldpath"
|
||||
"github.com/crossplane/crossplane-runtime/pkg/resource"
|
||||
"github.com/crossplane/crossplane-runtime/pkg/resource/fake"
|
||||
"github.com/crossplane/crossplane-runtime/pkg/test"
|
||||
"github.com/crossplane/crossplane-runtime/v2/pkg/fieldpath"
|
||||
"github.com/crossplane/crossplane-runtime/v2/pkg/resource"
|
||||
"github.com/crossplane/crossplane-runtime/v2/pkg/resource/fake"
|
||||
"github.com/crossplane/crossplane-runtime/v2/pkg/test"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
jsoniter "github.com/json-iterator/go"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
|
|
|
@ -10,7 +10,7 @@ import (
|
|||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/crossplane/crossplane-runtime/pkg/fieldpath"
|
||||
"github.com/crossplane/crossplane-runtime/v2/pkg/fieldpath"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
|
@ -103,7 +103,7 @@ func Convert(params map[string]any, paths []string, mode ListConversionMode, opt
|
|||
pv := fieldpath.Pave(params)
|
||||
for _, fp := range paths {
|
||||
exp, err := pv.ExpandWildcards(fp)
|
||||
if err != nil {
|
||||
if err != nil && !fieldpath.IsNotFound(err) {
|
||||
return nil, errors.Wrapf(err, "cannot expand wildcards for the field path expression %s", fp)
|
||||
}
|
||||
for _, e := range exp {
|
||||
|
|
|
@ -8,7 +8,7 @@ import (
|
|||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/crossplane/crossplane-runtime/pkg/test"
|
||||
"github.com/crossplane/crossplane-runtime/v2/pkg/test"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
jsoniter "github.com/json-iterator/go"
|
||||
"github.com/pkg/errors"
|
||||
|
|
|
@ -12,8 +12,8 @@ import (
|
|||
"text/template"
|
||||
"text/template/parse"
|
||||
|
||||
"github.com/crossplane/crossplane-runtime/pkg/errors"
|
||||
"github.com/crossplane/crossplane-runtime/pkg/fieldpath"
|
||||
"github.com/crossplane/crossplane-runtime/v2/pkg/errors"
|
||||
"github.com/crossplane/crossplane-runtime/v2/pkg/fieldpath"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
|
@ -8,8 +8,8 @@ import (
|
|||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/crossplane/crossplane-runtime/pkg/errors"
|
||||
"github.com/crossplane/crossplane-runtime/pkg/test"
|
||||
"github.com/crossplane/crossplane-runtime/v2/pkg/errors"
|
||||
"github.com/crossplane/crossplane-runtime/v2/pkg/test"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
)
|
||||
|
||||
|
|
|
@ -15,9 +15,9 @@ import (
|
|||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/crossplane/upjet/pkg/registry"
|
||||
"github.com/crossplane/upjet/pkg/schema/traverser"
|
||||
conversiontfjson "github.com/crossplane/upjet/pkg/types/conversion/tfjson"
|
||||
"github.com/crossplane/upjet/v2/pkg/registry"
|
||||
"github.com/crossplane/upjet/v2/pkg/schema/traverser"
|
||||
conversiontfjson "github.com/crossplane/upjet/v2/pkg/types/conversion/tfjson"
|
||||
)
|
||||
|
||||
// ResourceConfiguratorFn is a function that implements the ResourceConfigurator
|
||||
|
|
|
@ -10,11 +10,13 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1"
|
||||
"github.com/crossplane/crossplane-runtime/pkg/fieldpath"
|
||||
"github.com/crossplane/crossplane-runtime/pkg/reconciler/managed"
|
||||
xpresource "github.com/crossplane/crossplane-runtime/pkg/resource"
|
||||
xpv1 "github.com/crossplane/crossplane-runtime/v2/apis/common/v1"
|
||||
"github.com/crossplane/crossplane-runtime/v2/pkg/fieldpath"
|
||||
"github.com/crossplane/crossplane-runtime/v2/pkg/reconciler/managed"
|
||||
xpresource "github.com/crossplane/crossplane-runtime/v2/pkg/resource"
|
||||
fwresource "github.com/hashicorp/terraform-plugin-framework/resource"
|
||||
rschema "github.com/hashicorp/terraform-plugin-framework/resource/schema"
|
||||
"github.com/hashicorp/terraform-plugin-go/tftypes"
|
||||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
|
||||
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
|
||||
"github.com/pkg/errors"
|
||||
|
@ -23,8 +25,8 @@ import (
|
|||
"k8s.io/utils/ptr"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
"github.com/crossplane/upjet/pkg/config/conversion"
|
||||
"github.com/crossplane/upjet/pkg/registry"
|
||||
"github.com/crossplane/upjet/v2/pkg/config/conversion"
|
||||
"github.com/crossplane/upjet/v2/pkg/registry"
|
||||
)
|
||||
|
||||
// A ListType is a type of list.
|
||||
|
@ -517,6 +519,12 @@ type Resource struct {
|
|||
// Terraform InstanceDiff is computed during reconciliation.
|
||||
TerraformCustomDiff CustomDiff
|
||||
|
||||
// TerraformPluginFrameworkIsStateEmptyFn allows customizing the logic
|
||||
// for determining whether a Terraform Plugin Framework state value should
|
||||
// be considered empty/nil for resource existence checks. If not set, the
|
||||
// default behavior uses tfStateValue.IsNull().
|
||||
TerraformPluginFrameworkIsStateEmptyFn TerraformPluginFrameworkIsStateEmptyFn
|
||||
|
||||
// ServerSideApplyMergeStrategies configures the server-side apply merge
|
||||
// strategy for the fields at the given map keys. The map key is
|
||||
// a Terraform configuration argument path such as a.b.c, without any
|
||||
|
@ -642,6 +650,13 @@ type CustomDiff func(diff *terraform.InstanceDiff, state *terraform.InstanceStat
|
|||
// the JSON tags and tfMap is obtained by using the TF tags.
|
||||
type ConfigurationInjector func(jsonMap map[string]any, tfMap map[string]any) error
|
||||
|
||||
// TerraformPluginFrameworkIsStateEmptyFn is a function that determines whether
|
||||
// a Terraform Plugin Framework state value should be considered empty/nil for the
|
||||
// purpose of determining resource existence. This allows providers to implement
|
||||
// custom logic to handle cases where the standard IsNull() check is insufficient,
|
||||
// such as when provider interceptors add fields like region to all state values.
|
||||
type TerraformPluginFrameworkIsStateEmptyFn func(ctx context.Context, tfStateValue tftypes.Value, resourceSchema rschema.Schema) (bool, error)
|
||||
|
||||
// SchemaElementOptions represents schema element options for the
|
||||
// schema elements of a Resource.
|
||||
type SchemaElementOptions map[string]*SchemaElementOption
|
||||
|
|
|
@ -9,11 +9,11 @@ import (
|
|||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/crossplane/crossplane-runtime/pkg/errors"
|
||||
"github.com/crossplane/crossplane-runtime/pkg/fieldpath"
|
||||
xpresource "github.com/crossplane/crossplane-runtime/pkg/resource"
|
||||
"github.com/crossplane/crossplane-runtime/pkg/resource/fake"
|
||||
"github.com/crossplane/crossplane-runtime/pkg/test"
|
||||
"github.com/crossplane/crossplane-runtime/v2/pkg/errors"
|
||||
"github.com/crossplane/crossplane-runtime/v2/pkg/fieldpath"
|
||||
xpresource "github.com/crossplane/crossplane-runtime/v2/pkg/resource"
|
||||
"github.com/crossplane/crossplane-runtime/v2/pkg/resource/fake"
|
||||
"github.com/crossplane/crossplane-runtime/v2/pkg/test"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
)
|
||||
|
|
|
@ -8,7 +8,7 @@ import (
|
|||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/crossplane/upjet/pkg/schema/traverser"
|
||||
"github.com/crossplane/upjet/v2/pkg/schema/traverser"
|
||||
)
|
||||
|
||||
var _ ResourceSetter = &SingletonListEmbedder{}
|
||||
|
|
|
@ -7,7 +7,7 @@ package config
|
|||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/crossplane/crossplane-runtime/pkg/test"
|
||||
"github.com/crossplane/crossplane-runtime/v2/pkg/test"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
|
||||
)
|
||||
|
|
|
@ -7,7 +7,7 @@ package config
|
|||
import (
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/crossplane/upjet/pkg/config/conversion"
|
||||
"github.com/crossplane/upjet/v2/pkg/config/conversion"
|
||||
)
|
||||
|
||||
// Mode denotes the mode of the runtime Terraform conversion, e.g.,
|
||||
|
|
|
@ -7,8 +7,8 @@ package controller
|
|||
import (
|
||||
"context"
|
||||
|
||||
xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1"
|
||||
xpresource "github.com/crossplane/crossplane-runtime/pkg/resource"
|
||||
xpv1 "github.com/crossplane/crossplane-runtime/v2/apis/common/v1"
|
||||
xpresource "github.com/crossplane/crossplane-runtime/v2/pkg/resource"
|
||||
"github.com/pkg/errors"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
|
@ -16,9 +16,9 @@ import (
|
|||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
ctrl "sigs.k8s.io/controller-runtime/pkg/manager"
|
||||
|
||||
"github.com/crossplane/upjet/pkg/controller/handler"
|
||||
"github.com/crossplane/upjet/pkg/resource"
|
||||
"github.com/crossplane/upjet/pkg/terraform"
|
||||
"github.com/crossplane/upjet/v2/pkg/controller/handler"
|
||||
"github.com/crossplane/upjet/v2/pkg/resource"
|
||||
"github.com/crossplane/upjet/v2/pkg/terraform"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -113,12 +113,11 @@ type APICallbacks struct {
|
|||
enableStatusUpdates bool
|
||||
}
|
||||
|
||||
func (ac *APICallbacks) callbackFn(name, op string) terraform.CallbackFn {
|
||||
func (ac *APICallbacks) callbackFn(nn types.NamespacedName, op string) terraform.CallbackFn {
|
||||
return func(err error, ctx context.Context) error {
|
||||
nn := types.NamespacedName{Name: name}
|
||||
tr := ac.newTerraformed()
|
||||
if kErr := ac.kube.Get(ctx, nn, tr); kErr != nil {
|
||||
return errors.Wrapf(kErr, errGetFmt, tr.GetObjectKind().GroupVersionKind().String(), name, op)
|
||||
return errors.Wrapf(kErr, errGetFmt, tr.GetObjectKind().GroupVersionKind().String(), nn, op)
|
||||
}
|
||||
// For the no-fork architecture, we will need to be able to report
|
||||
// reconciliation errors. The proper place is the `Synced`
|
||||
|
@ -143,19 +142,19 @@ func (ac *APICallbacks) callbackFn(name, op string) terraform.CallbackFn {
|
|||
if ac.enableStatusUpdates {
|
||||
tr.SetConditions(resource.AsyncOperationFinishedCondition())
|
||||
}
|
||||
uErr := errors.Wrapf(ac.kube.Status().Update(ctx, tr), errUpdateStatusFmt, tr.GetObjectKind().GroupVersionKind().String(), name, op)
|
||||
uErr := errors.Wrapf(ac.kube.Status().Update(ctx, tr), errUpdateStatusFmt, tr.GetObjectKind().GroupVersionKind().String(), nn, op)
|
||||
if ac.eventHandler != nil {
|
||||
rateLimiter := handler.NoRateLimiter
|
||||
switch {
|
||||
case err != nil:
|
||||
rateLimiter = rateLimiterCallback
|
||||
default:
|
||||
ac.eventHandler.Forget(rateLimiterCallback, name)
|
||||
ac.eventHandler.Forget(rateLimiterCallback, nn)
|
||||
}
|
||||
// TODO: use the errors.Join from
|
||||
// github.com/crossplane/crossplane-runtime.
|
||||
if ok := ac.eventHandler.RequestReconcile(rateLimiter, name, nil); !ok {
|
||||
return errors.Errorf(errReconcileRequestFmt, tr.GetObjectKind().GroupVersionKind().String(), name, op)
|
||||
if ok := ac.eventHandler.RequestReconcile(rateLimiter, nn, nil); !ok {
|
||||
return errors.Errorf(errReconcileRequestFmt, tr.GetObjectKind().GroupVersionKind().String(), nn, op)
|
||||
}
|
||||
}
|
||||
return uErr
|
||||
|
@ -163,7 +162,7 @@ func (ac *APICallbacks) callbackFn(name, op string) terraform.CallbackFn {
|
|||
}
|
||||
|
||||
// Create makes sure the error is saved in async operation condition.
|
||||
func (ac *APICallbacks) Create(name string) terraform.CallbackFn {
|
||||
func (ac *APICallbacks) Create(name types.NamespacedName) terraform.CallbackFn {
|
||||
// request will be requeued although the managed reconciler already
|
||||
// requeues with exponential back-off during the creation phase
|
||||
// because the upjet external client returns ResourceExists &
|
||||
|
@ -175,12 +174,12 @@ func (ac *APICallbacks) Create(name string) terraform.CallbackFn {
|
|||
}
|
||||
|
||||
// Update makes sure the error is saved in async operation condition.
|
||||
func (ac *APICallbacks) Update(name string) terraform.CallbackFn {
|
||||
func (ac *APICallbacks) Update(name types.NamespacedName) terraform.CallbackFn {
|
||||
return ac.callbackFn(name, "update")
|
||||
}
|
||||
|
||||
// Destroy makes sure the error is saved in async operation condition.
|
||||
func (ac *APICallbacks) Destroy(name string) terraform.CallbackFn {
|
||||
func (ac *APICallbacks) Destroy(name types.NamespacedName) terraform.CallbackFn {
|
||||
// request will be requeued although the managed reconciler requeues
|
||||
// with exponential back-off during the deletion phase because
|
||||
// during the async deletion operation, external client's
|
||||
|
|
|
@ -8,17 +8,18 @@ import (
|
|||
"context"
|
||||
"testing"
|
||||
|
||||
xpresource "github.com/crossplane/crossplane-runtime/pkg/resource"
|
||||
xpfake "github.com/crossplane/crossplane-runtime/pkg/resource/fake"
|
||||
"github.com/crossplane/crossplane-runtime/pkg/test"
|
||||
xpresource "github.com/crossplane/crossplane-runtime/v2/pkg/resource"
|
||||
xpfake "github.com/crossplane/crossplane-runtime/v2/pkg/resource/fake"
|
||||
"github.com/crossplane/crossplane-runtime/v2/pkg/test"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/pkg/errors"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
ctrl "sigs.k8s.io/controller-runtime/pkg/manager"
|
||||
|
||||
"github.com/crossplane/upjet/pkg/resource"
|
||||
"github.com/crossplane/upjet/pkg/resource/fake"
|
||||
tjerrors "github.com/crossplane/upjet/pkg/terraform/errors"
|
||||
"github.com/crossplane/upjet/v2/pkg/resource"
|
||||
"github.com/crossplane/upjet/v2/pkg/resource/fake"
|
||||
tjerrors "github.com/crossplane/upjet/v2/pkg/terraform/errors"
|
||||
)
|
||||
|
||||
func TestAPICallbacksCreate(t *testing.T) {
|
||||
|
@ -88,14 +89,14 @@ func TestAPICallbacksCreate(t *testing.T) {
|
|||
},
|
||||
},
|
||||
want: want{
|
||||
err: errors.Wrapf(errBoom, errGetFmt, "", ", Kind=/name", "create"),
|
||||
err: errors.Wrapf(errBoom, errGetFmt, "", ", Kind=//name", "create"),
|
||||
},
|
||||
},
|
||||
}
|
||||
for name, tc := range cases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
e := NewAPICallbacks(tc.args.mgr, tc.args.mg)
|
||||
err := e.Create("name")(tc.args.err, context.TODO())
|
||||
err := e.Create(types.NamespacedName{Name: "name"})(tc.args.err, context.TODO())
|
||||
if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" {
|
||||
t.Errorf("\n%s\nCreate(...): -want error, +got error:\n%s", tc.reason, diff)
|
||||
}
|
||||
|
@ -170,14 +171,14 @@ func TestAPICallbacksUpdate(t *testing.T) {
|
|||
},
|
||||
},
|
||||
want: want{
|
||||
err: errors.Wrapf(errBoom, errGetFmt, "", ", Kind=/name", "update"),
|
||||
err: errors.Wrapf(errBoom, errGetFmt, "", ", Kind=//name", "update"),
|
||||
},
|
||||
},
|
||||
}
|
||||
for name, tc := range cases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
e := NewAPICallbacks(tc.args.mgr, tc.args.mg)
|
||||
err := e.Update("name")(tc.args.err, context.TODO())
|
||||
err := e.Update(types.NamespacedName{Name: "name"})(tc.args.err, context.TODO())
|
||||
if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" {
|
||||
t.Errorf("\n%s\nUpdate(...): -want error, +got error:\n%s", tc.reason, diff)
|
||||
}
|
||||
|
@ -252,14 +253,290 @@ func TestAPICallbacks_Destroy(t *testing.T) {
|
|||
},
|
||||
},
|
||||
want: want{
|
||||
err: errors.Wrapf(errBoom, errGetFmt, "", ", Kind=/name", "destroy"),
|
||||
err: errors.Wrapf(errBoom, errGetFmt, "", ", Kind=//name", "destroy"),
|
||||
},
|
||||
},
|
||||
}
|
||||
for name, tc := range cases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
e := NewAPICallbacks(tc.args.mgr, tc.args.mg)
|
||||
err := e.Destroy("name")(tc.args.err, context.TODO())
|
||||
err := e.Destroy(types.NamespacedName{Name: "name"})(tc.args.err, context.TODO())
|
||||
if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" {
|
||||
t.Errorf("\n%s\nDestroy(...): -want error, +got error:\n%s", tc.reason, diff)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAPICallbacksCreate_namespaced(t *testing.T) {
|
||||
type args struct {
|
||||
mgr ctrl.Manager
|
||||
mg xpresource.ManagedKind
|
||||
err error
|
||||
}
|
||||
type want struct {
|
||||
err error
|
||||
}
|
||||
cases := map[string]struct {
|
||||
reason string
|
||||
args
|
||||
want
|
||||
}{
|
||||
"CreateOperationFailed": {
|
||||
reason: "It should update the condition with error if async apply failed",
|
||||
args: args{
|
||||
mg: xpresource.ManagedKind(xpfake.GVK(&fake.ModernTerraformed{})),
|
||||
mgr: &xpfake.Manager{
|
||||
Client: &test.MockClient{
|
||||
MockGet: func(_ context.Context, gotKey client.ObjectKey, _ client.Object) error {
|
||||
if diff := cmp.Diff(client.ObjectKey{Name: "name", Namespace: "foo-ns"}, gotKey); diff != "" {
|
||||
t.Errorf("\nGet(...): -want object key, +got object key:\n%s", diff)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
MockStatusUpdate: func(ctx context.Context, obj client.Object, opts ...client.SubResourceUpdateOption) error {
|
||||
got := obj.(resource.Terraformed).GetCondition(resource.TypeLastAsyncOperation)
|
||||
if diff := cmp.Diff(resource.LastAsyncOperationCondition(tjerrors.NewApplyFailed(nil)), got); diff != "" {
|
||||
t.Errorf("\nCreate(...): -want error, +got error:\n%s", diff)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
},
|
||||
Scheme: xpfake.SchemeWith(&fake.ModernTerraformed{}),
|
||||
},
|
||||
err: tjerrors.NewApplyFailed(nil),
|
||||
},
|
||||
},
|
||||
"CreateOperationSucceeded": {
|
||||
reason: "It should update the condition with success if the apply operation does not report error",
|
||||
args: args{
|
||||
mg: xpresource.ManagedKind(xpfake.GVK(&fake.ModernTerraformed{})),
|
||||
mgr: &xpfake.Manager{
|
||||
Client: &test.MockClient{
|
||||
MockGet: func(_ context.Context, gotKey client.ObjectKey, _ client.Object) error {
|
||||
if diff := cmp.Diff(client.ObjectKey{Name: "name", Namespace: "foo-ns"}, gotKey); diff != "" {
|
||||
t.Errorf("\nGet(...): -want object key, +got object key:\n%s", diff)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
MockStatusUpdate: func(ctx context.Context, obj client.Object, opts ...client.SubResourceUpdateOption) error {
|
||||
got := obj.(resource.Terraformed).GetCondition(resource.TypeLastAsyncOperation)
|
||||
if diff := cmp.Diff(resource.LastAsyncOperationCondition(nil), got); diff != "" {
|
||||
t.Errorf("\nCreate(...): -want error, +got error:\n%s", diff)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
},
|
||||
Scheme: xpfake.SchemeWith(&fake.ModernTerraformed{}),
|
||||
},
|
||||
},
|
||||
},
|
||||
"CannotGet": {
|
||||
reason: "It should return error if it cannot get the resource to update",
|
||||
args: args{
|
||||
mg: xpresource.ManagedKind(xpfake.GVK(&fake.ModernTerraformed{})),
|
||||
mgr: &xpfake.Manager{
|
||||
Client: &test.MockClient{
|
||||
MockGet: func(_ context.Context, _ client.ObjectKey, _ client.Object) error {
|
||||
return errBoom
|
||||
},
|
||||
},
|
||||
Scheme: xpfake.SchemeWith(&fake.ModernTerraformed{}),
|
||||
},
|
||||
},
|
||||
want: want{
|
||||
err: errors.Wrapf(errBoom, errGetFmt, "", ", Kind=/foo-ns/name", "create"),
|
||||
},
|
||||
},
|
||||
}
|
||||
for name, tc := range cases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
e := NewAPICallbacks(tc.args.mgr, tc.args.mg)
|
||||
err := e.Create(types.NamespacedName{Name: "name", Namespace: "foo-ns"})(tc.args.err, context.TODO())
|
||||
if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" {
|
||||
t.Errorf("\n%s\nCreate(...): -want error, +got error:\n%s", tc.reason, diff)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAPICallbacksUpdate_namespaced(t *testing.T) {
|
||||
type args struct {
|
||||
mgr ctrl.Manager
|
||||
mg xpresource.ManagedKind
|
||||
err error
|
||||
}
|
||||
type want struct {
|
||||
err error
|
||||
}
|
||||
cases := map[string]struct {
|
||||
reason string
|
||||
args
|
||||
want
|
||||
}{
|
||||
"UpdateOperationFailed": {
|
||||
reason: "It should update the condition with error if async apply failed",
|
||||
args: args{
|
||||
mg: xpresource.ManagedKind(xpfake.GVK(&fake.ModernTerraformed{})),
|
||||
mgr: &xpfake.Manager{
|
||||
Client: &test.MockClient{
|
||||
MockGet: func(_ context.Context, gotKey client.ObjectKey, _ client.Object) error {
|
||||
if diff := cmp.Diff(client.ObjectKey{Name: "name", Namespace: "foo-ns"}, gotKey); diff != "" {
|
||||
t.Errorf("\nGet(...): -want object key, +got object key:\n%s", diff)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
MockStatusUpdate: func(ctx context.Context, obj client.Object, opts ...client.SubResourceUpdateOption) error {
|
||||
got := obj.(resource.Terraformed).GetCondition(resource.TypeLastAsyncOperation)
|
||||
if diff := cmp.Diff(resource.LastAsyncOperationCondition(tjerrors.NewApplyFailed(nil)), got); diff != "" {
|
||||
t.Errorf("\nUpdate(...): -want error, +got error:\n%s", diff)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
},
|
||||
Scheme: xpfake.SchemeWith(&fake.ModernTerraformed{}),
|
||||
},
|
||||
err: tjerrors.NewApplyFailed(nil),
|
||||
},
|
||||
},
|
||||
"ApplyOperationSucceeded": {
|
||||
reason: "It should update the condition with success if the apply operation does not report error",
|
||||
args: args{
|
||||
mg: xpresource.ManagedKind(xpfake.GVK(&fake.ModernTerraformed{})),
|
||||
mgr: &xpfake.Manager{
|
||||
Client: &test.MockClient{
|
||||
MockGet: func(_ context.Context, gotKey client.ObjectKey, _ client.Object) error {
|
||||
if diff := cmp.Diff(client.ObjectKey{Name: "name", Namespace: "foo-ns"}, gotKey); diff != "" {
|
||||
t.Errorf("\nGet(...): -want object key, +got object key:\n%s", diff)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
MockStatusUpdate: func(ctx context.Context, obj client.Object, opts ...client.SubResourceUpdateOption) error {
|
||||
got := obj.(resource.Terraformed).GetCondition(resource.TypeLastAsyncOperation)
|
||||
if diff := cmp.Diff(resource.LastAsyncOperationCondition(nil), got); diff != "" {
|
||||
t.Errorf("\nUpdate(...): -want error, +got error:\n%s", diff)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
},
|
||||
Scheme: xpfake.SchemeWith(&fake.ModernTerraformed{}),
|
||||
},
|
||||
},
|
||||
},
|
||||
"CannotGet": {
|
||||
reason: "It should return error if it cannot get the resource to update",
|
||||
args: args{
|
||||
mg: xpresource.ManagedKind(xpfake.GVK(&fake.ModernTerraformed{})),
|
||||
mgr: &xpfake.Manager{
|
||||
Client: &test.MockClient{
|
||||
MockGet: func(_ context.Context, _ client.ObjectKey, _ client.Object) error {
|
||||
return errBoom
|
||||
},
|
||||
},
|
||||
Scheme: xpfake.SchemeWith(&fake.ModernTerraformed{}),
|
||||
},
|
||||
},
|
||||
want: want{
|
||||
err: errors.Wrapf(errBoom, errGetFmt, "", ", Kind=/foo-ns/name", "update"),
|
||||
},
|
||||
},
|
||||
}
|
||||
for name, tc := range cases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
e := NewAPICallbacks(tc.args.mgr, tc.args.mg)
|
||||
err := e.Update(types.NamespacedName{Name: "name", Namespace: "foo-ns"})(tc.args.err, context.TODO())
|
||||
if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" {
|
||||
t.Errorf("\n%s\nUpdate(...): -want error, +got error:\n%s", tc.reason, diff)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAPICallbacks_Destroy_namespaced(t *testing.T) {
|
||||
type args struct {
|
||||
mgr ctrl.Manager
|
||||
mg xpresource.ManagedKind
|
||||
err error
|
||||
}
|
||||
type want struct {
|
||||
err error
|
||||
}
|
||||
cases := map[string]struct {
|
||||
reason string
|
||||
args
|
||||
want
|
||||
}{
|
||||
"DestroyOperationFailed": {
|
||||
reason: "It should update the condition with error if async destroy failed",
|
||||
args: args{
|
||||
mg: xpresource.ManagedKind(xpfake.GVK(&fake.ModernTerraformed{})),
|
||||
mgr: &xpfake.Manager{
|
||||
Client: &test.MockClient{
|
||||
MockGet: func(_ context.Context, gotKey client.ObjectKey, _ client.Object) error {
|
||||
if diff := cmp.Diff(client.ObjectKey{Name: "name", Namespace: "foo-ns"}, gotKey); diff != "" {
|
||||
t.Errorf("\nGet(...): -want object key, +got object key:\n%s", diff)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
MockStatusUpdate: func(ctx context.Context, obj client.Object, opts ...client.SubResourceUpdateOption) error {
|
||||
got := obj.(resource.Terraformed).GetCondition(resource.TypeLastAsyncOperation)
|
||||
if diff := cmp.Diff(resource.LastAsyncOperationCondition(tjerrors.NewDestroyFailed(nil)), got); diff != "" {
|
||||
t.Errorf("\nDestroy(...): -want error, +got error:\n%s", diff)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
},
|
||||
Scheme: xpfake.SchemeWith(&fake.ModernTerraformed{}),
|
||||
},
|
||||
err: tjerrors.NewDestroyFailed(nil),
|
||||
},
|
||||
},
|
||||
"DestroyOperationSucceeded": {
|
||||
reason: "It should update the condition with success if the destroy operation does not report error",
|
||||
args: args{
|
||||
mg: xpresource.ManagedKind(xpfake.GVK(&fake.ModernTerraformed{})),
|
||||
mgr: &xpfake.Manager{
|
||||
Client: &test.MockClient{
|
||||
MockGet: func(_ context.Context, gotKey client.ObjectKey, _ client.Object) error {
|
||||
if diff := cmp.Diff(client.ObjectKey{Name: "name", Namespace: "foo-ns"}, gotKey); diff != "" {
|
||||
t.Errorf("\nGet(...): -want object key, +got object key:\n%s", diff)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
MockStatusUpdate: func(ctx context.Context, obj client.Object, opts ...client.SubResourceUpdateOption) error {
|
||||
got := obj.(resource.Terraformed).GetCondition(resource.TypeLastAsyncOperation)
|
||||
if diff := cmp.Diff(resource.LastAsyncOperationCondition(nil), got); diff != "" {
|
||||
t.Errorf("\nDestroy(...): -want error, +got error:\n%s", diff)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
},
|
||||
Scheme: xpfake.SchemeWith(&fake.ModernTerraformed{}),
|
||||
},
|
||||
},
|
||||
},
|
||||
"CannotGet": {
|
||||
reason: "It should return error if it cannot get the resource to update",
|
||||
args: args{
|
||||
mg: xpresource.ManagedKind(xpfake.GVK(&fake.ModernTerraformed{})),
|
||||
mgr: &xpfake.Manager{
|
||||
Client: &test.MockClient{
|
||||
MockGet: func(_ context.Context, _ client.ObjectKey, _ client.Object) error {
|
||||
return errBoom
|
||||
},
|
||||
},
|
||||
Scheme: xpfake.SchemeWith(&fake.ModernTerraformed{}),
|
||||
},
|
||||
},
|
||||
want: want{
|
||||
err: errors.Wrapf(errBoom, errGetFmt, "", ", Kind=/foo-ns/name", "destroy"),
|
||||
},
|
||||
},
|
||||
}
|
||||
for name, tc := range cases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
e := NewAPICallbacks(tc.args.mgr, tc.args.mg)
|
||||
err := e.Destroy(types.NamespacedName{Name: "name", Namespace: "foo-ns"})(tc.args.err, context.TODO())
|
||||
if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" {
|
||||
t.Errorf("\n%s\nDestroy(...): -want error, +got error:\n%s", tc.reason, diff)
|
||||
}
|
||||
|
|
|
@ -5,13 +5,13 @@
|
|||
package conversion
|
||||
|
||||
import (
|
||||
"github.com/crossplane/crossplane-runtime/pkg/fieldpath"
|
||||
"github.com/crossplane/crossplane-runtime/v2/pkg/fieldpath"
|
||||
"github.com/pkg/errors"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client/apiutil"
|
||||
|
||||
"github.com/crossplane/upjet/pkg/config/conversion"
|
||||
"github.com/crossplane/upjet/pkg/resource"
|
||||
"github.com/crossplane/upjet/v2/pkg/config/conversion"
|
||||
"github.com/crossplane/upjet/v2/pkg/resource"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
|
@ -8,18 +8,18 @@ import (
|
|||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/crossplane/crossplane-runtime/pkg/fieldpath"
|
||||
xpresource "github.com/crossplane/crossplane-runtime/pkg/resource"
|
||||
"github.com/crossplane/crossplane-runtime/pkg/test"
|
||||
"github.com/crossplane/crossplane-runtime/v2/pkg/fieldpath"
|
||||
xpresource "github.com/crossplane/crossplane-runtime/v2/pkg/resource"
|
||||
"github.com/crossplane/crossplane-runtime/v2/pkg/test"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/pkg/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
|
||||
"github.com/crossplane/upjet/pkg/config"
|
||||
"github.com/crossplane/upjet/pkg/config/conversion"
|
||||
"github.com/crossplane/upjet/pkg/resource"
|
||||
"github.com/crossplane/upjet/pkg/resource/fake"
|
||||
"github.com/crossplane/upjet/v2/pkg/config"
|
||||
"github.com/crossplane/upjet/v2/pkg/config/conversion"
|
||||
"github.com/crossplane/upjet/v2/pkg/resource"
|
||||
"github.com/crossplane/upjet/v2/pkg/resource/fake"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -170,7 +170,7 @@ func TestRoundTrip(t *testing.T) {
|
|||
r := ®istry{
|
||||
scheme: s,
|
||||
}
|
||||
if err := r.RegisterConversions(p); err != nil {
|
||||
if err := r.RegisterConversions(p, nil); err != nil {
|
||||
t.Fatalf("\n%s\nRegisterConversions(p): Failed to register the conversions with the registry.\n", tc.reason)
|
||||
}
|
||||
err := r.RoundTrip(tc.args.dst, tc.args.src)
|
||||
|
|
|
@ -8,9 +8,9 @@ import (
|
|||
"github.com/pkg/errors"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
|
||||
"github.com/crossplane/upjet/pkg/config"
|
||||
"github.com/crossplane/upjet/pkg/config/conversion"
|
||||
"github.com/crossplane/upjet/pkg/resource"
|
||||
"github.com/crossplane/upjet/v2/pkg/config"
|
||||
"github.com/crossplane/upjet/v2/pkg/config/conversion"
|
||||
"github.com/crossplane/upjet/v2/pkg/resource"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -21,17 +21,19 @@ var instance *registry
|
|||
|
||||
// registry represents the conversion hook registry for a provider.
|
||||
type registry struct {
|
||||
provider *config.Provider
|
||||
providerCluster *config.Provider
|
||||
providerNamespaced *config.Provider
|
||||
scheme *runtime.Scheme
|
||||
}
|
||||
|
||||
// RegisterConversions registers the API version conversions from the specified
|
||||
// provider configuration with this registry.
|
||||
func (r *registry) RegisterConversions(provider *config.Provider) error {
|
||||
if r.provider != nil {
|
||||
func (r *registry) RegisterConversions(providerCluster, providerNamespaced *config.Provider) error {
|
||||
if r.providerCluster != nil || r.providerNamespaced != nil {
|
||||
return errors.New(errAlreadyRegistered)
|
||||
}
|
||||
r.provider = provider
|
||||
r.providerCluster = providerCluster
|
||||
r.providerNamespaced = providerNamespaced
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -39,10 +41,17 @@ func (r *registry) RegisterConversions(provider *config.Provider) error {
|
|||
// registry for the specified Terraformed resource.
|
||||
func (r *registry) GetConversions(tr resource.Terraformed) []conversion.Conversion {
|
||||
t := tr.GetTerraformResourceType()
|
||||
if r == nil || r.provider == nil || r.provider.Resources[t] == nil {
|
||||
|
||||
p := r.providerCluster
|
||||
if tr.GetNamespace() != "" {
|
||||
p = r.providerNamespaced
|
||||
}
|
||||
|
||||
if p == nil || p.Resources[t] == nil {
|
||||
return nil
|
||||
}
|
||||
return r.provider.Resources[t].Conversions
|
||||
|
||||
return p.Resources[t].Conversions
|
||||
}
|
||||
|
||||
// GetConversions returns the conversion.Conversions registered for the
|
||||
|
@ -56,12 +65,12 @@ func GetConversions(tr resource.Terraformed) []conversion.Conversion {
|
|||
// for the types whose versions are to be converted. If a registration for a
|
||||
// Go schema is not found in the specified registry, RoundTrip does not error
|
||||
// but only wildcard conversions must be used with the registry.
|
||||
func RegisterConversions(provider *config.Provider, scheme *runtime.Scheme) error {
|
||||
func RegisterConversions(providerCluster, providerNamespaced *config.Provider, scheme *runtime.Scheme) error {
|
||||
if instance != nil {
|
||||
return errors.New(errAlreadyRegistered)
|
||||
}
|
||||
instance = ®istry{
|
||||
scheme: scheme,
|
||||
}
|
||||
return instance.RegisterConversions(provider)
|
||||
return instance.RegisterConversions(providerCluster, providerNamespaced)
|
||||
}
|
||||
|
|
|
@ -8,21 +8,22 @@ import (
|
|||
"context"
|
||||
"time"
|
||||
|
||||
xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1"
|
||||
"github.com/crossplane/crossplane-runtime/pkg/logging"
|
||||
"github.com/crossplane/crossplane-runtime/pkg/reconciler/managed"
|
||||
xpresource "github.com/crossplane/crossplane-runtime/pkg/resource"
|
||||
xpv1 "github.com/crossplane/crossplane-runtime/v2/apis/common/v1"
|
||||
"github.com/crossplane/crossplane-runtime/v2/pkg/logging"
|
||||
"github.com/crossplane/crossplane-runtime/v2/pkg/reconciler/managed"
|
||||
xpresource "github.com/crossplane/crossplane-runtime/v2/pkg/resource"
|
||||
"github.com/pkg/errors"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
"github.com/crossplane/upjet/pkg/config"
|
||||
"github.com/crossplane/upjet/pkg/controller/handler"
|
||||
"github.com/crossplane/upjet/pkg/metrics"
|
||||
"github.com/crossplane/upjet/pkg/resource"
|
||||
"github.com/crossplane/upjet/pkg/resource/json"
|
||||
"github.com/crossplane/upjet/pkg/terraform"
|
||||
tferrors "github.com/crossplane/upjet/pkg/terraform/errors"
|
||||
"github.com/crossplane/upjet/v2/pkg/config"
|
||||
"github.com/crossplane/upjet/v2/pkg/controller/handler"
|
||||
"github.com/crossplane/upjet/v2/pkg/metrics"
|
||||
"github.com/crossplane/upjet/v2/pkg/resource"
|
||||
"github.com/crossplane/upjet/v2/pkg/resource/json"
|
||||
"github.com/crossplane/upjet/v2/pkg/terraform"
|
||||
tferrors "github.com/crossplane/upjet/v2/pkg/terraform/errors"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -125,7 +126,7 @@ func (c *Connector) Connect(ctx context.Context, mg xpresource.Managed) (managed
|
|||
providerHandle: ws.ProviderHandle,
|
||||
eventHandler: c.eventHandler,
|
||||
kube: c.kube,
|
||||
logger: c.logger.WithValues("uid", mg.GetUID(), "name", mg.GetName(), "gvk", mg.GetObjectKind().GroupVersionKind().String()),
|
||||
logger: c.logger.WithValues("uid", mg.GetUID(), "namespace", mg.GetNamespace(), "name", mg.GetName(), "gvk", mg.GetObjectKind().GroupVersionKind().String()),
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
@ -140,7 +141,7 @@ type external struct {
|
|||
logger logging.Logger
|
||||
}
|
||||
|
||||
func (e *external) scheduleProvider(name string) (bool, error) {
|
||||
func (e *external) scheduleProvider(name types.NamespacedName) (bool, error) {
|
||||
if e.providerScheduler == nil || e.workspace == nil {
|
||||
return false, nil
|
||||
}
|
||||
|
@ -176,7 +177,11 @@ func (e *external) Observe(ctx context.Context, mg xpresource.Managed) (managed.
|
|||
// and serial.
|
||||
// TODO(muvaf): Look for ways to reduce the cyclomatic complexity without
|
||||
// increasing the difficulty of understanding the flow.
|
||||
requeued, err := e.scheduleProvider(mg.GetName())
|
||||
name := types.NamespacedName{
|
||||
Namespace: mg.GetNamespace(),
|
||||
Name: mg.GetName(),
|
||||
}
|
||||
requeued, err := e.scheduleProvider(name)
|
||||
if err != nil {
|
||||
return managed.ExternalObservation{}, errors.Wrapf(err, "cannot schedule a native provider during observe: %s", mg.GetUID())
|
||||
}
|
||||
|
@ -308,7 +313,11 @@ func (e *external) Observe(ctx context.Context, mg xpresource.Managed) (managed.
|
|||
tr.SetConditions(xpv1.Available())
|
||||
e.logger.Debug("Resource is marked as available.")
|
||||
if e.eventHandler != nil {
|
||||
e.eventHandler.RequestReconcile(rateLimiterStatus, mg.GetName(), nil)
|
||||
name := types.NamespacedName{
|
||||
Namespace: mg.GetNamespace(),
|
||||
Name: mg.GetName(),
|
||||
}
|
||||
e.eventHandler.RequestReconcile(rateLimiterStatus, name, nil)
|
||||
}
|
||||
return managed.ExternalObservation{
|
||||
ResourceExists: true,
|
||||
|
@ -328,7 +337,11 @@ func (e *external) Observe(ctx context.Context, mg xpresource.Managed) (managed.
|
|||
// now we do a Workspace.Refresh
|
||||
default:
|
||||
if e.eventHandler != nil {
|
||||
e.eventHandler.Forget(rateLimiterStatus, mg.GetName())
|
||||
name := types.NamespacedName{
|
||||
Namespace: mg.GetNamespace(),
|
||||
Name: mg.GetName(),
|
||||
}
|
||||
e.eventHandler.Forget(rateLimiterStatus, name)
|
||||
}
|
||||
|
||||
// TODO(cem): Consider skipping diff calculation (terraform plan) to
|
||||
|
@ -356,7 +369,11 @@ func addTTR(mg xpresource.Managed) {
|
|||
}
|
||||
|
||||
func (e *external) Create(ctx context.Context, mg xpresource.Managed) (managed.ExternalCreation, error) {
|
||||
requeued, err := e.scheduleProvider(mg.GetName())
|
||||
name := types.NamespacedName{
|
||||
Namespace: mg.GetNamespace(),
|
||||
Name: mg.GetName(),
|
||||
}
|
||||
requeued, err := e.scheduleProvider(name)
|
||||
if err != nil {
|
||||
return managed.ExternalCreation{}, errors.Wrapf(err, "cannot schedule a native provider during create: %s", mg.GetUID())
|
||||
}
|
||||
|
@ -365,7 +382,7 @@ func (e *external) Create(ctx context.Context, mg xpresource.Managed) (managed.E
|
|||
}
|
||||
defer e.stopProvider()
|
||||
if e.config.UseAsync {
|
||||
return managed.ExternalCreation{}, errors.Wrap(e.workspace.ApplyAsync(e.callback.Create(mg.GetName())), errStartAsyncApply)
|
||||
return managed.ExternalCreation{}, errors.Wrap(e.workspace.ApplyAsync(e.callback.Create(name)), errStartAsyncApply)
|
||||
}
|
||||
tr, ok := mg.(resource.Terraformed)
|
||||
if !ok {
|
||||
|
@ -391,7 +408,11 @@ func (e *external) Create(ctx context.Context, mg xpresource.Managed) (managed.E
|
|||
}
|
||||
|
||||
func (e *external) Update(ctx context.Context, mg xpresource.Managed) (managed.ExternalUpdate, error) {
|
||||
requeued, err := e.scheduleProvider(mg.GetName())
|
||||
name := types.NamespacedName{
|
||||
Namespace: mg.GetNamespace(),
|
||||
Name: mg.GetName(),
|
||||
}
|
||||
requeued, err := e.scheduleProvider(name)
|
||||
if err != nil {
|
||||
return managed.ExternalUpdate{}, errors.Wrapf(err, "cannot schedule a native provider during update: %s", mg.GetUID())
|
||||
}
|
||||
|
@ -400,7 +421,7 @@ func (e *external) Update(ctx context.Context, mg xpresource.Managed) (managed.E
|
|||
}
|
||||
defer e.stopProvider()
|
||||
if e.config.UseAsync {
|
||||
return managed.ExternalUpdate{}, errors.Wrap(e.workspace.ApplyAsync(e.callback.Update(mg.GetName())), errStartAsyncApply)
|
||||
return managed.ExternalUpdate{}, errors.Wrap(e.workspace.ApplyAsync(e.callback.Update(name)), errStartAsyncApply)
|
||||
}
|
||||
tr, ok := mg.(resource.Terraformed)
|
||||
if !ok {
|
||||
|
@ -418,7 +439,11 @@ func (e *external) Update(ctx context.Context, mg xpresource.Managed) (managed.E
|
|||
}
|
||||
|
||||
func (e *external) Delete(ctx context.Context, mg xpresource.Managed) (managed.ExternalDelete, error) {
|
||||
requeued, err := e.scheduleProvider(mg.GetName())
|
||||
name := types.NamespacedName{
|
||||
Namespace: mg.GetNamespace(),
|
||||
Name: mg.GetName(),
|
||||
}
|
||||
requeued, err := e.scheduleProvider(name)
|
||||
if err != nil {
|
||||
return managed.ExternalDelete{}, errors.Wrapf(err, "cannot schedule a native provider during delete: %s", mg.GetUID())
|
||||
}
|
||||
|
@ -427,7 +452,7 @@ func (e *external) Delete(ctx context.Context, mg xpresource.Managed) (managed.E
|
|||
}
|
||||
defer e.stopProvider()
|
||||
if e.config.UseAsync {
|
||||
return managed.ExternalDelete{}, errors.Wrap(e.workspace.DestroyAsync(e.callback.Destroy(mg.GetName())), errStartAsyncDestroy)
|
||||
return managed.ExternalDelete{}, errors.Wrap(e.workspace.DestroyAsync(e.callback.Destroy(name)), errStartAsyncDestroy)
|
||||
}
|
||||
return managed.ExternalDelete{}, errors.Wrap(e.workspace.Destroy(ctx), errDestroy)
|
||||
}
|
||||
|
|
|
@ -8,21 +8,22 @@ import (
|
|||
"context"
|
||||
"fmt"
|
||||
|
||||
xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1"
|
||||
"github.com/crossplane/crossplane-runtime/pkg/logging"
|
||||
"github.com/crossplane/crossplane-runtime/pkg/meta"
|
||||
"github.com/crossplane/crossplane-runtime/pkg/reconciler/managed"
|
||||
xpresource "github.com/crossplane/crossplane-runtime/pkg/resource"
|
||||
xpv1 "github.com/crossplane/crossplane-runtime/v2/apis/common/v1"
|
||||
"github.com/crossplane/crossplane-runtime/v2/pkg/logging"
|
||||
"github.com/crossplane/crossplane-runtime/v2/pkg/meta"
|
||||
"github.com/crossplane/crossplane-runtime/v2/pkg/reconciler/managed"
|
||||
xpresource "github.com/crossplane/crossplane-runtime/v2/pkg/resource"
|
||||
"github.com/pkg/errors"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
"github.com/crossplane/upjet/pkg/config"
|
||||
"github.com/crossplane/upjet/pkg/controller/handler"
|
||||
"github.com/crossplane/upjet/pkg/metrics"
|
||||
"github.com/crossplane/upjet/pkg/resource"
|
||||
"github.com/crossplane/upjet/pkg/terraform"
|
||||
tferrors "github.com/crossplane/upjet/pkg/terraform/errors"
|
||||
"github.com/crossplane/upjet/v2/pkg/config"
|
||||
"github.com/crossplane/upjet/v2/pkg/controller/handler"
|
||||
"github.com/crossplane/upjet/v2/pkg/metrics"
|
||||
"github.com/crossplane/upjet/v2/pkg/resource"
|
||||
"github.com/crossplane/upjet/v2/pkg/terraform"
|
||||
tferrors "github.com/crossplane/upjet/v2/pkg/terraform/errors"
|
||||
)
|
||||
|
||||
// TerraformPluginFrameworkAsyncConnector is a managed reconciler Connecter
|
||||
|
@ -42,7 +43,8 @@ func NewTerraformPluginFrameworkAsyncConnector(kube client.Client,
|
|||
ots *OperationTrackerStore,
|
||||
sf terraform.SetupFn,
|
||||
cfg *config.Resource,
|
||||
opts ...TerraformPluginFrameworkAsyncOption) *TerraformPluginFrameworkAsyncConnector {
|
||||
opts ...TerraformPluginFrameworkAsyncOption,
|
||||
) *TerraformPluginFrameworkAsyncConnector {
|
||||
nfac := &TerraformPluginFrameworkAsyncConnector{
|
||||
TerraformPluginFrameworkConnector: NewTerraformPluginFrameworkConnector(kube, sf, cfg, ots),
|
||||
}
|
||||
|
@ -178,7 +180,11 @@ func (n *terraformPluginFrameworkAsyncExternalClient) Create(_ context.Context,
|
|||
n.opTracker.logger.Debug("Async create ended.", "error", err)
|
||||
|
||||
n.opTracker.LastOperation.MarkEnd()
|
||||
if cErr := n.callback.Create(mg.GetName())(err, ctx); cErr != nil {
|
||||
name := types.NamespacedName{
|
||||
Namespace: mg.GetNamespace(),
|
||||
Name: mg.GetName(),
|
||||
}
|
||||
if cErr := n.callback.Create(name)(err, ctx); cErr != nil {
|
||||
n.opTracker.logger.Info("Async create callback failed", "error", cErr.Error())
|
||||
}
|
||||
}()
|
||||
|
@ -211,7 +217,11 @@ func (n *terraformPluginFrameworkAsyncExternalClient) Update(_ context.Context,
|
|||
n.opTracker.logger.Debug("Async update ended.", "error", err)
|
||||
|
||||
n.opTracker.LastOperation.MarkEnd()
|
||||
if cErr := n.callback.Update(mg.GetName())(err, ctx); cErr != nil {
|
||||
name := types.NamespacedName{
|
||||
Namespace: mg.GetNamespace(),
|
||||
Name: mg.GetName(),
|
||||
}
|
||||
if cErr := n.callback.Update(name)(err, ctx); cErr != nil {
|
||||
n.opTracker.logger.Info("Async update callback failed", "error", cErr.Error())
|
||||
}
|
||||
}()
|
||||
|
@ -248,7 +258,11 @@ func (n *terraformPluginFrameworkAsyncExternalClient) Delete(_ context.Context,
|
|||
n.opTracker.logger.Debug("Async delete ended.", "error", err)
|
||||
|
||||
n.opTracker.LastOperation.MarkEnd()
|
||||
if cErr := n.callback.Destroy(mg.GetName())(err, ctx); cErr != nil {
|
||||
name := types.NamespacedName{
|
||||
Namespace: mg.GetNamespace(),
|
||||
Name: mg.GetName(),
|
||||
}
|
||||
if cErr := n.callback.Destroy(name)(err, ctx); cErr != nil {
|
||||
n.opTracker.logger.Info("Async delete callback failed", "error", cErr.Error())
|
||||
}
|
||||
}()
|
||||
|
|
|
@ -8,20 +8,21 @@ import (
|
|||
"context"
|
||||
"time"
|
||||
|
||||
xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1"
|
||||
"github.com/crossplane/crossplane-runtime/pkg/logging"
|
||||
"github.com/crossplane/crossplane-runtime/pkg/meta"
|
||||
"github.com/crossplane/crossplane-runtime/pkg/reconciler/managed"
|
||||
xpresource "github.com/crossplane/crossplane-runtime/pkg/resource"
|
||||
xpv1 "github.com/crossplane/crossplane-runtime/v2/apis/common/v1"
|
||||
"github.com/crossplane/crossplane-runtime/v2/pkg/logging"
|
||||
"github.com/crossplane/crossplane-runtime/v2/pkg/meta"
|
||||
"github.com/crossplane/crossplane-runtime/v2/pkg/reconciler/managed"
|
||||
xpresource "github.com/crossplane/crossplane-runtime/v2/pkg/resource"
|
||||
"github.com/pkg/errors"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
"github.com/crossplane/upjet/pkg/config"
|
||||
"github.com/crossplane/upjet/pkg/controller/handler"
|
||||
"github.com/crossplane/upjet/pkg/metrics"
|
||||
"github.com/crossplane/upjet/pkg/resource"
|
||||
"github.com/crossplane/upjet/pkg/terraform"
|
||||
tferrors "github.com/crossplane/upjet/pkg/terraform/errors"
|
||||
"github.com/crossplane/upjet/v2/pkg/config"
|
||||
"github.com/crossplane/upjet/v2/pkg/controller/handler"
|
||||
"github.com/crossplane/upjet/v2/pkg/metrics"
|
||||
"github.com/crossplane/upjet/v2/pkg/resource"
|
||||
"github.com/crossplane/upjet/v2/pkg/terraform"
|
||||
tferrors "github.com/crossplane/upjet/v2/pkg/terraform/errors"
|
||||
)
|
||||
|
||||
var defaultAsyncTimeout = 1 * time.Hour
|
||||
|
@ -156,7 +157,11 @@ func (n *terraformPluginSDKAsyncExternal) Create(_ context.Context, mg xpresourc
|
|||
n.opTracker.logger.Debug("Async create ended.", "error", err, "tfID", n.opTracker.GetTfID())
|
||||
|
||||
n.opTracker.LastOperation.MarkEnd()
|
||||
if cErr := n.callback.Create(mg.GetName())(err, ctx); cErr != nil {
|
||||
name := types.NamespacedName{
|
||||
Namespace: mg.GetNamespace(),
|
||||
Name: mg.GetName(),
|
||||
}
|
||||
if cErr := n.callback.Create(name)(err, ctx); cErr != nil {
|
||||
n.opTracker.logger.Info("Async create callback failed", "error", cErr.Error())
|
||||
}
|
||||
}()
|
||||
|
@ -189,7 +194,11 @@ func (n *terraformPluginSDKAsyncExternal) Update(_ context.Context, mg xpresourc
|
|||
n.opTracker.logger.Debug("Async update ended.", "error", err, "tfID", n.opTracker.GetTfID())
|
||||
|
||||
n.opTracker.LastOperation.MarkEnd()
|
||||
if cErr := n.callback.Update(mg.GetName())(err, ctx); cErr != nil {
|
||||
name := types.NamespacedName{
|
||||
Namespace: mg.GetNamespace(),
|
||||
Name: mg.GetName(),
|
||||
}
|
||||
if cErr := n.callback.Update(name)(err, ctx); cErr != nil {
|
||||
n.opTracker.logger.Info("Async update callback failed", "error", cErr.Error())
|
||||
}
|
||||
}()
|
||||
|
@ -226,7 +235,11 @@ func (n *terraformPluginSDKAsyncExternal) Delete(_ context.Context, mg xpresourc
|
|||
n.opTracker.logger.Debug("Async delete ended.", "error", err, "tfID", n.opTracker.GetTfID())
|
||||
|
||||
n.opTracker.LastOperation.MarkEnd()
|
||||
if cErr := n.callback.Destroy(mg.GetName())(err, ctx); cErr != nil {
|
||||
name := types.NamespacedName{
|
||||
Namespace: mg.GetNamespace(),
|
||||
Name: mg.GetName(),
|
||||
}
|
||||
if cErr := n.callback.Destroy(name)(err, ctx); cErr != nil {
|
||||
n.opTracker.logger.Info("Async delete callback failed", "error", cErr.Error())
|
||||
}
|
||||
}()
|
||||
|
|
|
@ -8,18 +8,19 @@ import (
|
|||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/crossplane/crossplane-runtime/pkg/reconciler/managed"
|
||||
xpresource "github.com/crossplane/crossplane-runtime/pkg/resource"
|
||||
"github.com/crossplane/crossplane-runtime/pkg/test"
|
||||
"github.com/crossplane/crossplane-runtime/v2/pkg/reconciler/managed"
|
||||
xpresource "github.com/crossplane/crossplane-runtime/v2/pkg/resource"
|
||||
"github.com/crossplane/crossplane-runtime/v2/pkg/test"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
|
||||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
|
||||
tf "github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
"github.com/crossplane/upjet/pkg/config"
|
||||
"github.com/crossplane/upjet/pkg/resource/fake"
|
||||
"github.com/crossplane/upjet/pkg/terraform"
|
||||
"github.com/crossplane/upjet/v2/pkg/config"
|
||||
"github.com/crossplane/upjet/v2/pkg/resource/fake"
|
||||
"github.com/crossplane/upjet/v2/pkg/terraform"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -227,7 +228,7 @@ func TestAsyncTerraformPluginSDKCreate(t *testing.T) {
|
|||
cfg: cfgAsync,
|
||||
obj: objAsync,
|
||||
fns: CallbackFns{
|
||||
CreateFn: func(s string) terraform.CallbackFn {
|
||||
CreateFn: func(nn types.NamespacedName) terraform.CallbackFn {
|
||||
return func(err error, ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
@ -271,7 +272,7 @@ func TestAsyncTerraformPluginSDKUpdate(t *testing.T) {
|
|||
cfg: cfgAsync,
|
||||
obj: objAsync,
|
||||
fns: CallbackFns{
|
||||
UpdateFn: func(s string) terraform.CallbackFn {
|
||||
UpdateFn: func(nn types.NamespacedName) terraform.CallbackFn {
|
||||
return func(err error, ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
@ -315,7 +316,7 @@ func TestAsyncTerraformPluginSDKDelete(t *testing.T) {
|
|||
cfg: cfgAsync,
|
||||
obj: objAsync,
|
||||
fns: CallbackFns{
|
||||
DestroyFn: func(s string) terraform.CallbackFn {
|
||||
DestroyFn: func(nn types.NamespacedName) terraform.CallbackFn {
|
||||
return func(err error, ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -8,24 +8,25 @@ import (
|
|||
"context"
|
||||
"testing"
|
||||
|
||||
xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1"
|
||||
"github.com/crossplane/crossplane-runtime/pkg/logging"
|
||||
xpmeta "github.com/crossplane/crossplane-runtime/pkg/meta"
|
||||
"github.com/crossplane/crossplane-runtime/pkg/reconciler/managed"
|
||||
xpresource "github.com/crossplane/crossplane-runtime/pkg/resource"
|
||||
xpfake "github.com/crossplane/crossplane-runtime/pkg/resource/fake"
|
||||
"github.com/crossplane/crossplane-runtime/pkg/test"
|
||||
xpv1 "github.com/crossplane/crossplane-runtime/v2/apis/common/v1"
|
||||
"github.com/crossplane/crossplane-runtime/v2/pkg/logging"
|
||||
xpmeta "github.com/crossplane/crossplane-runtime/v2/pkg/meta"
|
||||
"github.com/crossplane/crossplane-runtime/v2/pkg/reconciler/managed"
|
||||
xpresource "github.com/crossplane/crossplane-runtime/v2/pkg/resource"
|
||||
xpfake "github.com/crossplane/crossplane-runtime/v2/pkg/resource/fake"
|
||||
"github.com/crossplane/crossplane-runtime/v2/pkg/test"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/google/go-cmp/cmp/cmpopts"
|
||||
"github.com/pkg/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
"github.com/crossplane/upjet/pkg/config"
|
||||
"github.com/crossplane/upjet/pkg/resource"
|
||||
"github.com/crossplane/upjet/pkg/resource/fake"
|
||||
"github.com/crossplane/upjet/pkg/resource/json"
|
||||
"github.com/crossplane/upjet/pkg/terraform"
|
||||
"github.com/crossplane/upjet/v2/pkg/config"
|
||||
"github.com/crossplane/upjet/v2/pkg/resource"
|
||||
"github.com/crossplane/upjet/v2/pkg/resource/fake"
|
||||
"github.com/crossplane/upjet/v2/pkg/resource/json"
|
||||
"github.com/crossplane/upjet/v2/pkg/terraform"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -98,20 +99,20 @@ func (s StoreFns) Workspace(ctx context.Context, c resource.SecretClient, tr res
|
|||
}
|
||||
|
||||
type CallbackFns struct {
|
||||
CreateFn func(string) terraform.CallbackFn
|
||||
UpdateFn func(string) terraform.CallbackFn
|
||||
DestroyFn func(string) terraform.CallbackFn
|
||||
CreateFn func(types.NamespacedName) terraform.CallbackFn
|
||||
UpdateFn func(types.NamespacedName) terraform.CallbackFn
|
||||
DestroyFn func(types.NamespacedName) terraform.CallbackFn
|
||||
}
|
||||
|
||||
func (c CallbackFns) Create(name string) terraform.CallbackFn {
|
||||
func (c CallbackFns) Create(name types.NamespacedName) terraform.CallbackFn {
|
||||
return c.CreateFn(name)
|
||||
}
|
||||
|
||||
func (c CallbackFns) Update(name string) terraform.CallbackFn {
|
||||
func (c CallbackFns) Update(name types.NamespacedName) terraform.CallbackFn {
|
||||
return c.UpdateFn(name)
|
||||
}
|
||||
|
||||
func (c CallbackFns) Destroy(name string) terraform.CallbackFn {
|
||||
func (c CallbackFns) Destroy(name types.NamespacedName) terraform.CallbackFn {
|
||||
return c.DestroyFn(name)
|
||||
}
|
||||
|
||||
|
@ -645,7 +646,7 @@ func TestCreate(t *testing.T) {
|
|||
UseAsync: true,
|
||||
},
|
||||
c: CallbackFns{
|
||||
CreateFn: func(s string) terraform.CallbackFn {
|
||||
CreateFn: func(nn types.NamespacedName) terraform.CallbackFn {
|
||||
return nil
|
||||
},
|
||||
},
|
||||
|
@ -718,7 +719,7 @@ func TestUpdate(t *testing.T) {
|
|||
UseAsync: true,
|
||||
},
|
||||
c: CallbackFns{
|
||||
UpdateFn: func(s string) terraform.CallbackFn {
|
||||
UpdateFn: func(nn types.NamespacedName) terraform.CallbackFn {
|
||||
return nil
|
||||
},
|
||||
},
|
||||
|
@ -782,7 +783,7 @@ func TestDelete(t *testing.T) {
|
|||
UseAsync: true,
|
||||
},
|
||||
c: CallbackFns{
|
||||
DestroyFn: func(_ string) terraform.CallbackFn {
|
||||
DestroyFn: func(_ types.NamespacedName) terraform.CallbackFn {
|
||||
return nil
|
||||
},
|
||||
},
|
||||
|
|
|
@ -13,11 +13,11 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1"
|
||||
"github.com/crossplane/crossplane-runtime/pkg/logging"
|
||||
"github.com/crossplane/crossplane-runtime/pkg/meta"
|
||||
"github.com/crossplane/crossplane-runtime/pkg/reconciler/managed"
|
||||
xpresource "github.com/crossplane/crossplane-runtime/pkg/resource"
|
||||
xpv1 "github.com/crossplane/crossplane-runtime/v2/apis/common/v1"
|
||||
"github.com/crossplane/crossplane-runtime/v2/pkg/logging"
|
||||
"github.com/crossplane/crossplane-runtime/v2/pkg/meta"
|
||||
"github.com/crossplane/crossplane-runtime/v2/pkg/reconciler/managed"
|
||||
xpresource "github.com/crossplane/crossplane-runtime/v2/pkg/resource"
|
||||
fwdiag "github.com/hashicorp/terraform-plugin-framework/diag"
|
||||
fwprovider "github.com/hashicorp/terraform-plugin-framework/provider"
|
||||
"github.com/hashicorp/terraform-plugin-framework/providerserver"
|
||||
|
@ -30,11 +30,11 @@ import (
|
|||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
"github.com/crossplane/upjet/pkg/config"
|
||||
"github.com/crossplane/upjet/pkg/metrics"
|
||||
"github.com/crossplane/upjet/pkg/resource"
|
||||
upjson "github.com/crossplane/upjet/pkg/resource/json"
|
||||
"github.com/crossplane/upjet/pkg/terraform"
|
||||
"github.com/crossplane/upjet/v2/pkg/config"
|
||||
"github.com/crossplane/upjet/v2/pkg/metrics"
|
||||
"github.com/crossplane/upjet/v2/pkg/resource"
|
||||
upjson "github.com/crossplane/upjet/v2/pkg/resource/json"
|
||||
"github.com/crossplane/upjet/v2/pkg/terraform"
|
||||
)
|
||||
|
||||
// TerraformPluginFrameworkConnector is an external client, with credentials and
|
||||
|
@ -109,8 +109,8 @@ type terraformPluginFrameworkExternalClient struct {
|
|||
// Connect makes sure the underlying client is ready to issue requests to the
|
||||
// provider API.
|
||||
func (c *TerraformPluginFrameworkConnector) Connect(ctx context.Context, mg xpresource.Managed) (managed.ExternalClient, error) { //nolint:gocyclo
|
||||
c.metricRecorder.ObserveReconcileDelay(mg.GetObjectKind().GroupVersionKind(), mg.GetName())
|
||||
logger := c.logger.WithValues("uid", mg.GetUID(), "name", mg.GetName(), "gvk", mg.GetObjectKind().GroupVersionKind().String())
|
||||
c.metricRecorder.ObserveReconcileDelay(mg.GetObjectKind().GroupVersionKind(), metrics.NameForManaged(mg))
|
||||
logger := c.logger.WithValues("uid", mg.GetUID(), "name", mg.GetName(), "namespace", mg.GetNamespace(), "gvk", mg.GetObjectKind().GroupVersionKind().String())
|
||||
logger.Debug("Connecting to the service provider")
|
||||
start := time.Now()
|
||||
ts, err := c.getTerraformSetup(ctx, c.kube, mg)
|
||||
|
@ -124,7 +124,7 @@ func (c *TerraformPluginFrameworkConnector) Connect(ctx context.Context, mg xpre
|
|||
externalName := meta.GetExternalName(tr)
|
||||
params, err := getExtendedParameters(ctx, tr, externalName, c.config, ts, c.isManagementPoliciesEnabled, c.kube)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to get the extended parameters for resource %q", mg.GetName())
|
||||
return nil, errors.Wrapf(err, "failed to get the extended parameters for resource %q", client.ObjectKeyFromObject(mg))
|
||||
}
|
||||
|
||||
resourceSchema, err := c.getResourceSchema(ctx)
|
||||
|
@ -202,6 +202,10 @@ func (c *TerraformPluginFrameworkConnector) getResourceSchema(ctx context.Contex
|
|||
// at the terraform setup layer with the relevant provider meta if needed
|
||||
// by the provider implementation.
|
||||
func (c *TerraformPluginFrameworkConnector) configureProvider(ctx context.Context, ts terraform.Setup) (tfprotov5.ProviderServer, error) {
|
||||
if ts.FrameworkProvider == nil {
|
||||
return nil, fmt.Errorf("cannot retrieve framework provider")
|
||||
}
|
||||
|
||||
var schemaResp fwprovider.SchemaResponse
|
||||
ts.FrameworkProvider.Schema(ctx, fwprovider.SchemaRequest{}, &schemaResp)
|
||||
if schemaResp.Diagnostics.HasError() {
|
||||
|
@ -319,7 +323,31 @@ func (n *terraformPluginFrameworkExternalClient) Observe(ctx context.Context, mg
|
|||
}
|
||||
|
||||
n.opTracker.SetFrameworkTFState(readResponse.NewState)
|
||||
resourceExists := !tfStateValue.IsNull()
|
||||
|
||||
// Determine if the resource exists based on Terraform state
|
||||
var resourceExists bool
|
||||
if !tfStateValue.IsNull() {
|
||||
// Resource state is not null, assume it exists
|
||||
resourceExists = true
|
||||
// If a custom empty state check function is configured, use it to verify existence
|
||||
if n.config.TerraformPluginFrameworkIsStateEmptyFn != nil {
|
||||
isEmpty, err := n.config.TerraformPluginFrameworkIsStateEmptyFn(ctx, tfStateValue, n.resourceSchema)
|
||||
if err != nil {
|
||||
return managed.ExternalObservation{}, errors.Wrap(err, "cannot check if TF State is empty")
|
||||
}
|
||||
// Override existence based on custom check result
|
||||
resourceExists = !isEmpty
|
||||
// If custom check determines resource doesn't exist, reset state to nil
|
||||
if !resourceExists {
|
||||
nilTfValue := tftypes.NewValue(n.resourceValueTerraformType, nil)
|
||||
nildynamicValue, err := tfprotov5.NewDynamicValue(n.resourceValueTerraformType, nilTfValue)
|
||||
if err != nil {
|
||||
return managed.ExternalObservation{}, errors.Wrap(err, "cannot create nil dynamic value")
|
||||
}
|
||||
n.opTracker.SetFrameworkTFState(&nildynamicValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var stateValueMap map[string]any
|
||||
if resourceExists {
|
||||
|
@ -376,7 +404,7 @@ func (n *terraformPluginFrameworkExternalClient) Observe(ctx context.Context, mg
|
|||
return managed.ExternalObservation{}, errors.Wrap(err, "cannot get connection details")
|
||||
}
|
||||
if !hasDiff {
|
||||
n.metricRecorder.SetReconcileTime(mg.GetName())
|
||||
n.metricRecorder.SetReconcileTime(metrics.NameForManaged(mg))
|
||||
}
|
||||
if !specUpdateRequired {
|
||||
resource.SetUpToDateCondition(mg, !hasDiff)
|
||||
|
@ -564,13 +592,9 @@ func (n *terraformPluginFrameworkExternalClient) Delete(ctx context.Context, _ x
|
|||
}
|
||||
|
||||
func (n *terraformPluginFrameworkExternalClient) setExternalName(mg xpresource.Managed, stateValueMap map[string]interface{}) (bool, error) {
|
||||
id, ok := stateValueMap["id"]
|
||||
if !ok || id.(string) == "" {
|
||||
return false, nil
|
||||
}
|
||||
newName, err := n.config.ExternalName.GetExternalNameFn(stateValueMap)
|
||||
if err != nil {
|
||||
return false, errors.Wrapf(err, "failed to compute the external-name from the state map of the resource with the ID %s", id)
|
||||
return false, errors.Wrap(err, "failed to compute the external-name from the state map")
|
||||
}
|
||||
oldName := meta.GetExternalName(mg)
|
||||
// we have to make sure the newly set external-name is recorded
|
||||
|
|
|
@ -8,9 +8,9 @@ import (
|
|||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/crossplane/crossplane-runtime/pkg/reconciler/managed"
|
||||
xpresource "github.com/crossplane/crossplane-runtime/pkg/resource"
|
||||
"github.com/crossplane/crossplane-runtime/pkg/test"
|
||||
"github.com/crossplane/crossplane-runtime/v2/pkg/reconciler/managed"
|
||||
xpresource "github.com/crossplane/crossplane-runtime/v2/pkg/resource"
|
||||
"github.com/crossplane/crossplane-runtime/v2/pkg/test"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/hashicorp/terraform-plugin-framework/datasource"
|
||||
"github.com/hashicorp/terraform-plugin-framework/provider"
|
||||
|
@ -25,9 +25,9 @@ import (
|
|||
"github.com/pkg/errors"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
"github.com/crossplane/upjet/pkg/config"
|
||||
"github.com/crossplane/upjet/pkg/resource/fake"
|
||||
"github.com/crossplane/upjet/pkg/terraform"
|
||||
"github.com/crossplane/upjet/v2/pkg/config"
|
||||
"github.com/crossplane/upjet/v2/pkg/resource/fake"
|
||||
"github.com/crossplane/upjet/v2/pkg/terraform"
|
||||
)
|
||||
|
||||
func newBaseObject() fake.Terraformed {
|
||||
|
@ -532,6 +532,51 @@ type mockTPFProviderServer struct {
|
|||
ReadDataSourceFn func(ctx context.Context, request *tfprotov5.ReadDataSourceRequest) (*tfprotov5.ReadDataSourceResponse, error)
|
||||
}
|
||||
|
||||
func (m *mockTPFProviderServer) UpgradeResourceIdentity(_ context.Context, _ *tfprotov5.UpgradeResourceIdentityRequest) (*tfprotov5.UpgradeResourceIdentityResponse, error) {
|
||||
// TODO implement me
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (m *mockTPFProviderServer) GetResourceIdentitySchemas(_ context.Context, _ *tfprotov5.GetResourceIdentitySchemasRequest) (*tfprotov5.GetResourceIdentitySchemasResponse, error) {
|
||||
// TODO implement me
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (m *mockTPFProviderServer) MoveResourceState(_ context.Context, _ *tfprotov5.MoveResourceStateRequest) (*tfprotov5.MoveResourceStateResponse, error) {
|
||||
// TODO implement me
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (m *mockTPFProviderServer) CallFunction(_ context.Context, _ *tfprotov5.CallFunctionRequest) (*tfprotov5.CallFunctionResponse, error) {
|
||||
// TODO implement me
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (m *mockTPFProviderServer) GetFunctions(_ context.Context, _ *tfprotov5.GetFunctionsRequest) (*tfprotov5.GetFunctionsResponse, error) {
|
||||
// TODO implement me
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (m *mockTPFProviderServer) ValidateEphemeralResourceConfig(_ context.Context, _ *tfprotov5.ValidateEphemeralResourceConfigRequest) (*tfprotov5.ValidateEphemeralResourceConfigResponse, error) {
|
||||
// TODO implement me
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (m *mockTPFProviderServer) OpenEphemeralResource(_ context.Context, _ *tfprotov5.OpenEphemeralResourceRequest) (*tfprotov5.OpenEphemeralResourceResponse, error) {
|
||||
// TODO implement me
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (m *mockTPFProviderServer) RenewEphemeralResource(_ context.Context, _ *tfprotov5.RenewEphemeralResourceRequest) (*tfprotov5.RenewEphemeralResourceResponse, error) {
|
||||
// TODO implement me
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (m *mockTPFProviderServer) CloseEphemeralResource(_ context.Context, _ *tfprotov5.CloseEphemeralResourceRequest) (*tfprotov5.CloseEphemeralResourceResponse, error) {
|
||||
// TODO implement me
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (m *mockTPFProviderServer) GetMetadata(_ context.Context, _ *tfprotov5.GetMetadataRequest) (*tfprotov5.GetMetadataResponse, error) {
|
||||
// TODO implement me
|
||||
panic("implement me")
|
||||
|
|
|
@ -10,12 +10,12 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1"
|
||||
"github.com/crossplane/crossplane-runtime/pkg/fieldpath"
|
||||
"github.com/crossplane/crossplane-runtime/pkg/logging"
|
||||
"github.com/crossplane/crossplane-runtime/pkg/meta"
|
||||
"github.com/crossplane/crossplane-runtime/pkg/reconciler/managed"
|
||||
xpresource "github.com/crossplane/crossplane-runtime/pkg/resource"
|
||||
xpv1 "github.com/crossplane/crossplane-runtime/v2/apis/common/v1"
|
||||
"github.com/crossplane/crossplane-runtime/v2/pkg/fieldpath"
|
||||
"github.com/crossplane/crossplane-runtime/v2/pkg/logging"
|
||||
"github.com/crossplane/crossplane-runtime/v2/pkg/meta"
|
||||
"github.com/crossplane/crossplane-runtime/v2/pkg/reconciler/managed"
|
||||
xpresource "github.com/crossplane/crossplane-runtime/v2/pkg/resource"
|
||||
"github.com/hashicorp/go-cty/cty"
|
||||
tfdiag "github.com/hashicorp/terraform-plugin-sdk/v2/diag"
|
||||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
|
||||
|
@ -25,11 +25,11 @@ import (
|
|||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
"github.com/crossplane/upjet/pkg/config"
|
||||
"github.com/crossplane/upjet/pkg/metrics"
|
||||
"github.com/crossplane/upjet/pkg/resource"
|
||||
"github.com/crossplane/upjet/pkg/resource/json"
|
||||
"github.com/crossplane/upjet/pkg/terraform"
|
||||
"github.com/crossplane/upjet/v2/pkg/config"
|
||||
"github.com/crossplane/upjet/v2/pkg/metrics"
|
||||
"github.com/crossplane/upjet/v2/pkg/resource"
|
||||
"github.com/crossplane/upjet/v2/pkg/resource/json"
|
||||
"github.com/crossplane/upjet/v2/pkg/terraform"
|
||||
)
|
||||
|
||||
type TerraformPluginSDKConnector struct {
|
||||
|
@ -128,6 +128,10 @@ func getExtendedParameters(ctx context.Context, tr resource.Terraformed, externa
|
|||
if err != nil {
|
||||
return nil, errors.Wrap(err, "cannot get merged parameters")
|
||||
}
|
||||
params, err = cfg.ApplyTFConversions(params, config.ToTerraform)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "cannot apply tf conversions")
|
||||
}
|
||||
if err = resource.GetSensitiveParameters(ctx, &APISecretClient{kube: kube}, tr, params, tr.GetConnectionDetailsMapping()); err != nil {
|
||||
return nil, errors.Wrap(err, "cannot store sensitive parameters into params")
|
||||
}
|
||||
|
@ -156,7 +160,7 @@ func getExtendedParameters(ctx context.Context, tr resource.Terraformed, externa
|
|||
params["tags_all"] = params["tags"]
|
||||
}
|
||||
}
|
||||
return cfg.ApplyTFConversions(params, config.ToTerraform)
|
||||
return params, nil
|
||||
}
|
||||
|
||||
func (c *TerraformPluginSDKConnector) processParamsWithHCLParser(schemaMap map[string]*schema.Schema, params map[string]any) map[string]any {
|
||||
|
@ -225,8 +229,8 @@ func (c *TerraformPluginSDKConnector) applyHCLParserToParam(sc *schema.Schema, p
|
|||
}
|
||||
|
||||
func (c *TerraformPluginSDKConnector) Connect(ctx context.Context, mg xpresource.Managed) (managed.ExternalClient, error) { //nolint:gocyclo
|
||||
c.metricRecorder.ObserveReconcileDelay(mg.GetObjectKind().GroupVersionKind(), mg.GetName())
|
||||
logger := c.logger.WithValues("uid", mg.GetUID(), "name", mg.GetName(), "gvk", mg.GetObjectKind().GroupVersionKind().String())
|
||||
c.metricRecorder.ObserveReconcileDelay(mg.GetObjectKind().GroupVersionKind(), metrics.NameForManaged(mg))
|
||||
logger := c.logger.WithValues("uid", mg.GetUID(), "name", mg.GetName(), "namespace", mg.GetNamespace(), "gvk", mg.GetObjectKind().GroupVersionKind().String())
|
||||
logger.Debug("Connecting to the service provider")
|
||||
start := time.Now()
|
||||
ts, err := c.getTerraformSetup(ctx, c.kube, mg)
|
||||
|
@ -241,7 +245,7 @@ func (c *TerraformPluginSDKConnector) Connect(ctx context.Context, mg xpresource
|
|||
externalName := meta.GetExternalName(tr)
|
||||
params, err := getExtendedParameters(ctx, tr, externalName, c.config, ts, c.isManagementPoliciesEnabled, c.kube)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to get the extended parameters for resource %q", mg.GetName())
|
||||
return nil, errors.Wrapf(err, "failed to get the extended parameters for resource %q", client.ObjectKeyFromObject(mg))
|
||||
}
|
||||
params = c.processParamsWithHCLParser(c.config.TerraformResource.Schema, params)
|
||||
|
||||
|
@ -422,6 +426,11 @@ func (n *terraformPluginSDKExternal) getResourceDataDiff(tr resource.Terraformed
|
|||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to get *terraform.InstanceDiff")
|
||||
}
|
||||
// Sanitize Identity field in Diff.
|
||||
// This causes continuous diff loop.
|
||||
if instanceDiff != nil {
|
||||
instanceDiff.Identity = nil
|
||||
}
|
||||
if n.config.TerraformCustomDiff != nil {
|
||||
instanceDiff, err = n.config.TerraformCustomDiff(instanceDiff, s, resourceConfig)
|
||||
if err != nil {
|
||||
|
@ -557,7 +566,7 @@ func (n *terraformPluginSDKExternal) Observe(ctx context.Context, mg xpresource.
|
|||
}
|
||||
|
||||
if !hasDiff {
|
||||
n.metricRecorder.SetReconcileTime(mg.GetName())
|
||||
n.metricRecorder.SetReconcileTime(metrics.NameForManaged(mg))
|
||||
}
|
||||
if !specUpdateRequired {
|
||||
resource.SetUpToDateCondition(mg, !hasDiff)
|
||||
|
|
|
@ -9,10 +9,10 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/crossplane/crossplane-runtime/pkg/logging"
|
||||
"github.com/crossplane/crossplane-runtime/pkg/reconciler/managed"
|
||||
xpresource "github.com/crossplane/crossplane-runtime/pkg/resource"
|
||||
"github.com/crossplane/crossplane-runtime/pkg/test"
|
||||
"github.com/crossplane/crossplane-runtime/v2/pkg/logging"
|
||||
"github.com/crossplane/crossplane-runtime/v2/pkg/reconciler/managed"
|
||||
xpresource "github.com/crossplane/crossplane-runtime/v2/pkg/resource"
|
||||
"github.com/crossplane/crossplane-runtime/v2/pkg/test"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
|
||||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
|
||||
|
@ -21,9 +21,9 @@ import (
|
|||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/log/zap"
|
||||
|
||||
"github.com/crossplane/upjet/pkg/config"
|
||||
"github.com/crossplane/upjet/pkg/resource/fake"
|
||||
"github.com/crossplane/upjet/pkg/terraform"
|
||||
"github.com/crossplane/upjet/v2/pkg/config"
|
||||
"github.com/crossplane/upjet/v2/pkg/resource/fake"
|
||||
"github.com/crossplane/upjet/v2/pkg/terraform"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
|
@ -7,7 +7,7 @@ package controller
|
|||
import (
|
||||
"context"
|
||||
|
||||
xpresource "github.com/crossplane/crossplane-runtime/pkg/resource"
|
||||
xpresource "github.com/crossplane/crossplane-runtime/v2/pkg/resource"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/crossplane/crossplane-runtime/pkg/logging"
|
||||
"github.com/crossplane/crossplane-runtime/v2/pkg/logging"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/client-go/util/workqueue"
|
||||
"sigs.k8s.io/controller-runtime/pkg/event"
|
||||
|
@ -54,7 +54,7 @@ func NewEventHandler(opts ...Option) *EventHandler {
|
|||
|
||||
// RequestReconcile requeues a reconciliation request for the specified name.
|
||||
// Returns true if the reconcile request was successfully queued.
|
||||
func (e *EventHandler) RequestReconcile(rateLimiterName, name string, failureLimit *int) bool {
|
||||
func (e *EventHandler) RequestReconcile(rateLimiterName string, name types.NamespacedName, failureLimit *int) bool {
|
||||
e.mu.Lock()
|
||||
defer e.mu.Unlock()
|
||||
if e.queue == nil {
|
||||
|
@ -62,9 +62,7 @@ func (e *EventHandler) RequestReconcile(rateLimiterName, name string, failureLim
|
|||
}
|
||||
logger := e.logger.WithValues("name", name)
|
||||
item := reconcile.Request{
|
||||
NamespacedName: types.NamespacedName{
|
||||
Name: name,
|
||||
},
|
||||
NamespacedName: name,
|
||||
}
|
||||
var when time.Duration = 0
|
||||
if rateLimiterName != NoRateLimiter {
|
||||
|
@ -86,7 +84,7 @@ func (e *EventHandler) RequestReconcile(rateLimiterName, name string, failureLim
|
|||
|
||||
// Forget indicates that the reconcile retries is finished for
|
||||
// the specified name.
|
||||
func (e *EventHandler) Forget(rateLimiterName, name string) {
|
||||
func (e *EventHandler) Forget(rateLimiterName string, name types.NamespacedName) {
|
||||
e.mu.RLock()
|
||||
defer e.mu.RUnlock()
|
||||
rateLimiter := e.rateLimiterMap[rateLimiterName]
|
||||
|
@ -94,9 +92,7 @@ func (e *EventHandler) Forget(rateLimiterName, name string) {
|
|||
return
|
||||
}
|
||||
rateLimiter.Forget(reconcile.Request{
|
||||
NamespacedName: types.NamespacedName{
|
||||
Name: name,
|
||||
},
|
||||
NamespacedName: name,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -110,24 +106,24 @@ func (e *EventHandler) setQueue(limitingInterface workqueue.TypedRateLimitingInt
|
|||
|
||||
func (e *EventHandler) Create(ctx context.Context, ev event.CreateEvent, limitingInterface workqueue.TypedRateLimitingInterface[reconcile.Request]) {
|
||||
e.setQueue(limitingInterface)
|
||||
e.logger.Debug("Calling the inner handler for Create event.", "name", ev.Object.GetName(), "queueLength", limitingInterface.Len())
|
||||
e.logger.Debug("Calling the inner handler for Create event.", "name", ev.Object.GetName(), "namespace", ev.Object.GetNamespace(), "queueLength", limitingInterface.Len())
|
||||
e.innerHandler.Create(ctx, ev, limitingInterface)
|
||||
}
|
||||
|
||||
func (e *EventHandler) Update(ctx context.Context, ev event.UpdateEvent, limitingInterface workqueue.TypedRateLimitingInterface[reconcile.Request]) {
|
||||
e.setQueue(limitingInterface)
|
||||
e.logger.Debug("Calling the inner handler for Update event.", "name", ev.ObjectOld.GetName(), "queueLength", limitingInterface.Len())
|
||||
e.logger.Debug("Calling the inner handler for Update event.", "name", ev.ObjectOld.GetName(), "namespace", ev.ObjectOld.GetNamespace(), "queueLength", limitingInterface.Len())
|
||||
e.innerHandler.Update(ctx, ev, limitingInterface)
|
||||
}
|
||||
|
||||
func (e *EventHandler) Delete(ctx context.Context, ev event.DeleteEvent, limitingInterface workqueue.TypedRateLimitingInterface[reconcile.Request]) {
|
||||
e.setQueue(limitingInterface)
|
||||
e.logger.Debug("Calling the inner handler for Delete event.", "name", ev.Object.GetName(), "queueLength", limitingInterface.Len())
|
||||
e.logger.Debug("Calling the inner handler for Delete event.", "name", ev.Object.GetName(), "namespace", ev.Object.GetNamespace(), "queueLength", limitingInterface.Len())
|
||||
e.innerHandler.Delete(ctx, ev, limitingInterface)
|
||||
}
|
||||
|
||||
func (e *EventHandler) Generic(ctx context.Context, ev event.GenericEvent, limitingInterface workqueue.TypedRateLimitingInterface[reconcile.Request]) {
|
||||
e.setQueue(limitingInterface)
|
||||
e.logger.Debug("Calling the inner handler for Generic event.", "name", ev.Object.GetName(), "queueLength", limitingInterface.Len())
|
||||
e.logger.Debug("Calling the inner handler for Generic event.", "name", ev.Object.GetName(), "namespace", ev.Object.GetNamespace(), "queueLength", limitingInterface.Len())
|
||||
e.innerHandler.Generic(ctx, ev, limitingInterface)
|
||||
}
|
||||
|
|
|
@ -7,9 +7,11 @@ package controller
|
|||
import (
|
||||
"context"
|
||||
|
||||
"github.com/crossplane/upjet/pkg/config"
|
||||
"github.com/crossplane/upjet/pkg/resource"
|
||||
"github.com/crossplane/upjet/pkg/terraform"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
|
||||
"github.com/crossplane/upjet/v2/pkg/config"
|
||||
"github.com/crossplane/upjet/v2/pkg/resource"
|
||||
"github.com/crossplane/upjet/v2/pkg/terraform"
|
||||
)
|
||||
|
||||
// TODO(muvaf): It's a bit weird that the functions return the struct of a
|
||||
|
@ -40,7 +42,7 @@ type Store interface {
|
|||
// CallbackProvider provides functions that can be called with the result of
|
||||
// async operations.
|
||||
type CallbackProvider interface {
|
||||
Create(name string) terraform.CallbackFn
|
||||
Update(name string) terraform.CallbackFn
|
||||
Destroy(name string) terraform.CallbackFn
|
||||
Create(name types.NamespacedName) terraform.CallbackFn
|
||||
Update(name types.NamespacedName) terraform.CallbackFn
|
||||
Destroy(name types.NamespacedName) terraform.CallbackFn
|
||||
}
|
||||
|
|
|
@ -8,14 +8,14 @@ import (
|
|||
"sync"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/crossplane/crossplane-runtime/pkg/logging"
|
||||
xpresource "github.com/crossplane/crossplane-runtime/pkg/resource"
|
||||
"github.com/crossplane/crossplane-runtime/v2/pkg/logging"
|
||||
xpresource "github.com/crossplane/crossplane-runtime/v2/pkg/resource"
|
||||
"github.com/hashicorp/terraform-plugin-go/tfprotov5"
|
||||
tfsdk "github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
|
||||
"github.com/crossplane/upjet/pkg/resource"
|
||||
"github.com/crossplane/upjet/pkg/terraform"
|
||||
"github.com/crossplane/upjet/v2/pkg/resource"
|
||||
"github.com/crossplane/upjet/v2/pkg/terraform"
|
||||
)
|
||||
|
||||
// AsyncTracker holds information for a managed resource to track the
|
||||
|
@ -189,7 +189,7 @@ func (ops *OperationTrackerStore) Tracker(tr resource.Terraformed) *AsyncTracker
|
|||
defer ops.mu.Unlock()
|
||||
tracker, ok := ops.store[tr.GetUID()]
|
||||
if !ok {
|
||||
l := ops.logger.WithValues("trackerUID", tr.GetUID(), "resourceName", tr.GetName(), "gvk", tr.GetObjectKind().GroupVersionKind().String())
|
||||
l := ops.logger.WithValues("trackerUID", tr.GetUID(), "resourceName", tr.GetName(), "resourceNamespace", tr.GetNamespace(), "gvk", tr.GetObjectKind().GroupVersionKind().String())
|
||||
ops.store[tr.GetUID()] = NewAsyncTracker(WithAsyncTrackerLogger(l))
|
||||
tracker = ops.store[tr.GetUID()]
|
||||
}
|
||||
|
|
|
@ -5,14 +5,12 @@
|
|||
package controller
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"time"
|
||||
|
||||
"github.com/crossplane/crossplane-runtime/pkg/controller"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"github.com/crossplane/crossplane-runtime/v2/pkg/controller"
|
||||
|
||||
"github.com/crossplane/upjet/pkg/config"
|
||||
"github.com/crossplane/upjet/pkg/terraform"
|
||||
"github.com/crossplane/upjet/v2/pkg/config"
|
||||
"github.com/crossplane/upjet/v2/pkg/terraform"
|
||||
)
|
||||
|
||||
// Options contains incriminating options for a given Upjet controller instance.
|
||||
|
@ -34,14 +32,6 @@ type Options struct {
|
|||
// preparing the auth token for Terraform CLI.
|
||||
SetupFn terraform.SetupFn
|
||||
|
||||
// SecretStoreConfigGVK is the GroupVersionKind for the Secret StoreConfig
|
||||
// resource. Setting this enables External Secret Stores for the controller
|
||||
// by adding connection.DetailsManager as a ConnectionPublisher.
|
||||
SecretStoreConfigGVK *schema.GroupVersionKind
|
||||
|
||||
// ESSOptions for External Secret Stores.
|
||||
ESSOptions *ESSOptions
|
||||
|
||||
// PollJitter adds the specified jitter to the configured reconcile period
|
||||
// of the up-to-date resources in managed.Reconciler.
|
||||
PollJitter time.Duration
|
||||
|
@ -50,9 +40,3 @@ type Options struct {
|
|||
// provider's controllerruntime.Manager.
|
||||
StartWebhooks bool
|
||||
}
|
||||
|
||||
// ESSOptions for External Secret Stores.
|
||||
type ESSOptions struct {
|
||||
TLSConfig *tls.Config
|
||||
TLSSecretName *string
|
||||
}
|
||||
|
|
|
@ -19,8 +19,8 @@ import (
|
|||
kyaml "k8s.io/apimachinery/pkg/util/yaml"
|
||||
"sigs.k8s.io/yaml"
|
||||
|
||||
"github.com/crossplane/upjet/pkg/config"
|
||||
"github.com/crossplane/upjet/pkg/config/conversion"
|
||||
"github.com/crossplane/upjet/v2/pkg/config"
|
||||
"github.com/crossplane/upjet/v2/pkg/config/conversion"
|
||||
)
|
||||
|
||||
// ConvertSingletonListToEmbeddedObject generates the example manifests for
|
||||
|
|
|
@ -14,17 +14,17 @@ import (
|
|||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/crossplane/crossplane-runtime/pkg/fieldpath"
|
||||
xpmeta "github.com/crossplane/crossplane-runtime/pkg/meta"
|
||||
"github.com/crossplane/crossplane-runtime/v2/pkg/fieldpath"
|
||||
xpmeta "github.com/crossplane/crossplane-runtime/v2/pkg/meta"
|
||||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
|
||||
"github.com/pkg/errors"
|
||||
"sigs.k8s.io/yaml"
|
||||
|
||||
"github.com/crossplane/upjet/pkg/config"
|
||||
"github.com/crossplane/upjet/pkg/registry/reference"
|
||||
"github.com/crossplane/upjet/pkg/resource/json"
|
||||
tjtypes "github.com/crossplane/upjet/pkg/types"
|
||||
"github.com/crossplane/upjet/pkg/types/name"
|
||||
"github.com/crossplane/upjet/v2/pkg/config"
|
||||
"github.com/crossplane/upjet/v2/pkg/registry/reference"
|
||||
"github.com/crossplane/upjet/v2/pkg/resource/json"
|
||||
tjtypes "github.com/crossplane/upjet/v2/pkg/types"
|
||||
"github.com/crossplane/upjet/v2/pkg/types/name"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -42,27 +42,53 @@ const (
|
|||
// Generates example manifests for Terraform resources under examples-generated.
|
||||
type Generator struct {
|
||||
reference.Injector
|
||||
rootDir string
|
||||
exampleDir string
|
||||
configResources map[string]*config.Resource
|
||||
resources map[string]*reference.PavedWithManifest
|
||||
|
||||
exampleNamespace string
|
||||
localSecretRefs bool
|
||||
}
|
||||
|
||||
type GeneratorOption func(*Generator)
|
||||
|
||||
// WithLocalSecretRefs configures the example generator to
|
||||
// generate examples with local secret references,
|
||||
// i.e. no namespace specified.
|
||||
func WithLocalSecretRefs() GeneratorOption {
|
||||
return func(g *Generator) {
|
||||
g.localSecretRefs = true
|
||||
}
|
||||
}
|
||||
|
||||
// WithNamespacedExamples configures the example generator to
|
||||
// generate examples with the default namespace
|
||||
func WithNamespacedExamples() GeneratorOption {
|
||||
return func(g *Generator) {
|
||||
g.exampleNamespace = defaultNamespace
|
||||
}
|
||||
}
|
||||
|
||||
// NewGenerator returns a configured Generator
|
||||
func NewGenerator(rootDir, modulePath, shortName string, configResources map[string]*config.Resource) *Generator {
|
||||
return &Generator{
|
||||
func NewGenerator(exampleDir, apisModulePath, shortName string, configResources map[string]*config.Resource, opts ...GeneratorOption) *Generator {
|
||||
g := &Generator{
|
||||
Injector: reference.Injector{
|
||||
ModulePath: modulePath,
|
||||
ModulePath: apisModulePath,
|
||||
ProviderShortName: shortName,
|
||||
},
|
||||
rootDir: rootDir,
|
||||
exampleDir: exampleDir,
|
||||
configResources: configResources,
|
||||
resources: make(map[string]*reference.PavedWithManifest),
|
||||
}
|
||||
for _, opt := range opts {
|
||||
opt(g)
|
||||
}
|
||||
return g
|
||||
}
|
||||
|
||||
// StoreExamples stores the generated example manifests under examples-generated in
|
||||
// their respective API groups.
|
||||
func (eg *Generator) StoreExamples() error { // nolint:gocyclo
|
||||
func (eg *Generator) StoreExamples() error { //nolint:gocyclo
|
||||
for rn, pm := range eg.resources {
|
||||
manifestDir := filepath.Dir(pm.ManifestPath)
|
||||
if err := os.MkdirAll(manifestDir, 0750); err != nil {
|
||||
|
@ -98,7 +124,7 @@ func (eg *Generator) StoreExamples() error { // nolint:gocyclo
|
|||
// e.g. meta.upbound.io/example-id: ec2/v1beta1/instance
|
||||
eGroup := fmt.Sprintf("%s/%s/%s", strings.ToLower(r.ShortGroup), r.Version, strings.ToLower(r.Kind))
|
||||
pmd := paveCRManifest(exampleParams, dr.Config,
|
||||
reference.NewRefPartsFromResourceName(dn).ExampleName, dr.Group, dr.Version, eGroup)
|
||||
reference.NewRefPartsFromResourceName(dn).ExampleName, dr.Group, dr.Version, eGroup, eg.exampleNamespace, eg.localSecretRefs)
|
||||
if err := eg.writeManifest(&buff, pmd, context); err != nil {
|
||||
return errors.Wrapf(err, "cannot store example manifest for %s dependency: %s", rn, dn)
|
||||
}
|
||||
|
@ -115,10 +141,10 @@ func (eg *Generator) StoreExamples() error { // nolint:gocyclo
|
|||
return nil
|
||||
}
|
||||
|
||||
func paveCRManifest(exampleParams map[string]any, r *config.Resource, eName, group, version, eGroup string) *reference.PavedWithManifest {
|
||||
func paveCRManifest(exampleParams map[string]any, r *config.Resource, eName, group, version, eGroup, namespace string, localSecretRefs bool) *reference.PavedWithManifest {
|
||||
delete(exampleParams, "depends_on")
|
||||
delete(exampleParams, "lifecycle")
|
||||
transformFields(r, exampleParams, r.ExternalName.OmittedFields, "")
|
||||
transformFields(r, exampleParams, r.ExternalName.OmittedFields, "", localSecretRefs)
|
||||
metadata := map[string]any{
|
||||
"labels": map[string]string{
|
||||
labelExampleName: eName,
|
||||
|
@ -127,6 +153,9 @@ func paveCRManifest(exampleParams map[string]any, r *config.Resource, eName, gro
|
|||
annotationExampleGroup: eGroup,
|
||||
},
|
||||
}
|
||||
if namespace != "" {
|
||||
metadata["namespace"] = namespace
|
||||
}
|
||||
example := map[string]any{
|
||||
"apiVersion": fmt.Sprintf("%s/%s", group, version),
|
||||
"kind": r.Kind,
|
||||
|
@ -184,8 +213,8 @@ func (eg *Generator) Generate(group, version string, r *config.Resource) error {
|
|||
groupPrefix := strings.ToLower(strings.Split(group, ".")[0])
|
||||
// e.g. gvk = ec2/v1beta1/instance
|
||||
gvk := fmt.Sprintf("%s/%s/%s", groupPrefix, version, strings.ToLower(r.Kind))
|
||||
pm := paveCRManifest(rm.Examples[0].Paved.UnstructuredContent(), r, rm.Examples[0].Name, group, version, gvk)
|
||||
manifestDir := filepath.Join(eg.rootDir, "examples-generated", groupPrefix, r.Version)
|
||||
pm := paveCRManifest(rm.Examples[0].Paved.UnstructuredContent(), r, rm.Examples[0].Name, group, version, gvk, eg.exampleNamespace, eg.localSecretRefs)
|
||||
manifestDir := filepath.Join(eg.exampleDir, groupPrefix, r.Version)
|
||||
pm.ManifestPath = filepath.Join(manifestDir, fmt.Sprintf("%s.yaml", strings.ToLower(r.Kind)))
|
||||
eg.resources[fmt.Sprintf("%s.%s", r.Name, reference.Wildcard)] = pm
|
||||
return nil
|
||||
|
@ -206,7 +235,7 @@ func isStatus(r *config.Resource, attr string) bool {
|
|||
return tjtypes.IsObservation(s)
|
||||
}
|
||||
|
||||
func transformFields(r *config.Resource, params map[string]any, omittedFields []string, namePrefix string) { // nolint:gocyclo
|
||||
func transformFields(r *config.Resource, params map[string]any, omittedFields []string, namePrefix string, localSecretRefs bool) { //nolint:gocyclo
|
||||
for n := range params {
|
||||
hName := getHierarchicalName(namePrefix, n)
|
||||
if isStatus(r, hName) {
|
||||
|
@ -224,7 +253,7 @@ func transformFields(r *config.Resource, params map[string]any, omittedFields []
|
|||
for n, v := range params {
|
||||
switch pT := v.(type) {
|
||||
case map[string]any:
|
||||
transformFields(r, pT, omittedFields, getHierarchicalName(namePrefix, n))
|
||||
transformFields(r, pT, omittedFields, getHierarchicalName(namePrefix, n), localSecretRefs)
|
||||
|
||||
case []any:
|
||||
for _, e := range pT {
|
||||
|
@ -232,7 +261,7 @@ func transformFields(r *config.Resource, params map[string]any, omittedFields []
|
|||
if !ok {
|
||||
continue
|
||||
}
|
||||
transformFields(r, eM, omittedFields, getHierarchicalName(namePrefix, n))
|
||||
transformFields(r, eM, omittedFields, getHierarchicalName(namePrefix, n), localSecretRefs)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -250,11 +279,14 @@ func transformFields(r *config.Resource, params map[string]any, omittedFields []
|
|||
switch {
|
||||
case sch.Sensitive:
|
||||
secretName, secretKey := getSecretRef(v)
|
||||
params[fn.LowerCamelComputed+"SecretRef"] = getRefField(v, map[string]any{
|
||||
ref := map[string]any{
|
||||
"name": secretName,
|
||||
"namespace": defaultNamespace,
|
||||
"key": secretKey,
|
||||
})
|
||||
}
|
||||
if !localSecretRefs {
|
||||
ref["namespace"] = defaultNamespace
|
||||
}
|
||||
params[fn.LowerCamelComputed+"SecretRef"] = getRefField(v, ref)
|
||||
case r.References[fieldPath] != config.Reference{}:
|
||||
switch v.(type) {
|
||||
case []any:
|
||||
|
|
|
@ -6,10 +6,11 @@ package metrics
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/crossplane/crossplane-runtime/pkg/resource"
|
||||
"github.com/crossplane/crossplane-runtime/v2/pkg/resource"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
|
@ -124,6 +125,13 @@ type Observations struct {
|
|||
observeReconcileDelay bool
|
||||
}
|
||||
|
||||
func NameForManaged(mg resource.Managed) string {
|
||||
if mg.GetNamespace() == "" {
|
||||
return mg.GetName()
|
||||
}
|
||||
return fmt.Sprintf("%s/%s", mg.GetNamespace(), mg.GetName())
|
||||
}
|
||||
|
||||
func NewMetricRecorder(gvk schema.GroupVersionKind, c cluster.Cluster, pollInterval time.Duration) *MetricRecorder {
|
||||
return &MetricRecorder{
|
||||
gvk: gvk,
|
||||
|
@ -174,7 +182,7 @@ func (r *MetricRecorder) Start(ctx context.Context) error {
|
|||
obj = final.Obj
|
||||
}
|
||||
managed := obj.(resource.Managed)
|
||||
r.observations.Delete(managed.GetName())
|
||||
r.observations.Delete(NameForManaged(managed))
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
|
|
|
@ -1,347 +0,0 @@
|
|||
// SPDX-FileCopyrightText: 2023 The Crossplane Authors <https://crossplane.io>
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package migration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
v1 "github.com/crossplane/crossplane-runtime/apis/common/v1"
|
||||
"github.com/crossplane/crossplane-runtime/pkg/meta"
|
||||
"github.com/crossplane/crossplane-runtime/pkg/resource/unstructured/claim"
|
||||
"github.com/crossplane/crossplane-runtime/pkg/resource/unstructured/composite"
|
||||
"github.com/pkg/errors"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
)
|
||||
|
||||
const (
|
||||
stepPauseManaged step = iota
|
||||
stepPauseComposites
|
||||
stepCreateNewManaged
|
||||
stepNewCompositions
|
||||
stepEditComposites
|
||||
stepEditClaims
|
||||
stepDeletionPolicyOrphan
|
||||
stepRemoveFinalizers
|
||||
stepDeleteOldManaged
|
||||
stepStartManaged
|
||||
stepStartComposites
|
||||
// this must be the last step
|
||||
stepAPIEnd
|
||||
)
|
||||
|
||||
func getAPIMigrationSteps() []step {
|
||||
steps := make([]step, 0, stepAPIEnd)
|
||||
for i := step(0); i < stepAPIEnd; i++ {
|
||||
steps = append(steps, i)
|
||||
}
|
||||
return steps
|
||||
}
|
||||
|
||||
func getAPIMigrationStepsFileSystemMode() []step {
|
||||
return []step{
|
||||
stepCreateNewManaged,
|
||||
stepNewCompositions,
|
||||
stepEditComposites,
|
||||
stepEditClaims,
|
||||
stepStartManaged,
|
||||
stepStartComposites,
|
||||
// this must be the last step
|
||||
stepAPIEnd,
|
||||
}
|
||||
}
|
||||
|
||||
func (pg *PlanGenerator) addStepsForManagedResource(u *UnstructuredWithMetadata) error {
|
||||
if u.Metadata.Category != CategoryManaged {
|
||||
if _, ok, err := toManagedResource(pg.registry.scheme, u.Object); err != nil || !ok {
|
||||
// not a managed resource or unable to determine
|
||||
// whether it's a managed resource
|
||||
return nil //nolint:nilerr
|
||||
}
|
||||
}
|
||||
qName := getQualifiedName(u.Object)
|
||||
if err := pg.stepPauseManagedResource(u, qName); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := pg.stepOrphanManagedResource(u, qName); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := pg.stepRemoveFinalizersManagedResource(u, qName); err != nil {
|
||||
return err
|
||||
}
|
||||
pg.stepDeleteOldManagedResource(u)
|
||||
orphaned, err := pg.stepOrhanMR(*u)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !orphaned {
|
||||
return nil
|
||||
}
|
||||
_, err = pg.stepRevertOrhanMR(*u)
|
||||
return err
|
||||
}
|
||||
|
||||
func (pg *PlanGenerator) stepStartManagedResource(u *UnstructuredWithMetadata) error {
|
||||
if !pg.stepEnabled(stepStartManaged) {
|
||||
return nil
|
||||
}
|
||||
u.Metadata.Path = fmt.Sprintf("%s/%s.yaml", pg.stepAPI(stepStartManaged).Name, getQualifiedName(u.Object))
|
||||
pg.stepAPI(stepStartManaged).Patch.Files = append(pg.stepAPI(stepStartManaged).Patch.Files, u.Metadata.Path)
|
||||
return pg.pause(*u, false)
|
||||
}
|
||||
|
||||
func (pg *PlanGenerator) stepPauseManagedResource(u *UnstructuredWithMetadata, qName string) error {
|
||||
if !pg.stepEnabled(stepPauseManaged) {
|
||||
return nil
|
||||
}
|
||||
u.Metadata.Path = fmt.Sprintf("%s/%s.yaml", pg.stepAPI(stepPauseManaged).Name, qName)
|
||||
pg.stepAPI(stepPauseManaged).Patch.Files = append(pg.stepAPI(stepPauseManaged).Patch.Files, u.Metadata.Path)
|
||||
return pg.pause(*u, true)
|
||||
}
|
||||
|
||||
func (pg *PlanGenerator) stepPauseComposite(u *UnstructuredWithMetadata) error {
|
||||
if !pg.stepEnabled(stepPauseComposites) {
|
||||
return nil
|
||||
}
|
||||
u.Metadata.Path = fmt.Sprintf("%s/%s.yaml", pg.stepAPI(stepPauseComposites).Name, getQualifiedName(u.Object))
|
||||
pg.stepAPI(stepPauseComposites).Patch.Files = append(pg.stepAPI(stepPauseComposites).Patch.Files, u.Metadata.Path)
|
||||
return pg.pause(*u, true)
|
||||
}
|
||||
|
||||
func (pg *PlanGenerator) stepOrphanManagedResource(u *UnstructuredWithMetadata, qName string) error {
|
||||
if !pg.stepEnabled(stepDeletionPolicyOrphan) {
|
||||
return nil
|
||||
}
|
||||
u.Metadata.Path = fmt.Sprintf("%s/%s.yaml", pg.stepAPI(stepDeletionPolicyOrphan).Name, qName)
|
||||
pg.stepAPI(stepDeletionPolicyOrphan).Patch.Files = append(pg.stepAPI(stepDeletionPolicyOrphan).Patch.Files, u.Metadata.Path)
|
||||
return errors.Wrap(pg.target.Put(UnstructuredWithMetadata{
|
||||
Object: unstructured.Unstructured{
|
||||
Object: addNameGVK(u.Object, map[string]any{
|
||||
"spec": map[string]any{
|
||||
"deletionPolicy": string(v1.DeletionOrphan),
|
||||
},
|
||||
}),
|
||||
},
|
||||
Metadata: u.Metadata,
|
||||
}), errResourceOrphan)
|
||||
}
|
||||
|
||||
func (pg *PlanGenerator) stepRemoveFinalizersManagedResource(u *UnstructuredWithMetadata, qName string) error {
|
||||
if !pg.stepEnabled(stepRemoveFinalizers) {
|
||||
return nil
|
||||
}
|
||||
u.Metadata.Path = fmt.Sprintf("%s/%s.yaml", pg.stepAPI(stepRemoveFinalizers).Name, qName)
|
||||
pg.stepAPI(stepRemoveFinalizers).Patch.Files = append(pg.stepAPI(stepRemoveFinalizers).Patch.Files, u.Metadata.Path)
|
||||
return pg.removeFinalizers(*u)
|
||||
}
|
||||
|
||||
func (pg *PlanGenerator) stepDeleteOldManagedResource(u *UnstructuredWithMetadata) {
|
||||
if !pg.stepEnabled(stepDeleteOldManaged) {
|
||||
return
|
||||
}
|
||||
pg.stepAPI(stepDeleteOldManaged).Delete.Resources = append(pg.stepAPI(stepDeleteOldManaged).Delete.Resources,
|
||||
Resource{
|
||||
GroupVersionKind: FromGroupVersionKind(u.Object.GroupVersionKind()),
|
||||
Name: u.Object.GetName(),
|
||||
})
|
||||
}
|
||||
|
||||
func (pg *PlanGenerator) stepNewManagedResource(u *UnstructuredWithMetadata) error {
|
||||
if !pg.stepEnabled(stepCreateNewManaged) {
|
||||
return nil
|
||||
}
|
||||
meta.AddAnnotations(&u.Object, map[string]string{meta.AnnotationKeyReconciliationPaused: "true"})
|
||||
u.Metadata.Path = fmt.Sprintf("%s/%s.yaml", pg.stepAPI(stepCreateNewManaged).Name, getQualifiedName(u.Object))
|
||||
pg.stepAPI(stepCreateNewManaged).Apply.Files = append(pg.stepAPI(stepCreateNewManaged).Apply.Files, u.Metadata.Path)
|
||||
if err := pg.target.Put(*u); err != nil {
|
||||
return errors.Wrap(err, errResourceOutput)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (pg *PlanGenerator) stepNewComposition(u *UnstructuredWithMetadata) error {
|
||||
if !pg.stepEnabled(stepNewCompositions) {
|
||||
return nil
|
||||
}
|
||||
u.Metadata.Path = fmt.Sprintf("%s/%s.yaml", pg.stepAPI(stepNewCompositions).Name, getQualifiedName(u.Object))
|
||||
pg.stepAPI(stepNewCompositions).Apply.Files = append(pg.stepAPI(stepNewCompositions).Apply.Files, u.Metadata.Path)
|
||||
if err := pg.target.Put(*u); err != nil {
|
||||
return errors.Wrap(err, errCompositionOutput)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (pg *PlanGenerator) stepStartComposites(composites []UnstructuredWithMetadata) error {
|
||||
if !pg.stepEnabled(stepStartComposites) {
|
||||
return nil
|
||||
}
|
||||
for _, u := range composites {
|
||||
u.Metadata.Path = fmt.Sprintf("%s/%s.yaml", pg.stepAPI(stepStartComposites).Name, getQualifiedName(u.Object))
|
||||
pg.stepAPI(stepStartComposites).Patch.Files = append(pg.stepAPI(stepStartComposites).Patch.Files, u.Metadata.Path)
|
||||
if err := pg.pause(u, false); err != nil {
|
||||
return errors.Wrap(err, errCompositeOutput)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (pg *PlanGenerator) pause(u UnstructuredWithMetadata, isPaused bool) error {
|
||||
return errors.Wrap(pg.target.Put(UnstructuredWithMetadata{
|
||||
Object: unstructured.Unstructured{
|
||||
Object: addNameGVK(u.Object, map[string]any{
|
||||
"metadata": map[string]any{
|
||||
"annotations": map[string]any{
|
||||
meta.AnnotationKeyReconciliationPaused: strconv.FormatBool(isPaused),
|
||||
},
|
||||
},
|
||||
}),
|
||||
},
|
||||
Metadata: Metadata{
|
||||
Path: u.Metadata.Path,
|
||||
},
|
||||
}), errPause)
|
||||
}
|
||||
|
||||
func (pg *PlanGenerator) removeFinalizers(u UnstructuredWithMetadata) error {
|
||||
return errors.Wrap(pg.target.Put(UnstructuredWithMetadata{
|
||||
Object: unstructured.Unstructured{
|
||||
Object: addNameGVK(u.Object, map[string]any{
|
||||
"metadata": map[string]any{
|
||||
"finalizers": []any{},
|
||||
},
|
||||
}),
|
||||
},
|
||||
Metadata: Metadata{
|
||||
Path: u.Metadata.Path,
|
||||
},
|
||||
}), errResourceRemoveFinalizer)
|
||||
}
|
||||
|
||||
func (pg *PlanGenerator) stepEditComposites(composites []UnstructuredWithMetadata, convertedMap map[corev1.ObjectReference][]UnstructuredWithMetadata, convertedComposition map[string]string) error {
|
||||
if !pg.stepEnabled(stepEditComposites) {
|
||||
return nil
|
||||
}
|
||||
for _, u := range composites {
|
||||
cp := composite.Unstructured{Unstructured: u.Object}
|
||||
refs := cp.GetResourceReferences()
|
||||
// compute new spec.resourceRefs so that the XR references the new MRs
|
||||
newRefs := make([]corev1.ObjectReference, 0, len(refs))
|
||||
for _, ref := range refs {
|
||||
converted, ok := convertedMap[ref]
|
||||
if !ok {
|
||||
newRefs = append(newRefs, ref)
|
||||
continue
|
||||
}
|
||||
for _, o := range converted {
|
||||
gvk := o.Object.GroupVersionKind()
|
||||
newRefs = append(newRefs, corev1.ObjectReference{
|
||||
Kind: gvk.Kind,
|
||||
Name: o.Object.GetName(),
|
||||
APIVersion: gvk.GroupVersion().String(),
|
||||
})
|
||||
}
|
||||
}
|
||||
cp.SetResourceReferences(newRefs)
|
||||
// compute new spec.compositionRef
|
||||
if ref := cp.GetCompositionReference(); ref != nil && convertedComposition[ref.Name] != "" {
|
||||
ref.Name = convertedComposition[ref.Name]
|
||||
cp.SetCompositionReference(ref)
|
||||
}
|
||||
spec := u.Object.Object["spec"].(map[string]any)
|
||||
u.Metadata.Path = fmt.Sprintf("%s/%s.yaml", pg.stepAPI(stepEditComposites).Name, getQualifiedName(u.Object))
|
||||
pg.stepAPI(stepEditComposites).Patch.Files = append(pg.stepAPI(stepEditComposites).Patch.Files, u.Metadata.Path)
|
||||
if err := pg.target.Put(UnstructuredWithMetadata{
|
||||
Object: unstructured.Unstructured{
|
||||
Object: addNameGVK(u.Object, map[string]any{
|
||||
"spec": map[string]any{
|
||||
keyResourceRefs: spec[keyResourceRefs],
|
||||
keyCompositionRef: spec[keyCompositionRef]},
|
||||
}),
|
||||
},
|
||||
Metadata: u.Metadata,
|
||||
}); err != nil {
|
||||
return errors.Wrap(err, errCompositeOutput)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (pg *PlanGenerator) stepEditClaims(claims []UnstructuredWithMetadata, convertedComposition map[string]string) error {
|
||||
if !pg.stepEnabled(stepEditClaims) {
|
||||
return nil
|
||||
}
|
||||
for _, u := range claims {
|
||||
cm := claim.Unstructured{Unstructured: u.Object}
|
||||
if ref := cm.GetCompositionReference(); ref != nil && convertedComposition[ref.Name] != "" {
|
||||
ref.Name = convertedComposition[ref.Name]
|
||||
cm.SetCompositionReference(ref)
|
||||
}
|
||||
u.Metadata.Path = fmt.Sprintf("%s/%s.yaml", pg.stepAPI(stepEditClaims).Name, getQualifiedName(u.Object))
|
||||
pg.stepAPI(stepEditClaims).Patch.Files = append(pg.stepAPI(stepEditClaims).Patch.Files, u.Metadata.Path)
|
||||
if err := pg.target.Put(UnstructuredWithMetadata{
|
||||
Object: unstructured.Unstructured{
|
||||
Object: addNameGVK(u.Object, map[string]any{
|
||||
"spec": map[string]any{
|
||||
keyCompositionRef: u.Object.Object["spec"].(map[string]any)[keyCompositionRef],
|
||||
},
|
||||
}),
|
||||
},
|
||||
Metadata: u.Metadata,
|
||||
}); err != nil {
|
||||
return errors.Wrap(err, errClaimOutput)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// NOTE: to cover different migration scenarios, we may use
|
||||
// "migration templates" instead of a static plan. But a static plan should be
|
||||
// fine as a start.
|
||||
func (pg *PlanGenerator) stepAPI(s step) *Step { //nolint:gocyclo // all steps under a single clause for readability
|
||||
stepKey := strconv.Itoa(int(s))
|
||||
if pg.Plan.Spec.stepMap[stepKey] != nil {
|
||||
return pg.Plan.Spec.stepMap[stepKey]
|
||||
}
|
||||
|
||||
pg.Plan.Spec.stepMap[stepKey] = &Step{}
|
||||
switch s { //nolint:exhaustive
|
||||
case stepPauseManaged:
|
||||
setPatchStep("pause-managed", pg.Plan.Spec.stepMap[stepKey])
|
||||
|
||||
case stepPauseComposites:
|
||||
setPatchStep("pause-composites", pg.Plan.Spec.stepMap[stepKey])
|
||||
|
||||
case stepCreateNewManaged:
|
||||
setApplyStep("create-new-managed", pg.Plan.Spec.stepMap[stepKey])
|
||||
|
||||
case stepNewCompositions:
|
||||
setApplyStep("new-compositions", pg.Plan.Spec.stepMap[stepKey])
|
||||
|
||||
case stepEditComposites:
|
||||
setPatchStep("edit-composites", pg.Plan.Spec.stepMap[stepKey])
|
||||
|
||||
case stepEditClaims:
|
||||
setPatchStep("edit-claims", pg.Plan.Spec.stepMap[stepKey])
|
||||
|
||||
case stepDeletionPolicyOrphan:
|
||||
setPatchStep("deletion-policy-orphan", pg.Plan.Spec.stepMap[stepKey])
|
||||
|
||||
case stepRemoveFinalizers:
|
||||
setPatchStep("remove-finalizers", pg.Plan.Spec.stepMap[stepKey])
|
||||
|
||||
case stepDeleteOldManaged:
|
||||
setDeleteStep("delete-old-managed", pg.Plan.Spec.stepMap[stepKey])
|
||||
|
||||
case stepStartManaged:
|
||||
setPatchStep("start-managed", pg.Plan.Spec.stepMap[stepKey])
|
||||
|
||||
case stepStartComposites:
|
||||
setPatchStep("start-composites", pg.Plan.Spec.stepMap[stepKey])
|
||||
default:
|
||||
panic(fmt.Sprintf(errInvalidStepFmt, s))
|
||||
}
|
||||
return pg.Plan.Spec.stepMap[stepKey]
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
// SPDX-FileCopyrightText: 2023 The Crossplane Authors <https://crossplane.io>
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package migration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
)
|
||||
|
||||
const (
|
||||
errEditCategory = "failed to put the edited resource of category %q: %s"
|
||||
)
|
||||
|
||||
func (pg *PlanGenerator) stepEditCategory(source UnstructuredWithMetadata, t *UnstructuredWithMetadata) error {
|
||||
s := pg.stepConfiguration(stepOrphanMRs)
|
||||
t.Metadata.Path = fmt.Sprintf("%s/%s.yaml", s.Name, getVersionedName(t.Object))
|
||||
s.Patch.Files = append(s.Patch.Files, t.Metadata.Path)
|
||||
patchMap, err := computeJSONMergePathDoc(source.Object, t.Object)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return errors.Wrapf(pg.target.Put(UnstructuredWithMetadata{
|
||||
Object: unstructured.Unstructured{
|
||||
Object: addNameGVK(t.Object, patchMap),
|
||||
},
|
||||
Metadata: t.Metadata,
|
||||
}), errEditCategory, source.Metadata.Category, source.Object.GetName())
|
||||
}
|
|
@ -1,170 +0,0 @@
|
|||
// SPDX-FileCopyrightText: 2023 The Crossplane Authors <https://crossplane.io>
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package migration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
xpmetav1 "github.com/crossplane/crossplane/apis/pkg/meta/v1"
|
||||
xpmetav1alpha1 "github.com/crossplane/crossplane/apis/pkg/meta/v1alpha1"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
const (
|
||||
// configuration migration steps follow any existing API migration steps
|
||||
stepBackupMRs = iota + stepAPIEnd + 1
|
||||
stepBackupComposites
|
||||
stepBackupClaims
|
||||
stepOrphanMRs
|
||||
stepNewFamilyProvider
|
||||
stepCheckHealthFamilyProvider
|
||||
stepNewServiceScopedProvider
|
||||
stepCheckHealthNewServiceScopedProvider
|
||||
stepConfigurationPackageDisableDepResolution
|
||||
stepEditPackageLock
|
||||
stepDeleteMonolithicProvider
|
||||
stepActivateFamilyProviderRevision
|
||||
stepCheckInstallationFamilyProviderRevision
|
||||
stepActivateServiceScopedProviderRevision
|
||||
stepCheckInstallationServiceScopedProviderRevision
|
||||
stepEditConfigurationMetadata
|
||||
stepBuildConfiguration
|
||||
stepPushConfiguration
|
||||
stepEditConfigurationPackage
|
||||
stepConfigurationPackageEnableDepResolution
|
||||
stepRevertOrphanMRs
|
||||
stepConfigurationEnd
|
||||
)
|
||||
|
||||
func getConfigurationMigrationSteps() []step {
|
||||
steps := make([]step, 0, stepConfigurationEnd-stepAPIEnd-1)
|
||||
for i := stepAPIEnd + 1; i < stepConfigurationEnd; i++ {
|
||||
steps = append(steps, i)
|
||||
}
|
||||
return steps
|
||||
}
|
||||
|
||||
const (
|
||||
errConfigurationMetadataOutput = "failed to output configuration YAML document"
|
||||
)
|
||||
|
||||
func (pg *PlanGenerator) convertConfigurationMetadata(o UnstructuredWithMetadata) error {
|
||||
isConverted := false
|
||||
conf, err := toConfigurationMetadata(o.Object)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, confConv := range pg.registry.configurationMetaConverters {
|
||||
if confConv.re == nil || confConv.converter == nil || !confConv.re.MatchString(o.Object.GetName()) {
|
||||
continue
|
||||
}
|
||||
|
||||
switch o.Object.GroupVersionKind().Version {
|
||||
case "v1alpha1":
|
||||
err = confConv.converter.ConfigurationMetadataV1Alpha1(conf.(*xpmetav1alpha1.Configuration))
|
||||
default:
|
||||
err = confConv.converter.ConfigurationMetadataV1(conf.(*xpmetav1.Configuration))
|
||||
}
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to call converter on Configuration: %s", conf.GetName())
|
||||
}
|
||||
// TODO: if a configuration converter only converts a specific version,
|
||||
// (or does not convert the given configuration),
|
||||
// we will have a false positive. Better to compute and check
|
||||
// a diff here.
|
||||
isConverted = true
|
||||
}
|
||||
if !isConverted {
|
||||
return nil
|
||||
}
|
||||
return pg.stepEditConfigurationMetadata(o, &UnstructuredWithMetadata{
|
||||
Object: ToSanitizedUnstructured(conf),
|
||||
Metadata: o.Metadata,
|
||||
})
|
||||
}
|
||||
|
||||
func (pg *PlanGenerator) stepConfiguration(s step) *Step {
|
||||
return pg.stepConfigurationWithSubStep(s, false)
|
||||
}
|
||||
|
||||
func (pg *PlanGenerator) configurationSubStep(s step) string {
|
||||
ss := -1
|
||||
subStep := pg.subSteps[s]
|
||||
if subStep != "" {
|
||||
s, err := strconv.Atoi(subStep)
|
||||
if err == nil {
|
||||
ss = s
|
||||
}
|
||||
}
|
||||
pg.subSteps[s] = strconv.Itoa(ss + 1)
|
||||
return pg.subSteps[s]
|
||||
}
|
||||
|
||||
func (pg *PlanGenerator) stepConfigurationWithSubStep(s step, newSubStep bool) *Step { //nolint:gocyclo // easy to follow all steps here
|
||||
stepKey := strconv.Itoa(int(s))
|
||||
if newSubStep {
|
||||
stepKey = fmt.Sprintf("%s.%s", stepKey, pg.configurationSubStep(s))
|
||||
}
|
||||
if pg.Plan.Spec.stepMap[stepKey] != nil {
|
||||
return pg.Plan.Spec.stepMap[stepKey]
|
||||
}
|
||||
|
||||
pg.Plan.Spec.stepMap[stepKey] = &Step{}
|
||||
switch s { //nolint:exhaustive
|
||||
case stepOrphanMRs:
|
||||
setPatchStep("deletion-policy-orphan", pg.Plan.Spec.stepMap[stepKey])
|
||||
case stepRevertOrphanMRs:
|
||||
setPatchStep("deletion-policy-delete", pg.Plan.Spec.stepMap[stepKey])
|
||||
case stepNewFamilyProvider:
|
||||
setApplyStep("new-ssop", pg.Plan.Spec.stepMap[stepKey])
|
||||
case stepNewServiceScopedProvider:
|
||||
setApplyStep("new-ssop", pg.Plan.Spec.stepMap[stepKey])
|
||||
case stepConfigurationPackageDisableDepResolution:
|
||||
setPatchStep("disable-dependency-resolution", pg.Plan.Spec.stepMap[stepKey])
|
||||
case stepConfigurationPackageEnableDepResolution:
|
||||
setPatchStep("enable-dependency-resolution", pg.Plan.Spec.stepMap[stepKey])
|
||||
case stepEditConfigurationPackage:
|
||||
setPatchStep("edit-configuration-package", pg.Plan.Spec.stepMap[stepKey])
|
||||
case stepEditPackageLock:
|
||||
setPatchStep("edit-package-lock", pg.Plan.Spec.stepMap[stepKey])
|
||||
case stepDeleteMonolithicProvider:
|
||||
setDeleteStep("delete-monolithic-provider", pg.Plan.Spec.stepMap[stepKey])
|
||||
case stepActivateFamilyProviderRevision:
|
||||
setPatchStep("activate-ssop", pg.Plan.Spec.stepMap[stepKey])
|
||||
case stepActivateServiceScopedProviderRevision:
|
||||
setPatchStep("activate-ssop", pg.Plan.Spec.stepMap[stepKey])
|
||||
case stepEditConfigurationMetadata:
|
||||
setExecStep("edit-configuration-metadata", pg.Plan.Spec.stepMap[stepKey])
|
||||
case stepBackupMRs:
|
||||
setExecStep("backup-managed-resources", pg.Plan.Spec.stepMap[stepKey])
|
||||
case stepBackupComposites:
|
||||
setExecStep("backup-composite-resources", pg.Plan.Spec.stepMap[stepKey])
|
||||
case stepBackupClaims:
|
||||
setExecStep("backup-claim-resources", pg.Plan.Spec.stepMap[stepKey])
|
||||
case stepCheckHealthFamilyProvider:
|
||||
setExecStep("wait-for-healthy", pg.Plan.Spec.stepMap[stepKey])
|
||||
case stepCheckHealthNewServiceScopedProvider:
|
||||
setExecStep("wait-for-healthy", pg.Plan.Spec.stepMap[stepKey])
|
||||
case stepCheckInstallationFamilyProviderRevision:
|
||||
setExecStep("wait-for-installed", pg.Plan.Spec.stepMap[stepKey])
|
||||
case stepCheckInstallationServiceScopedProviderRevision:
|
||||
setExecStep("wait-for-installed", pg.Plan.Spec.stepMap[stepKey])
|
||||
case stepBuildConfiguration:
|
||||
setExecStep("build-configuration", pg.Plan.Spec.stepMap[stepKey])
|
||||
case stepPushConfiguration:
|
||||
setExecStep("push-configuration", pg.Plan.Spec.stepMap[stepKey])
|
||||
default:
|
||||
panic(fmt.Sprintf(errInvalidStepFmt, s))
|
||||
}
|
||||
return pg.Plan.Spec.stepMap[stepKey]
|
||||
}
|
||||
|
||||
func (pg *PlanGenerator) stepEditConfigurationMetadata(source UnstructuredWithMetadata, target *UnstructuredWithMetadata) error {
|
||||
s := pg.stepConfiguration(stepEditConfigurationMetadata)
|
||||
target.Metadata.Path = fmt.Sprintf("%s/%s.yaml", s.Name, getVersionedName(target.Object))
|
||||
s.Exec.Args = []string{"-c", fmt.Sprintf("cp %s %s", target.Metadata.Path, source.Metadata.Path)}
|
||||
return errors.Wrap(pg.target.Put(*target), errConfigurationMetadataOutput)
|
||||
}
|
|
@ -1,143 +0,0 @@
|
|||
// SPDX-FileCopyrightText: 2023 The Crossplane Authors <https://crossplane.io>
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package migration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
v1 "github.com/crossplane/crossplane-runtime/apis/common/v1"
|
||||
"github.com/crossplane/crossplane-runtime/pkg/fieldpath"
|
||||
"github.com/pkg/errors"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
)
|
||||
|
||||
const (
|
||||
errSetDeletionPolicyFmt = "failed to put the patch file to set the deletion policy to %q: %s"
|
||||
errEditConfigurationPackageFmt = `failed to put the edited Configuration package: %s`
|
||||
)
|
||||
|
||||
func (pg *PlanGenerator) convertConfigurationPackage(o UnstructuredWithMetadata) error {
|
||||
pkg, err := toConfigurationPackageV1(o.Object)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// add step for disabling the dependency resolution
|
||||
// for the configuration package
|
||||
s := pg.stepConfiguration(stepConfigurationPackageDisableDepResolution)
|
||||
p := fmt.Sprintf("%s/%s.yaml", s.Name, getVersionedName(o.Object))
|
||||
s.Patch.Files = append(s.Patch.Files, p)
|
||||
if err := pg.target.Put(UnstructuredWithMetadata{
|
||||
Object: unstructured.Unstructured{
|
||||
Object: addNameGVK(o.Object, map[string]any{
|
||||
"spec": map[string]any{
|
||||
"skipDependencyResolution": true,
|
||||
},
|
||||
}),
|
||||
},
|
||||
Metadata: Metadata{
|
||||
Path: p,
|
||||
},
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// add step for enabling the dependency resolution
|
||||
// for the configuration package
|
||||
s = pg.stepConfiguration(stepConfigurationPackageEnableDepResolution)
|
||||
p = fmt.Sprintf("%s/%s.yaml", s.Name, getVersionedName(o.Object))
|
||||
s.Patch.Files = append(s.Patch.Files, p)
|
||||
if err := pg.target.Put(UnstructuredWithMetadata{
|
||||
Object: unstructured.Unstructured{
|
||||
Object: addNameGVK(o.Object, map[string]any{
|
||||
"spec": map[string]any{
|
||||
"skipDependencyResolution": false,
|
||||
},
|
||||
}),
|
||||
},
|
||||
Metadata: Metadata{
|
||||
Path: p,
|
||||
},
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// add the step for editing the configuration package
|
||||
for _, pkgConv := range pg.registry.configurationPackageConverters {
|
||||
if pkgConv.re == nil || pkgConv.converter == nil || !pkgConv.re.MatchString(pkg.Spec.Package) {
|
||||
continue
|
||||
}
|
||||
err := pkgConv.converter.ConfigurationPackageV1(pkg)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to call converter on Configuration package: %s", pkg.Spec.Package)
|
||||
}
|
||||
// TODO: if a converter only converts a specific version,
|
||||
// (or does not convert the given configuration),
|
||||
// we will have a false positive. Better to compute and check
|
||||
// a diff here.
|
||||
target := &UnstructuredWithMetadata{
|
||||
Object: ToSanitizedUnstructured(pkg),
|
||||
Metadata: o.Metadata,
|
||||
}
|
||||
if err := pg.stepEditConfigurationPackage(o, target); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (pg *PlanGenerator) stepEditConfigurationPackage(source UnstructuredWithMetadata, t *UnstructuredWithMetadata) error {
|
||||
if !pg.stepEnabled(stepEditConfigurationPackage) {
|
||||
return nil
|
||||
}
|
||||
s := pg.stepConfigurationWithSubStep(stepEditConfigurationPackage, true)
|
||||
t.Metadata.Path = fmt.Sprintf("%s/%s.yaml", s.Name, getVersionedName(t.Object))
|
||||
s.Patch.Files = append(s.Patch.Files, t.Metadata.Path)
|
||||
patchMap, err := computeJSONMergePathDoc(source.Object, t.Object)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return errors.Wrapf(pg.target.Put(UnstructuredWithMetadata{
|
||||
Object: unstructured.Unstructured{
|
||||
Object: addNameGVK(t.Object, patchMap),
|
||||
},
|
||||
Metadata: t.Metadata,
|
||||
}), errEditConfigurationPackageFmt, t.Object.GetName())
|
||||
}
|
||||
|
||||
func (pg *PlanGenerator) stepOrhanMR(u UnstructuredWithMetadata) (bool, error) {
|
||||
return pg.stepSetDeletionPolicy(u, stepOrphanMRs, v1.DeletionOrphan, true)
|
||||
}
|
||||
|
||||
func (pg *PlanGenerator) stepRevertOrhanMR(u UnstructuredWithMetadata) (bool, error) {
|
||||
return pg.stepSetDeletionPolicy(u, stepRevertOrphanMRs, v1.DeletionDelete, false)
|
||||
}
|
||||
|
||||
func (pg *PlanGenerator) stepSetDeletionPolicy(u UnstructuredWithMetadata, step step, policy v1.DeletionPolicy, checkCurrentPolicy bool) (bool, error) {
|
||||
if !pg.stepEnabled(step) {
|
||||
return false, nil
|
||||
}
|
||||
pv := fieldpath.Pave(u.Object.Object)
|
||||
p, err := pv.GetString("spec.deletionPolicy")
|
||||
if err != nil && !fieldpath.IsNotFound(err) {
|
||||
return false, errors.Wrapf(err, "failed to get the current deletion policy from MR: %s", u.Object.GetName())
|
||||
}
|
||||
if checkCurrentPolicy && err == nil && v1.DeletionPolicy(p) == policy {
|
||||
return false, nil
|
||||
}
|
||||
s := pg.stepConfiguration(step)
|
||||
u.Metadata.Path = fmt.Sprintf("%s/%s.yaml", s.Name, getVersionedName(u.Object))
|
||||
s.Patch.Files = append(s.Patch.Files, u.Metadata.Path)
|
||||
return true, errors.Wrapf(pg.target.Put(UnstructuredWithMetadata{
|
||||
Object: unstructured.Unstructured{
|
||||
Object: addNameGVK(u.Object, map[string]any{
|
||||
"spec": map[string]any{
|
||||
"deletionPolicy": string(policy),
|
||||
},
|
||||
}),
|
||||
},
|
||||
Metadata: u.Metadata,
|
||||
}), errSetDeletionPolicyFmt, policy, u.Object.GetName())
|
||||
}
|
|
@ -1,304 +0,0 @@
|
|||
// SPDX-FileCopyrightText: 2023 The Crossplane Authors <https://crossplane.io>
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package migration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/crossplane/crossplane-runtime/pkg/fieldpath"
|
||||
xpmeta "github.com/crossplane/crossplane-runtime/pkg/meta"
|
||||
"github.com/crossplane/crossplane-runtime/pkg/resource"
|
||||
xpv1 "github.com/crossplane/crossplane/apis/apiextensions/v1"
|
||||
xpmetav1 "github.com/crossplane/crossplane/apis/pkg/meta/v1"
|
||||
xpmetav1alpha1 "github.com/crossplane/crossplane/apis/pkg/meta/v1alpha1"
|
||||
xppkgv1 "github.com/crossplane/crossplane/apis/pkg/v1"
|
||||
xppkgv1beta1 "github.com/crossplane/crossplane/apis/pkg/v1beta1"
|
||||
"github.com/pkg/errors"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/util/json"
|
||||
k8sjson "sigs.k8s.io/json"
|
||||
)
|
||||
|
||||
const (
|
||||
errFromUnstructured = "failed to convert from unstructured.Unstructured to the managed resource type"
|
||||
errFromUnstructuredConfMeta = "failed to convert from unstructured.Unstructured to Crossplane Configuration metadata"
|
||||
errFromUnstructuredConfPackage = "failed to convert from unstructured.Unstructured to Crossplane Configuration package"
|
||||
errFromUnstructuredProvider = "failed to convert from unstructured.Unstructured to Crossplane Provider package"
|
||||
errFromUnstructuredLock = "failed to convert from unstructured.Unstructured to Crossplane package lock"
|
||||
errToUnstructured = "failed to convert from the managed resource type to unstructured.Unstructured"
|
||||
errRawExtensionUnmarshal = "failed to unmarshal runtime.RawExtension"
|
||||
|
||||
errFmtPavedDelete = "failed to delete fieldpath %q from paved"
|
||||
|
||||
metadataAnnotationPaveKey = "metadata.annotations['%s']"
|
||||
)
|
||||
|
||||
// CopyInto copies values of fields from the migration `source` object
|
||||
// into the migration `target` object and fills in the target object's
|
||||
// TypeMeta using the supplied `targetGVK`. While copying fields from
|
||||
// migration source to migration target, the fields at the paths
|
||||
// specified with `skipFieldPaths` array are skipped. This is a utility
|
||||
// that can be used in the migration resource converter implementations.
|
||||
// If a certain field with the same name in both the `source` and the `target`
|
||||
// objects has different types in `source` and `target`, then it must be
|
||||
// included in the `skipFieldPaths` and it must manually be handled in the
|
||||
// conversion function.
|
||||
func CopyInto(source any, target any, targetGVK schema.GroupVersionKind, skipFieldPaths ...string) (any, error) {
|
||||
u := ToSanitizedUnstructured(source)
|
||||
paved := fieldpath.Pave(u.Object)
|
||||
skipFieldPaths = append(skipFieldPaths, "apiVersion", "kind",
|
||||
fmt.Sprintf(metadataAnnotationPaveKey, xpmeta.AnnotationKeyExternalCreatePending),
|
||||
fmt.Sprintf(metadataAnnotationPaveKey, xpmeta.AnnotationKeyExternalCreateSucceeded),
|
||||
fmt.Sprintf(metadataAnnotationPaveKey, xpmeta.AnnotationKeyExternalCreateFailed),
|
||||
fmt.Sprintf(metadataAnnotationPaveKey, corev1.LastAppliedConfigAnnotation),
|
||||
)
|
||||
for _, p := range skipFieldPaths {
|
||||
if err := paved.DeleteField(p); err != nil {
|
||||
return nil, errors.Wrapf(err, errFmtPavedDelete, p)
|
||||
}
|
||||
}
|
||||
u.SetGroupVersionKind(targetGVK)
|
||||
return target, errors.Wrap(runtime.DefaultUnstructuredConverter.FromUnstructured(u.Object, target), errFromUnstructured)
|
||||
}
|
||||
|
||||
// sanitizeResource removes certain fields from the unstructured object.
|
||||
// It turns out that certain fields, such as `metadata.creationTimestamp`
|
||||
// are still serialized even if they have zero-values. This function
|
||||
// removes such fields. We also unconditionally sanitize `status`
|
||||
// so that the controller will populate it back.
|
||||
func sanitizeResource(m map[string]any) map[string]any {
|
||||
delete(m, "status")
|
||||
if _, ok := m["metadata"]; !ok {
|
||||
return m
|
||||
}
|
||||
metadata := m["metadata"].(map[string]any)
|
||||
|
||||
if v := metadata["creationTimestamp"]; v == nil {
|
||||
delete(metadata, "creationTimestamp")
|
||||
}
|
||||
if len(metadata) == 0 {
|
||||
delete(m, "metadata")
|
||||
}
|
||||
removeNilValuedKeys(m)
|
||||
return m
|
||||
}
|
||||
|
||||
// removeNilValuedKeys removes nil values from the specified map so that
|
||||
// the serialized manifest do not contain corresponding superfluous YAML
|
||||
// nulls.
|
||||
func removeNilValuedKeys(m map[string]interface{}) {
|
||||
for k, v := range m {
|
||||
if v == nil {
|
||||
delete(m, k)
|
||||
continue
|
||||
}
|
||||
switch c := v.(type) {
|
||||
case map[string]any:
|
||||
removeNilValuedKeys(c)
|
||||
case []any:
|
||||
for _, e := range c {
|
||||
if cm, ok := e.(map[string]interface{}); ok {
|
||||
removeNilValuedKeys(cm)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ToSanitizedUnstructured converts the specified managed resource to an
|
||||
// unstructured.Unstructured. Before the converted object is
|
||||
// returned, it's sanitized by removing certain fields
|
||||
// (like status, metadata.creationTimestamp).
|
||||
func ToSanitizedUnstructured(mg any) unstructured.Unstructured {
|
||||
m, err := runtime.DefaultUnstructuredConverter.ToUnstructured(mg)
|
||||
if err != nil {
|
||||
panic(errors.Wrap(err, errToUnstructured))
|
||||
}
|
||||
return unstructured.Unstructured{
|
||||
Object: sanitizeResource(m),
|
||||
}
|
||||
}
|
||||
|
||||
// FromRawExtension attempts to convert a runtime.RawExtension into
|
||||
// an unstructured.Unstructured.
|
||||
func FromRawExtension(r runtime.RawExtension) (unstructured.Unstructured, error) {
|
||||
var m map[string]interface{}
|
||||
if err := json.Unmarshal(r.Raw, &m); err != nil {
|
||||
return unstructured.Unstructured{}, errors.Wrap(err, errRawExtensionUnmarshal)
|
||||
}
|
||||
return unstructured.Unstructured{
|
||||
Object: m,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// FromGroupVersionKind converts a schema.GroupVersionKind into
|
||||
// a migration.GroupVersionKind.
|
||||
func FromGroupVersionKind(gvk schema.GroupVersionKind) GroupVersionKind {
|
||||
return GroupVersionKind{
|
||||
Group: gvk.Group,
|
||||
Version: gvk.Version,
|
||||
Kind: gvk.Kind,
|
||||
}
|
||||
}
|
||||
|
||||
// ToComposition converts the specified unstructured.Unstructured to
|
||||
// a Crossplane Composition.
|
||||
// Workaround for:
|
||||
// https://github.com/kubernetes-sigs/structured-merge-diff/issues/230
|
||||
func ToComposition(u unstructured.Unstructured) (*xpv1.Composition, error) {
|
||||
buff, err := json.Marshal(u.Object)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to marshal map to JSON")
|
||||
}
|
||||
c := &xpv1.Composition{}
|
||||
return c, errors.Wrap(k8sjson.UnmarshalCaseSensitivePreserveInts(buff, c), "failed to unmarshal into a v1.Composition")
|
||||
}
|
||||
|
||||
func addGVK(u unstructured.Unstructured, target map[string]any) map[string]any {
|
||||
if target == nil {
|
||||
target = make(map[string]any)
|
||||
}
|
||||
target["apiVersion"] = u.GetAPIVersion()
|
||||
target["kind"] = u.GetKind()
|
||||
return target
|
||||
}
|
||||
|
||||
func addNameGVK(u unstructured.Unstructured, target map[string]any) map[string]any {
|
||||
target = addGVK(u, target)
|
||||
m := target["metadata"]
|
||||
if m == nil {
|
||||
m = make(map[string]any)
|
||||
}
|
||||
metadata := m.(map[string]any)
|
||||
metadata["name"] = u.GetName()
|
||||
if len(u.GetNamespace()) != 0 {
|
||||
metadata["namespace"] = u.GetNamespace()
|
||||
}
|
||||
target["metadata"] = m
|
||||
return target
|
||||
}
|
||||
|
||||
func toManagedResource(c runtime.ObjectCreater, u unstructured.Unstructured) (resource.Managed, bool, error) {
|
||||
gvk := u.GroupVersionKind()
|
||||
if gvk == xpv1.CompositionGroupVersionKind {
|
||||
return nil, false, nil
|
||||
}
|
||||
obj, err := c.New(gvk)
|
||||
if err != nil {
|
||||
return nil, false, errors.Wrapf(err, errFmtNewObject, gvk)
|
||||
}
|
||||
if err := runtime.DefaultUnstructuredConverter.FromUnstructured(u.Object, obj); err != nil {
|
||||
return nil, false, errors.Wrap(err, errFromUnstructured)
|
||||
}
|
||||
mg, ok := obj.(resource.Managed)
|
||||
return mg, ok, nil
|
||||
}
|
||||
|
||||
func toConfigurationPackageV1(u unstructured.Unstructured) (*xppkgv1.Configuration, error) {
|
||||
conf := &xppkgv1.Configuration{}
|
||||
if err := runtime.DefaultUnstructuredConverter.FromUnstructured(u.Object, conf); err != nil {
|
||||
return nil, errors.Wrap(err, errFromUnstructuredConfPackage)
|
||||
}
|
||||
return conf, nil
|
||||
}
|
||||
|
||||
func toConfigurationMetadataV1(u unstructured.Unstructured) (*xpmetav1.Configuration, error) {
|
||||
conf := &xpmetav1.Configuration{}
|
||||
if err := runtime.DefaultUnstructuredConverter.FromUnstructured(u.Object, conf); err != nil {
|
||||
return nil, errors.Wrap(err, errFromUnstructuredConfMeta)
|
||||
}
|
||||
return conf, nil
|
||||
}
|
||||
|
||||
func toConfigurationMetadataV1Alpha1(u unstructured.Unstructured) (*xpmetav1alpha1.Configuration, error) {
|
||||
conf := &xpmetav1alpha1.Configuration{}
|
||||
if err := runtime.DefaultUnstructuredConverter.FromUnstructured(u.Object, conf); err != nil {
|
||||
return nil, errors.Wrap(err, errFromUnstructuredConfMeta)
|
||||
}
|
||||
return conf, nil
|
||||
}
|
||||
|
||||
func toConfigurationMetadata(u unstructured.Unstructured) (metav1.Object, error) {
|
||||
var conf metav1.Object
|
||||
var err error
|
||||
switch u.GroupVersionKind().Version {
|
||||
case "v1alpha1":
|
||||
conf, err = toConfigurationMetadataV1Alpha1(u)
|
||||
default:
|
||||
conf, err = toConfigurationMetadataV1(u)
|
||||
}
|
||||
return conf, err
|
||||
}
|
||||
|
||||
func toProviderPackage(u unstructured.Unstructured) (*xppkgv1.Provider, error) {
|
||||
pkg := &xppkgv1.Provider{}
|
||||
if err := runtime.DefaultUnstructuredConverter.FromUnstructured(u.Object, pkg); err != nil {
|
||||
return nil, errors.Wrap(err, errFromUnstructuredProvider)
|
||||
}
|
||||
return pkg, nil
|
||||
}
|
||||
|
||||
func getCategory(u unstructured.Unstructured) Category {
|
||||
switch u.GroupVersionKind() {
|
||||
case xpv1.CompositionGroupVersionKind:
|
||||
return CategoryComposition
|
||||
default:
|
||||
return categoryUnknown
|
||||
}
|
||||
}
|
||||
|
||||
func toPackageLock(u unstructured.Unstructured) (*xppkgv1beta1.Lock, error) {
|
||||
lock := &xppkgv1beta1.Lock{}
|
||||
if err := runtime.DefaultUnstructuredConverter.FromUnstructured(u.Object, lock); err != nil {
|
||||
return nil, errors.Wrap(err, errFromUnstructuredLock)
|
||||
}
|
||||
return lock, nil
|
||||
}
|
||||
|
||||
// ConvertComposedTemplatePatchesMap converts the composed templates with given conversionMap
|
||||
// Key of the conversionMap points to the source field
|
||||
// Value of the conversionMap points to the target field
|
||||
func ConvertComposedTemplatePatchesMap(sourceTemplate xpv1.ComposedTemplate, conversionMap map[string]string) []xpv1.Patch {
|
||||
var patchesToAdd []xpv1.Patch
|
||||
for _, p := range sourceTemplate.Patches {
|
||||
switch p.Type { //nolint:exhaustive
|
||||
case xpv1.PatchTypeFromCompositeFieldPath, xpv1.PatchTypeCombineFromComposite, "":
|
||||
{
|
||||
if p.ToFieldPath != nil {
|
||||
if to, ok := conversionMap[*p.ToFieldPath]; ok {
|
||||
patchesToAdd = append(patchesToAdd, xpv1.Patch{
|
||||
Type: p.Type,
|
||||
FromFieldPath: p.FromFieldPath,
|
||||
ToFieldPath: &to,
|
||||
Transforms: p.Transforms,
|
||||
Policy: p.Policy,
|
||||
Combine: p.Combine,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
case xpv1.PatchTypeToCompositeFieldPath, xpv1.PatchTypeCombineToComposite:
|
||||
{
|
||||
if p.FromFieldPath != nil {
|
||||
if to, ok := conversionMap[*p.FromFieldPath]; ok {
|
||||
patchesToAdd = append(patchesToAdd, xpv1.Patch{
|
||||
Type: p.Type,
|
||||
FromFieldPath: &to,
|
||||
ToFieldPath: p.ToFieldPath,
|
||||
Transforms: p.Transforms,
|
||||
Policy: p.Policy,
|
||||
Combine: p.Combine,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return patchesToAdd
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
// SPDX-FileCopyrightText: 2023 The Crossplane Authors <https://crossplane.io>
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package migration
|
||||
|
||||
import "fmt"
|
||||
|
||||
type errUnsupportedStepType struct {
|
||||
planStep Step
|
||||
}
|
||||
|
||||
func (e errUnsupportedStepType) Error() string {
|
||||
return fmt.Sprintf("executor does not support steps of type %q in step: %s", e.planStep.Type, e.planStep.Name)
|
||||
}
|
||||
|
||||
func NewUnsupportedStepTypeError(s Step) error {
|
||||
return errUnsupportedStepType{
|
||||
planStep: s,
|
||||
}
|
||||
}
|
|
@ -1,80 +0,0 @@
|
|||
// SPDX-FileCopyrightText: 2023 The Crossplane Authors <https://crossplane.io>
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package migration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func (pg *PlanGenerator) stepBackupAllResources() {
|
||||
pg.stepBackupManagedResources()
|
||||
pg.stepBackupCompositeResources()
|
||||
pg.stepBackupClaims()
|
||||
}
|
||||
|
||||
func (pg *PlanGenerator) stepBackupManagedResources() {
|
||||
s := pg.stepConfiguration(stepBackupMRs)
|
||||
s.Exec.Args = []string{"-c", "kubectl get managed -o yaml > backup/managed-resources.yaml"}
|
||||
}
|
||||
|
||||
func (pg *PlanGenerator) stepBackupCompositeResources() {
|
||||
s := pg.stepConfiguration(stepBackupComposites)
|
||||
s.Exec.Args = []string{"-c", "kubectl get composite -o yaml > backup/composite-resources.yaml"}
|
||||
}
|
||||
|
||||
func (pg *PlanGenerator) stepBackupClaims() {
|
||||
s := pg.stepConfiguration(stepBackupClaims)
|
||||
s.Exec.Args = []string{"-c", "kubectl get claim --all-namespaces -o yaml > backup/claim-resources.yaml"}
|
||||
}
|
||||
|
||||
func (pg *PlanGenerator) stepCheckHealthOfNewProvider(source UnstructuredWithMetadata, targets []*UnstructuredWithMetadata) error {
|
||||
for _, t := range targets {
|
||||
var s *Step
|
||||
isFamilyConfig, err := checkContainsFamilyConfigProvider(targets)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "could not decide whether the provider family config")
|
||||
}
|
||||
if isFamilyConfig {
|
||||
s = pg.stepConfigurationWithSubStep(stepCheckHealthFamilyProvider, true)
|
||||
} else {
|
||||
s = pg.stepConfigurationWithSubStep(stepCheckHealthNewServiceScopedProvider, true)
|
||||
}
|
||||
s.Exec.Args = []string{"-c", fmt.Sprintf("kubectl wait provider.pkg %s --for condition=Healthy", t.Object.GetName())}
|
||||
t.Object.Object = addGVK(source.Object, t.Object.Object)
|
||||
t.Metadata.Path = fmt.Sprintf("%s/%s.yaml", s.Name, getVersionedName(t.Object))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (pg *PlanGenerator) stepCheckInstallationOfNewProvider(source UnstructuredWithMetadata, targets []*UnstructuredWithMetadata) error {
|
||||
for _, t := range targets {
|
||||
var s *Step
|
||||
isFamilyConfig, err := checkContainsFamilyConfigProvider(targets)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "could not decide whether the provider family config")
|
||||
}
|
||||
if isFamilyConfig {
|
||||
s = pg.stepConfigurationWithSubStep(stepCheckInstallationFamilyProviderRevision, true)
|
||||
} else {
|
||||
s = pg.stepConfigurationWithSubStep(stepCheckInstallationServiceScopedProviderRevision, true)
|
||||
}
|
||||
s.Exec.Args = []string{"-c", fmt.Sprintf("kubectl wait provider.pkg %s --for condition=Installed", t.Object.GetName())}
|
||||
t.Object.Object = addGVK(source.Object, t.Object.Object)
|
||||
t.Metadata.Path = fmt.Sprintf("%s/%s.yaml", s.Name, getVersionedName(t.Object))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (pg *PlanGenerator) stepBuildConfiguration() {
|
||||
s := pg.stepConfiguration(stepBuildConfiguration)
|
||||
s.Exec.Args = []string{"-c", "up xpkg build --package-root={{PKG_ROOT}} --examples-root={{EXAMPLES_ROOT}} -o {{PKG_PATH}}"}
|
||||
}
|
||||
|
||||
func (pg *PlanGenerator) stepPushConfiguration() {
|
||||
s := pg.stepConfiguration(stepPushConfiguration)
|
||||
s.Exec.Args = []string{"-c", "up xpkg push {{TARGET_CONFIGURATION_PACKAGE}} -f {{PKG_PATH}}"}
|
||||
}
|
|
@ -1,621 +0,0 @@
|
|||
// SPDX-FileCopyrightText: 2023 The Crossplane Authors <https://crossplane.io>
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Code generated by MockGen. DO NOT EDIT.
|
||||
// Source: github.com/crossplane/crossplane-runtime/pkg/resource (interfaces: Managed)
|
||||
|
||||
// Package mocks is a generated GoMock package.
|
||||
package mocks
|
||||
|
||||
import (
|
||||
reflect "reflect"
|
||||
|
||||
v1 "github.com/crossplane/crossplane-runtime/apis/common/v1"
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
v10 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
schema "k8s.io/apimachinery/pkg/runtime/schema"
|
||||
types "k8s.io/apimachinery/pkg/types"
|
||||
)
|
||||
|
||||
// MockManaged is a mock of Managed interface.
|
||||
type MockManaged struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockManagedMockRecorder
|
||||
}
|
||||
|
||||
// MockManagedMockRecorder is the mock recorder for MockManaged.
|
||||
type MockManagedMockRecorder struct {
|
||||
mock *MockManaged
|
||||
}
|
||||
|
||||
// NewMockManaged creates a new mock instance.
|
||||
func NewMockManaged(ctrl *gomock.Controller) *MockManaged {
|
||||
mock := &MockManaged{ctrl: ctrl}
|
||||
mock.recorder = &MockManagedMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockManaged) EXPECT() *MockManagedMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// DeepCopyObject mocks base method.
|
||||
func (m *MockManaged) DeepCopyObject() runtime.Object {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "DeepCopyObject")
|
||||
ret0, _ := ret[0].(runtime.Object)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// DeepCopyObject indicates an expected call of DeepCopyObject.
|
||||
func (mr *MockManagedMockRecorder) DeepCopyObject() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeepCopyObject", reflect.TypeOf((*MockManaged)(nil).DeepCopyObject))
|
||||
}
|
||||
|
||||
// GetAnnotations mocks base method.
|
||||
func (m *MockManaged) GetAnnotations() map[string]string {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetAnnotations")
|
||||
ret0, _ := ret[0].(map[string]string)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// GetAnnotations indicates an expected call of GetAnnotations.
|
||||
func (mr *MockManagedMockRecorder) GetAnnotations() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAnnotations", reflect.TypeOf((*MockManaged)(nil).GetAnnotations))
|
||||
}
|
||||
|
||||
// GetCondition mocks base method.
|
||||
func (m *MockManaged) GetCondition(arg0 v1.ConditionType) v1.Condition {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetCondition", arg0)
|
||||
ret0, _ := ret[0].(v1.Condition)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// GetCondition indicates an expected call of GetCondition.
|
||||
func (mr *MockManagedMockRecorder) GetCondition(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCondition", reflect.TypeOf((*MockManaged)(nil).GetCondition), arg0)
|
||||
}
|
||||
|
||||
// GetCreationTimestamp mocks base method.
|
||||
func (m *MockManaged) GetCreationTimestamp() v10.Time {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetCreationTimestamp")
|
||||
ret0, _ := ret[0].(v10.Time)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// GetCreationTimestamp indicates an expected call of GetCreationTimestamp.
|
||||
func (mr *MockManagedMockRecorder) GetCreationTimestamp() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCreationTimestamp", reflect.TypeOf((*MockManaged)(nil).GetCreationTimestamp))
|
||||
}
|
||||
|
||||
// GetDeletionGracePeriodSeconds mocks base method.
|
||||
func (m *MockManaged) GetDeletionGracePeriodSeconds() *int64 {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetDeletionGracePeriodSeconds")
|
||||
ret0, _ := ret[0].(*int64)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// GetDeletionGracePeriodSeconds indicates an expected call of GetDeletionGracePeriodSeconds.
|
||||
func (mr *MockManagedMockRecorder) GetDeletionGracePeriodSeconds() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetDeletionGracePeriodSeconds", reflect.TypeOf((*MockManaged)(nil).GetDeletionGracePeriodSeconds))
|
||||
}
|
||||
|
||||
// GetDeletionPolicy mocks base method.
|
||||
func (m *MockManaged) GetDeletionPolicy() v1.DeletionPolicy {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetDeletionPolicy")
|
||||
ret0, _ := ret[0].(v1.DeletionPolicy)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// GetDeletionPolicy indicates an expected call of GetDeletionPolicy.
|
||||
func (mr *MockManagedMockRecorder) GetDeletionPolicy() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetDeletionPolicy", reflect.TypeOf((*MockManaged)(nil).GetDeletionPolicy))
|
||||
}
|
||||
|
||||
// GetDeletionTimestamp mocks base method.
|
||||
func (m *MockManaged) GetDeletionTimestamp() *v10.Time {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetDeletionTimestamp")
|
||||
ret0, _ := ret[0].(*v10.Time)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// GetDeletionTimestamp indicates an expected call of GetDeletionTimestamp.
|
||||
func (mr *MockManagedMockRecorder) GetDeletionTimestamp() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetDeletionTimestamp", reflect.TypeOf((*MockManaged)(nil).GetDeletionTimestamp))
|
||||
}
|
||||
|
||||
// GetFinalizers mocks base method.
|
||||
func (m *MockManaged) GetFinalizers() []string {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetFinalizers")
|
||||
ret0, _ := ret[0].([]string)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// GetFinalizers indicates an expected call of GetFinalizers.
|
||||
func (mr *MockManagedMockRecorder) GetFinalizers() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetFinalizers", reflect.TypeOf((*MockManaged)(nil).GetFinalizers))
|
||||
}
|
||||
|
||||
// GetGenerateName mocks base method.
|
||||
func (m *MockManaged) GetGenerateName() string {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetGenerateName")
|
||||
ret0, _ := ret[0].(string)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// GetGenerateName indicates an expected call of GetGenerateName.
|
||||
func (mr *MockManagedMockRecorder) GetGenerateName() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetGenerateName", reflect.TypeOf((*MockManaged)(nil).GetGenerateName))
|
||||
}
|
||||
|
||||
// GetGeneration mocks base method.
|
||||
func (m *MockManaged) GetGeneration() int64 {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetGeneration")
|
||||
ret0, _ := ret[0].(int64)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// GetGeneration indicates an expected call of GetGeneration.
|
||||
func (mr *MockManagedMockRecorder) GetGeneration() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetGeneration", reflect.TypeOf((*MockManaged)(nil).GetGeneration))
|
||||
}
|
||||
|
||||
// GetLabels mocks base method.
|
||||
func (m *MockManaged) GetLabels() map[string]string {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetLabels")
|
||||
ret0, _ := ret[0].(map[string]string)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// GetLabels indicates an expected call of GetLabels.
|
||||
func (mr *MockManagedMockRecorder) GetLabels() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetLabels", reflect.TypeOf((*MockManaged)(nil).GetLabels))
|
||||
}
|
||||
|
||||
// GetManagedFields mocks base method.
|
||||
func (m *MockManaged) GetManagedFields() []v10.ManagedFieldsEntry {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetManagedFields")
|
||||
ret0, _ := ret[0].([]v10.ManagedFieldsEntry)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// GetManagedFields indicates an expected call of GetManagedFields.
|
||||
func (mr *MockManagedMockRecorder) GetManagedFields() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetManagedFields", reflect.TypeOf((*MockManaged)(nil).GetManagedFields))
|
||||
}
|
||||
|
||||
// GetManagementPolicies mocks base method.
|
||||
func (m *MockManaged) GetManagementPolicies() v1.ManagementPolicies {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetManagementPolicies")
|
||||
ret0, _ := ret[0].(v1.ManagementPolicies)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// GetManagementPolicies indicates an expected call of GetManagementPolicies.
|
||||
func (mr *MockManagedMockRecorder) GetManagementPolicies() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetManagementPolicies", reflect.TypeOf((*MockManaged)(nil).GetManagementPolicies))
|
||||
}
|
||||
|
||||
// GetName mocks base method.
|
||||
func (m *MockManaged) GetName() string {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetName")
|
||||
ret0, _ := ret[0].(string)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// GetName indicates an expected call of GetName.
|
||||
func (mr *MockManagedMockRecorder) GetName() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetName", reflect.TypeOf((*MockManaged)(nil).GetName))
|
||||
}
|
||||
|
||||
// GetNamespace mocks base method.
|
||||
func (m *MockManaged) GetNamespace() string {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetNamespace")
|
||||
ret0, _ := ret[0].(string)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// GetNamespace indicates an expected call of GetNamespace.
|
||||
func (mr *MockManagedMockRecorder) GetNamespace() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetNamespace", reflect.TypeOf((*MockManaged)(nil).GetNamespace))
|
||||
}
|
||||
|
||||
// GetObjectKind mocks base method.
|
||||
func (m *MockManaged) GetObjectKind() schema.ObjectKind {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetObjectKind")
|
||||
ret0, _ := ret[0].(schema.ObjectKind)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// GetObjectKind indicates an expected call of GetObjectKind.
|
||||
func (mr *MockManagedMockRecorder) GetObjectKind() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetObjectKind", reflect.TypeOf((*MockManaged)(nil).GetObjectKind))
|
||||
}
|
||||
|
||||
// GetOwnerReferences mocks base method.
|
||||
func (m *MockManaged) GetOwnerReferences() []v10.OwnerReference {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetOwnerReferences")
|
||||
ret0, _ := ret[0].([]v10.OwnerReference)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// GetOwnerReferences indicates an expected call of GetOwnerReferences.
|
||||
func (mr *MockManagedMockRecorder) GetOwnerReferences() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetOwnerReferences", reflect.TypeOf((*MockManaged)(nil).GetOwnerReferences))
|
||||
}
|
||||
|
||||
// GetProviderConfigReference mocks base method.
|
||||
func (m *MockManaged) GetProviderConfigReference() *v1.Reference {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetProviderConfigReference")
|
||||
ret0, _ := ret[0].(*v1.Reference)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// GetProviderConfigReference indicates an expected call of GetProviderConfigReference.
|
||||
func (mr *MockManagedMockRecorder) GetProviderConfigReference() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetProviderConfigReference", reflect.TypeOf((*MockManaged)(nil).GetProviderConfigReference))
|
||||
}
|
||||
|
||||
// GetPublishConnectionDetailsTo mocks base method.
|
||||
func (m *MockManaged) GetPublishConnectionDetailsTo() *v1.PublishConnectionDetailsTo {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetPublishConnectionDetailsTo")
|
||||
ret0, _ := ret[0].(*v1.PublishConnectionDetailsTo)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// GetPublishConnectionDetailsTo indicates an expected call of GetPublishConnectionDetailsTo.
|
||||
func (mr *MockManagedMockRecorder) GetPublishConnectionDetailsTo() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPublishConnectionDetailsTo", reflect.TypeOf((*MockManaged)(nil).GetPublishConnectionDetailsTo))
|
||||
}
|
||||
|
||||
// GetResourceVersion mocks base method.
|
||||
func (m *MockManaged) GetResourceVersion() string {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetResourceVersion")
|
||||
ret0, _ := ret[0].(string)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// GetResourceVersion indicates an expected call of GetResourceVersion.
|
||||
func (mr *MockManagedMockRecorder) GetResourceVersion() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetResourceVersion", reflect.TypeOf((*MockManaged)(nil).GetResourceVersion))
|
||||
}
|
||||
|
||||
// GetSelfLink mocks base method.
|
||||
func (m *MockManaged) GetSelfLink() string {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetSelfLink")
|
||||
ret0, _ := ret[0].(string)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// GetSelfLink indicates an expected call of GetSelfLink.
|
||||
func (mr *MockManagedMockRecorder) GetSelfLink() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSelfLink", reflect.TypeOf((*MockManaged)(nil).GetSelfLink))
|
||||
}
|
||||
|
||||
// GetUID mocks base method.
|
||||
func (m *MockManaged) GetUID() types.UID {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetUID")
|
||||
ret0, _ := ret[0].(types.UID)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// GetUID indicates an expected call of GetUID.
|
||||
func (mr *MockManagedMockRecorder) GetUID() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUID", reflect.TypeOf((*MockManaged)(nil).GetUID))
|
||||
}
|
||||
|
||||
// GetWriteConnectionSecretToReference mocks base method.
|
||||
func (m *MockManaged) GetWriteConnectionSecretToReference() *v1.SecretReference {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetWriteConnectionSecretToReference")
|
||||
ret0, _ := ret[0].(*v1.SecretReference)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// GetWriteConnectionSecretToReference indicates an expected call of GetWriteConnectionSecretToReference.
|
||||
func (mr *MockManagedMockRecorder) GetWriteConnectionSecretToReference() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetWriteConnectionSecretToReference", reflect.TypeOf((*MockManaged)(nil).GetWriteConnectionSecretToReference))
|
||||
}
|
||||
|
||||
// SetAnnotations mocks base method.
|
||||
func (m *MockManaged) SetAnnotations(arg0 map[string]string) {
|
||||
m.ctrl.T.Helper()
|
||||
m.ctrl.Call(m, "SetAnnotations", arg0)
|
||||
}
|
||||
|
||||
// SetAnnotations indicates an expected call of SetAnnotations.
|
||||
func (mr *MockManagedMockRecorder) SetAnnotations(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetAnnotations", reflect.TypeOf((*MockManaged)(nil).SetAnnotations), arg0)
|
||||
}
|
||||
|
||||
// SetConditions mocks base method.
|
||||
func (m *MockManaged) SetConditions(arg0 ...v1.Condition) {
|
||||
m.ctrl.T.Helper()
|
||||
varargs := []interface{}{}
|
||||
for _, a := range arg0 {
|
||||
varargs = append(varargs, a)
|
||||
}
|
||||
m.ctrl.Call(m, "SetConditions", varargs...)
|
||||
}
|
||||
|
||||
// SetConditions indicates an expected call of SetConditions.
|
||||
func (mr *MockManagedMockRecorder) SetConditions(arg0 ...interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetConditions", reflect.TypeOf((*MockManaged)(nil).SetConditions), arg0...)
|
||||
}
|
||||
|
||||
// SetCreationTimestamp mocks base method.
|
||||
func (m *MockManaged) SetCreationTimestamp(arg0 v10.Time) {
|
||||
m.ctrl.T.Helper()
|
||||
m.ctrl.Call(m, "SetCreationTimestamp", arg0)
|
||||
}
|
||||
|
||||
// SetCreationTimestamp indicates an expected call of SetCreationTimestamp.
|
||||
func (mr *MockManagedMockRecorder) SetCreationTimestamp(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetCreationTimestamp", reflect.TypeOf((*MockManaged)(nil).SetCreationTimestamp), arg0)
|
||||
}
|
||||
|
||||
// SetDeletionGracePeriodSeconds mocks base method.
|
||||
func (m *MockManaged) SetDeletionGracePeriodSeconds(arg0 *int64) {
|
||||
m.ctrl.T.Helper()
|
||||
m.ctrl.Call(m, "SetDeletionGracePeriodSeconds", arg0)
|
||||
}
|
||||
|
||||
// SetDeletionGracePeriodSeconds indicates an expected call of SetDeletionGracePeriodSeconds.
|
||||
func (mr *MockManagedMockRecorder) SetDeletionGracePeriodSeconds(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetDeletionGracePeriodSeconds", reflect.TypeOf((*MockManaged)(nil).SetDeletionGracePeriodSeconds), arg0)
|
||||
}
|
||||
|
||||
// SetDeletionPolicy mocks base method.
|
||||
func (m *MockManaged) SetDeletionPolicy(arg0 v1.DeletionPolicy) {
|
||||
m.ctrl.T.Helper()
|
||||
m.ctrl.Call(m, "SetDeletionPolicy", arg0)
|
||||
}
|
||||
|
||||
// SetDeletionPolicy indicates an expected call of SetDeletionPolicy.
|
||||
func (mr *MockManagedMockRecorder) SetDeletionPolicy(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetDeletionPolicy", reflect.TypeOf((*MockManaged)(nil).SetDeletionPolicy), arg0)
|
||||
}
|
||||
|
||||
// SetDeletionTimestamp mocks base method.
|
||||
func (m *MockManaged) SetDeletionTimestamp(arg0 *v10.Time) {
|
||||
m.ctrl.T.Helper()
|
||||
m.ctrl.Call(m, "SetDeletionTimestamp", arg0)
|
||||
}
|
||||
|
||||
// SetDeletionTimestamp indicates an expected call of SetDeletionTimestamp.
|
||||
func (mr *MockManagedMockRecorder) SetDeletionTimestamp(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetDeletionTimestamp", reflect.TypeOf((*MockManaged)(nil).SetDeletionTimestamp), arg0)
|
||||
}
|
||||
|
||||
// SetFinalizers mocks base method.
|
||||
func (m *MockManaged) SetFinalizers(arg0 []string) {
|
||||
m.ctrl.T.Helper()
|
||||
m.ctrl.Call(m, "SetFinalizers", arg0)
|
||||
}
|
||||
|
||||
// SetFinalizers indicates an expected call of SetFinalizers.
|
||||
func (mr *MockManagedMockRecorder) SetFinalizers(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetFinalizers", reflect.TypeOf((*MockManaged)(nil).SetFinalizers), arg0)
|
||||
}
|
||||
|
||||
// SetGenerateName mocks base method.
|
||||
func (m *MockManaged) SetGenerateName(arg0 string) {
|
||||
m.ctrl.T.Helper()
|
||||
m.ctrl.Call(m, "SetGenerateName", arg0)
|
||||
}
|
||||
|
||||
// SetGenerateName indicates an expected call of SetGenerateName.
|
||||
func (mr *MockManagedMockRecorder) SetGenerateName(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetGenerateName", reflect.TypeOf((*MockManaged)(nil).SetGenerateName), arg0)
|
||||
}
|
||||
|
||||
// SetGeneration mocks base method.
|
||||
func (m *MockManaged) SetGeneration(arg0 int64) {
|
||||
m.ctrl.T.Helper()
|
||||
m.ctrl.Call(m, "SetGeneration", arg0)
|
||||
}
|
||||
|
||||
// SetGeneration indicates an expected call of SetGeneration.
|
||||
func (mr *MockManagedMockRecorder) SetGeneration(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetGeneration", reflect.TypeOf((*MockManaged)(nil).SetGeneration), arg0)
|
||||
}
|
||||
|
||||
// SetLabels mocks base method.
|
||||
func (m *MockManaged) SetLabels(arg0 map[string]string) {
|
||||
m.ctrl.T.Helper()
|
||||
m.ctrl.Call(m, "SetLabels", arg0)
|
||||
}
|
||||
|
||||
// SetLabels indicates an expected call of SetLabels.
|
||||
func (mr *MockManagedMockRecorder) SetLabels(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetLabels", reflect.TypeOf((*MockManaged)(nil).SetLabels), arg0)
|
||||
}
|
||||
|
||||
// SetManagedFields mocks base method.
|
||||
func (m *MockManaged) SetManagedFields(arg0 []v10.ManagedFieldsEntry) {
|
||||
m.ctrl.T.Helper()
|
||||
m.ctrl.Call(m, "SetManagedFields", arg0)
|
||||
}
|
||||
|
||||
// SetManagedFields indicates an expected call of SetManagedFields.
|
||||
func (mr *MockManagedMockRecorder) SetManagedFields(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetManagedFields", reflect.TypeOf((*MockManaged)(nil).SetManagedFields), arg0)
|
||||
}
|
||||
|
||||
// SetManagementPolicies mocks base method.
|
||||
func (m *MockManaged) SetManagementPolicies(arg0 v1.ManagementPolicies) {
|
||||
m.ctrl.T.Helper()
|
||||
m.ctrl.Call(m, "SetManagementPolicies", arg0)
|
||||
}
|
||||
|
||||
// SetManagementPolicies indicates an expected call of SetManagementPolicies.
|
||||
func (mr *MockManagedMockRecorder) SetManagementPolicies(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetManagementPolicies", reflect.TypeOf((*MockManaged)(nil).SetManagementPolicies), arg0)
|
||||
}
|
||||
|
||||
// SetName mocks base method.
|
||||
func (m *MockManaged) SetName(arg0 string) {
|
||||
m.ctrl.T.Helper()
|
||||
m.ctrl.Call(m, "SetName", arg0)
|
||||
}
|
||||
|
||||
// SetName indicates an expected call of SetName.
|
||||
func (mr *MockManagedMockRecorder) SetName(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetName", reflect.TypeOf((*MockManaged)(nil).SetName), arg0)
|
||||
}
|
||||
|
||||
// SetNamespace mocks base method.
|
||||
func (m *MockManaged) SetNamespace(arg0 string) {
|
||||
m.ctrl.T.Helper()
|
||||
m.ctrl.Call(m, "SetNamespace", arg0)
|
||||
}
|
||||
|
||||
// SetNamespace indicates an expected call of SetNamespace.
|
||||
func (mr *MockManagedMockRecorder) SetNamespace(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetNamespace", reflect.TypeOf((*MockManaged)(nil).SetNamespace), arg0)
|
||||
}
|
||||
|
||||
// SetOwnerReferences mocks base method.
|
||||
func (m *MockManaged) SetOwnerReferences(arg0 []v10.OwnerReference) {
|
||||
m.ctrl.T.Helper()
|
||||
m.ctrl.Call(m, "SetOwnerReferences", arg0)
|
||||
}
|
||||
|
||||
// SetOwnerReferences indicates an expected call of SetOwnerReferences.
|
||||
func (mr *MockManagedMockRecorder) SetOwnerReferences(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetOwnerReferences", reflect.TypeOf((*MockManaged)(nil).SetOwnerReferences), arg0)
|
||||
}
|
||||
|
||||
// SetProviderConfigReference mocks base method.
|
||||
func (m *MockManaged) SetProviderConfigReference(arg0 *v1.Reference) {
|
||||
m.ctrl.T.Helper()
|
||||
m.ctrl.Call(m, "SetProviderConfigReference", arg0)
|
||||
}
|
||||
|
||||
// SetProviderConfigReference indicates an expected call of SetProviderConfigReference.
|
||||
func (mr *MockManagedMockRecorder) SetProviderConfigReference(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetProviderConfigReference", reflect.TypeOf((*MockManaged)(nil).SetProviderConfigReference), arg0)
|
||||
}
|
||||
|
||||
// SetPublishConnectionDetailsTo mocks base method.
|
||||
func (m *MockManaged) SetPublishConnectionDetailsTo(arg0 *v1.PublishConnectionDetailsTo) {
|
||||
m.ctrl.T.Helper()
|
||||
m.ctrl.Call(m, "SetPublishConnectionDetailsTo", arg0)
|
||||
}
|
||||
|
||||
// SetPublishConnectionDetailsTo indicates an expected call of SetPublishConnectionDetailsTo.
|
||||
func (mr *MockManagedMockRecorder) SetPublishConnectionDetailsTo(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetPublishConnectionDetailsTo", reflect.TypeOf((*MockManaged)(nil).SetPublishConnectionDetailsTo), arg0)
|
||||
}
|
||||
|
||||
// SetResourceVersion mocks base method.
|
||||
func (m *MockManaged) SetResourceVersion(arg0 string) {
|
||||
m.ctrl.T.Helper()
|
||||
m.ctrl.Call(m, "SetResourceVersion", arg0)
|
||||
}
|
||||
|
||||
// SetResourceVersion indicates an expected call of SetResourceVersion.
|
||||
func (mr *MockManagedMockRecorder) SetResourceVersion(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetResourceVersion", reflect.TypeOf((*MockManaged)(nil).SetResourceVersion), arg0)
|
||||
}
|
||||
|
||||
// SetSelfLink mocks base method.
|
||||
func (m *MockManaged) SetSelfLink(arg0 string) {
|
||||
m.ctrl.T.Helper()
|
||||
m.ctrl.Call(m, "SetSelfLink", arg0)
|
||||
}
|
||||
|
||||
// SetSelfLink indicates an expected call of SetSelfLink.
|
||||
func (mr *MockManagedMockRecorder) SetSelfLink(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetSelfLink", reflect.TypeOf((*MockManaged)(nil).SetSelfLink), arg0)
|
||||
}
|
||||
|
||||
// SetUID mocks base method.
|
||||
func (m *MockManaged) SetUID(arg0 types.UID) {
|
||||
m.ctrl.T.Helper()
|
||||
m.ctrl.Call(m, "SetUID", arg0)
|
||||
}
|
||||
|
||||
// SetUID indicates an expected call of SetUID.
|
||||
func (mr *MockManagedMockRecorder) SetUID(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetUID", reflect.TypeOf((*MockManaged)(nil).SetUID), arg0)
|
||||
}
|
||||
|
||||
// SetWriteConnectionSecretToReference mocks base method.
|
||||
func (m *MockManaged) SetWriteConnectionSecretToReference(arg0 *v1.SecretReference) {
|
||||
m.ctrl.T.Helper()
|
||||
m.ctrl.Call(m, "SetWriteConnectionSecretToReference", arg0)
|
||||
}
|
||||
|
||||
// SetWriteConnectionSecretToReference indicates an expected call of SetWriteConnectionSecretToReference.
|
||||
func (mr *MockManagedMockRecorder) SetWriteConnectionSecretToReference(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetWriteConnectionSecretToReference", reflect.TypeOf((*MockManaged)(nil).SetWriteConnectionSecretToReference), arg0)
|
||||
}
|
|
@ -1,130 +0,0 @@
|
|||
// SPDX-FileCopyrightText: 2023 The Crossplane Authors <https://crossplane.io>
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
//go:generate go run github.com/golang/mock/mockgen -copyright_file ../../../hack/boilerplate.txt -destination=./mocks/mock.go -package mocks github.com/crossplane/crossplane-runtime/pkg/resource Managed
|
||||
|
||||
package fake
|
||||
|
||||
import (
|
||||
xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
|
||||
"github.com/crossplane/upjet/pkg/migration/fake/mocks"
|
||||
)
|
||||
|
||||
const (
|
||||
MigrationSourceGroup = "fakesourceapi"
|
||||
MigrationSourceVersion = "v1alpha1"
|
||||
MigrationSourceKind = "VPC"
|
||||
|
||||
MigrationTargetGroup = "faketargetapi"
|
||||
MigrationTargetVersion = "v1alpha1"
|
||||
MigrationTargetKind = "VPC"
|
||||
)
|
||||
|
||||
var (
|
||||
MigrationSourceGVK = schema.GroupVersionKind{
|
||||
Group: MigrationSourceGroup,
|
||||
Version: MigrationSourceVersion,
|
||||
Kind: MigrationSourceKind,
|
||||
}
|
||||
|
||||
MigrationTargetGVK = schema.GroupVersionKind{
|
||||
Group: MigrationTargetGroup,
|
||||
Version: MigrationTargetVersion,
|
||||
Kind: MigrationTargetKind,
|
||||
}
|
||||
)
|
||||
|
||||
type MigrationSourceObject struct {
|
||||
mocks.MockManaged
|
||||
// cannot inline v1.TypeMeta here as mocks.MockManaged is also inlined
|
||||
APIVersion string `json:"apiVersion,omitempty"`
|
||||
Kind string `json:"kind,omitempty"`
|
||||
// cannot inline v1.ObjectMeta here as mocks.MockManaged is also inlined
|
||||
ObjectMeta ObjectMeta `json:"metadata,omitempty"`
|
||||
Spec SourceSpec `json:"spec"`
|
||||
Status Status `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
type SourceSpec struct {
|
||||
xpv1.ResourceSpec `json:",inline"`
|
||||
ForProvider SourceSpecParameters `json:"forProvider"`
|
||||
}
|
||||
|
||||
type EmbeddedParameter struct {
|
||||
Param *string `json:"param,omitempty"`
|
||||
}
|
||||
|
||||
type SourceSpecParameters struct {
|
||||
Region *string `json:"region,omitempty"`
|
||||
CIDRBlock string `json:"cidrBlock"`
|
||||
Tags []Tag `json:"tags,omitempty"`
|
||||
TestParam *EmbeddedParameter `json:",inline"`
|
||||
}
|
||||
|
||||
type Tag struct {
|
||||
Key string `json:"key"`
|
||||
Value string `json:"value"`
|
||||
}
|
||||
|
||||
type Status struct {
|
||||
xpv1.ResourceStatus `json:",inline"`
|
||||
AtProvider Observation `json:"atProvider,omitempty"`
|
||||
}
|
||||
|
||||
type Observation struct{}
|
||||
|
||||
func (m *MigrationSourceObject) GetName() string {
|
||||
return m.ObjectMeta.Name
|
||||
}
|
||||
|
||||
type MigrationTargetObject struct {
|
||||
mocks.MockManaged
|
||||
// cannot inline v1.TypeMeta here as mocks.MockManaged is also inlined
|
||||
APIVersion string `json:"apiVersion,omitempty"`
|
||||
Kind string `json:"kind,omitempty"`
|
||||
// cannot inline v1.ObjectMeta here as mocks.MockManaged is also inlined
|
||||
ObjectMeta ObjectMeta `json:"metadata,omitempty"`
|
||||
Spec TargetSpec `json:"spec"`
|
||||
Status Status `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
type ObjectMeta struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
GenerateName string `json:"generateName,omitempty"`
|
||||
Labels map[string]string `json:"labels,omitempty"`
|
||||
}
|
||||
|
||||
type TargetSpec struct {
|
||||
xpv1.ResourceSpec `json:",inline"`
|
||||
ForProvider TargetSpecParameters `json:"forProvider"`
|
||||
}
|
||||
|
||||
type TargetSpecParameters struct {
|
||||
Region *string `json:"region,omitempty"`
|
||||
CIDRBlock string `json:"cidrBlock"`
|
||||
Tags map[string]string `json:"tags,omitempty"`
|
||||
TestParam EmbeddedParameter `json:",inline"`
|
||||
}
|
||||
|
||||
type targetObjectKind struct{}
|
||||
|
||||
func (t *targetObjectKind) SetGroupVersionKind(_ schema.GroupVersionKind) {}
|
||||
|
||||
func (t *targetObjectKind) GroupVersionKind() schema.GroupVersionKind {
|
||||
return MigrationTargetGVK
|
||||
}
|
||||
|
||||
func (m *MigrationTargetObject) GetObjectKind() schema.ObjectKind {
|
||||
return &targetObjectKind{}
|
||||
}
|
||||
|
||||
func (m *MigrationTargetObject) GetName() string {
|
||||
return m.ObjectMeta.Name
|
||||
}
|
||||
|
||||
func (m *MigrationTargetObject) GetGenerateName() string {
|
||||
return m.ObjectMeta.GenerateName
|
||||
}
|
|
@ -1,178 +0,0 @@
|
|||
// SPDX-FileCopyrightText: 2023 The Crossplane Authors <https://crossplane.io>
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package migration
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/afero"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/util/yaml"
|
||||
sigsyaml "sigs.k8s.io/yaml"
|
||||
)
|
||||
|
||||
var (
|
||||
_ Source = &FileSystemSource{}
|
||||
_ Target = &FileSystemTarget{}
|
||||
)
|
||||
|
||||
// FileSystemSource is a source implementation to read resources from filesystem
|
||||
type FileSystemSource struct {
|
||||
index int
|
||||
items []UnstructuredWithMetadata
|
||||
afero afero.Afero
|
||||
}
|
||||
|
||||
// FileSystemSourceOption allows you to configure FileSystemSource
|
||||
type FileSystemSourceOption func(*FileSystemSource)
|
||||
|
||||
// FsWithFileSystem configures the filesystem to use. Used mostly for testing.
|
||||
func FsWithFileSystem(f afero.Fs) FileSystemSourceOption {
|
||||
return func(fs *FileSystemSource) {
|
||||
fs.afero = afero.Afero{Fs: f}
|
||||
}
|
||||
}
|
||||
|
||||
// NewFileSystemSource returns a FileSystemSource
|
||||
func NewFileSystemSource(dir string, opts ...FileSystemSourceOption) (*FileSystemSource, error) {
|
||||
fs := &FileSystemSource{
|
||||
afero: afero.Afero{Fs: afero.NewOsFs()},
|
||||
}
|
||||
for _, f := range opts {
|
||||
f(fs)
|
||||
}
|
||||
|
||||
if err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return errors.Wrap(err, fmt.Sprintf("cannot read %s", path))
|
||||
}
|
||||
|
||||
if info.IsDir() {
|
||||
return nil
|
||||
}
|
||||
|
||||
data, err := fs.afero.ReadFile(path)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "cannot read source file")
|
||||
}
|
||||
|
||||
decoder := yaml.NewYAMLOrJSONDecoder(bytes.NewBufferString(string(data)), 1024)
|
||||
u := &unstructured.Unstructured{}
|
||||
if err := decoder.Decode(&u); err != nil {
|
||||
return errors.Wrap(err, "cannot decode read data")
|
||||
}
|
||||
|
||||
fs.items = append(fs.items, UnstructuredWithMetadata{
|
||||
Object: *u,
|
||||
Metadata: Metadata{
|
||||
Path: path,
|
||||
Category: getCategory(*u),
|
||||
},
|
||||
})
|
||||
|
||||
return nil
|
||||
}); err != nil {
|
||||
return nil, errors.Wrap(err, "cannot read source directory")
|
||||
}
|
||||
|
||||
return fs, nil
|
||||
}
|
||||
|
||||
// HasNext checks the next item
|
||||
func (fs *FileSystemSource) HasNext() (bool, error) {
|
||||
return fs.index < len(fs.items), nil
|
||||
}
|
||||
|
||||
// Next returns the next item of slice
|
||||
func (fs *FileSystemSource) Next() (UnstructuredWithMetadata, error) {
|
||||
if hasNext, _ := fs.HasNext(); hasNext {
|
||||
item := fs.items[fs.index]
|
||||
fs.index++
|
||||
return item, nil
|
||||
}
|
||||
return UnstructuredWithMetadata{}, errors.New("no more elements")
|
||||
}
|
||||
|
||||
// Reset resets the source so that resources can be reread from the beginning.
|
||||
func (fs *FileSystemSource) Reset() error {
|
||||
fs.index = 0
|
||||
return nil
|
||||
}
|
||||
|
||||
// FileSystemTarget is a target implementation to write/patch/delete resources to file system
|
||||
type FileSystemTarget struct {
|
||||
afero afero.Afero
|
||||
parent string
|
||||
}
|
||||
|
||||
// FileSystemTargetOption allows you to configure FileSystemTarget
|
||||
type FileSystemTargetOption func(*FileSystemTarget)
|
||||
|
||||
// FtWithFileSystem configures the filesystem to use. Used mostly for testing.
|
||||
func FtWithFileSystem(f afero.Fs) FileSystemTargetOption {
|
||||
return func(ft *FileSystemTarget) {
|
||||
ft.afero = afero.Afero{Fs: f}
|
||||
}
|
||||
}
|
||||
|
||||
// WithParentDirectory configures the parent directory for the FileSystemTarget
|
||||
func WithParentDirectory(parent string) FileSystemTargetOption {
|
||||
return func(ft *FileSystemTarget) {
|
||||
ft.parent = parent
|
||||
}
|
||||
}
|
||||
|
||||
// NewFileSystemTarget returns a FileSystemTarget
|
||||
func NewFileSystemTarget(opts ...FileSystemTargetOption) *FileSystemTarget {
|
||||
ft := &FileSystemTarget{
|
||||
afero: afero.Afero{Fs: afero.NewOsFs()},
|
||||
}
|
||||
for _, f := range opts {
|
||||
f(ft)
|
||||
}
|
||||
return ft
|
||||
}
|
||||
|
||||
// Put writes input to filesystem
|
||||
func (ft *FileSystemTarget) Put(o UnstructuredWithMetadata) error {
|
||||
b, err := sigsyaml.Marshal(o.Object.Object)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "cannot marshal object")
|
||||
}
|
||||
if err := os.MkdirAll(filepath.Join(ft.parent, filepath.Dir(o.Metadata.Path)), 0o750); err != nil {
|
||||
return errors.Wrapf(err, "cannot mkdirall: %s", filepath.Dir(o.Metadata.Path))
|
||||
}
|
||||
if o.Metadata.Parents != "" {
|
||||
f, err := ft.afero.OpenFile(filepath.Join(ft.parent, o.Metadata.Path), os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "cannot open file")
|
||||
}
|
||||
|
||||
defer f.Close() //nolint:errcheck
|
||||
|
||||
if _, err = fmt.Fprintf(f, "\n---\n\n%s", string(b)); err != nil {
|
||||
return errors.Wrap(err, "cannot write file")
|
||||
}
|
||||
} else {
|
||||
f, err := ft.afero.Create(filepath.Join(ft.parent, o.Metadata.Path))
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "cannot create file")
|
||||
}
|
||||
if _, err := f.Write(b); err != nil {
|
||||
return errors.Wrap(err, "cannot write file")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Delete deletes a file from filesystem
|
||||
func (ft *FileSystemTarget) Delete(o UnstructuredWithMetadata) error {
|
||||
return ft.afero.Remove(o.Metadata.Path)
|
||||
}
|
|
@ -1,260 +0,0 @@
|
|||
// SPDX-FileCopyrightText: 2023 The Crossplane Authors <https://crossplane.io>
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package migration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/afero"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
)
|
||||
|
||||
var (
|
||||
unstructuredAwsVpc = map[string]interface{}{
|
||||
"apiVersion": "ec2.aws.crossplane.io/v1beta1",
|
||||
"kind": "VPC",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "sample-vpc",
|
||||
},
|
||||
"spec": map[string]interface{}{
|
||||
"forProvider": map[string]interface{}{
|
||||
"region": "us-west-1",
|
||||
"cidrBlock": "172.16.0.0/16",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
unstructuredResourceGroup = map[string]interface{}{
|
||||
"apiVersion": "azure.crossplane.io/v1beta1",
|
||||
"kind": "ResourceGroup",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "example-resources",
|
||||
},
|
||||
"spec": map[string]interface{}{
|
||||
"forProvider": map[string]interface{}{
|
||||
"location": "West Europe",
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
func TestNewFileSystemSource(t *testing.T) {
|
||||
type args struct {
|
||||
dir string
|
||||
a func() afero.Afero
|
||||
}
|
||||
type want struct {
|
||||
fs *FileSystemSource
|
||||
err error
|
||||
}
|
||||
|
||||
cases := map[string]struct {
|
||||
args
|
||||
want
|
||||
}{
|
||||
"Successful": {
|
||||
args: args{
|
||||
dir: "testdata",
|
||||
a: func() afero.Afero {
|
||||
fss := afero.Afero{Fs: afero.NewMemMapFs()}
|
||||
_ = fss.WriteFile("testdata/source/awsvpc.yaml",
|
||||
[]byte("apiVersion: ec2.aws.crossplane.io/v1beta1\nkind: VPC\nmetadata:\n name: sample-vpc\nspec:\n forProvider:\n cidrBlock: 172.16.0.0/16\n region: us-west-1\n"),
|
||||
0600)
|
||||
_ = fss.WriteFile("testdata/source/resourcegroup.yaml",
|
||||
[]byte("apiVersion: azure.crossplane.io/v1beta1\nkind: ResourceGroup\nmetadata:\n name: example-resources\nspec:\n forProvider:\n location: West Europe\n"),
|
||||
0600)
|
||||
return fss
|
||||
},
|
||||
},
|
||||
want: want{
|
||||
fs: &FileSystemSource{
|
||||
index: 0,
|
||||
items: []UnstructuredWithMetadata{
|
||||
{
|
||||
Object: unstructured.Unstructured{
|
||||
Object: unstructuredAwsVpc,
|
||||
},
|
||||
Metadata: Metadata{
|
||||
Path: "testdata/source/awsvpc.yaml",
|
||||
},
|
||||
},
|
||||
{
|
||||
Object: unstructured.Unstructured{
|
||||
Object: unstructuredResourceGroup,
|
||||
},
|
||||
Metadata: Metadata{
|
||||
Path: "testdata/source/resourcegroup.yaml",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for name, tc := range cases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
files := tc.args.a()
|
||||
fs, err := NewFileSystemSource("testdata/source", FsWithFileSystem(files))
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to initialize a new FileSystemSource: %v", err)
|
||||
}
|
||||
if diff := cmp.Diff(tc.want.err, err); diff != "" {
|
||||
t.Errorf("\nNext(...): -want, +got:\n%s", diff)
|
||||
}
|
||||
if diff := cmp.Diff(tc.want.fs.items, fs.items); diff != "" {
|
||||
t.Errorf("\nNext(...): -want, +got:\n%s", diff)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestFileSystemTarget_Put(t *testing.T) {
|
||||
type args struct {
|
||||
o UnstructuredWithMetadata
|
||||
a func() afero.Afero
|
||||
}
|
||||
type want struct {
|
||||
data string
|
||||
err error
|
||||
}
|
||||
|
||||
cases := map[string]struct {
|
||||
args
|
||||
want
|
||||
}{
|
||||
"Write": {
|
||||
args: args{
|
||||
o: UnstructuredWithMetadata{
|
||||
Object: unstructured.Unstructured{
|
||||
Object: map[string]interface{}{
|
||||
"apiVersion": "ec2.aws.upbound.io/v1beta1",
|
||||
"kind": "VPC",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "sample-vpc",
|
||||
},
|
||||
"spec": map[string]interface{}{
|
||||
"forProvider": map[string]interface{}{
|
||||
"region": "us-west-1",
|
||||
"cidrBlock": "172.16.0.0/16",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Metadata: Metadata{
|
||||
Path: "testdata/source/awsvpc.yaml",
|
||||
},
|
||||
},
|
||||
a: func() afero.Afero {
|
||||
return afero.Afero{Fs: afero.NewMemMapFs()}
|
||||
},
|
||||
},
|
||||
want: want{
|
||||
data: "apiVersion: ec2.aws.upbound.io/v1beta1\nkind: VPC\nmetadata:\n name: sample-vpc\nspec:\n forProvider:\n cidrBlock: 172.16.0.0/16\n region: us-west-1\n",
|
||||
err: nil,
|
||||
},
|
||||
},
|
||||
"Append": {
|
||||
args: args{
|
||||
o: UnstructuredWithMetadata{
|
||||
Object: unstructured.Unstructured{
|
||||
Object: map[string]interface{}{
|
||||
"apiVersion": "azure.crossplane.io/v1beta1",
|
||||
"kind": "ResourceGroup",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "example-resources",
|
||||
},
|
||||
"spec": map[string]interface{}{
|
||||
"forProvider": map[string]interface{}{
|
||||
"location": "West Europe",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Metadata: Metadata{
|
||||
Path: "testdata/source/awsvpc.yaml",
|
||||
Parents: "parent metadata",
|
||||
},
|
||||
},
|
||||
a: func() afero.Afero {
|
||||
fss := afero.Afero{Fs: afero.NewMemMapFs()}
|
||||
_ = fss.WriteFile("testdata/source/awsvpc.yaml",
|
||||
[]byte("apiVersion: ec2.aws.upbound.io/v1beta1\nkind: VPC\nmetadata:\n name: sample-vpc\nspec:\n forProvider:\n cidrBlock: 172.16.0.0/16\n region: us-west-1\n"),
|
||||
0600)
|
||||
return fss
|
||||
},
|
||||
},
|
||||
want: want{
|
||||
data: "apiVersion: ec2.aws.upbound.io/v1beta1\nkind: VPC\nmetadata:\n name: sample-vpc\nspec:\n forProvider:\n cidrBlock: 172.16.0.0/16\n region: us-west-1\n\n---\n\napiVersion: azure.crossplane.io/v1beta1\nkind: ResourceGroup\nmetadata:\n name: example-resources\nspec:\n forProvider:\n location: West Europe\n",
|
||||
err: nil,
|
||||
},
|
||||
},
|
||||
}
|
||||
for name, tc := range cases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
files := tc.args.a()
|
||||
ft := NewFileSystemTarget(FtWithFileSystem(files))
|
||||
if err := ft.Put(tc.args.o); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
b, err := ft.afero.ReadFile("testdata/source/awsvpc.yaml")
|
||||
if diff := cmp.Diff(tc.want.err, err); diff != "" {
|
||||
t.Errorf("\nNext(...): -want, +got:\n%s", diff)
|
||||
}
|
||||
if diff := cmp.Diff(tc.want.data, string(b)); diff != "" {
|
||||
t.Errorf("\nNext(...): -want, +got:\n%s", diff)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestFileSystemTarget_Delete(t *testing.T) {
|
||||
type args struct {
|
||||
o UnstructuredWithMetadata
|
||||
a func() afero.Afero
|
||||
}
|
||||
type want struct {
|
||||
err error
|
||||
}
|
||||
cases := map[string]struct {
|
||||
args
|
||||
want
|
||||
}{
|
||||
"Successful": {
|
||||
args: args{
|
||||
o: UnstructuredWithMetadata{
|
||||
Metadata: Metadata{
|
||||
Path: "testdata/source/awsvpc.yaml",
|
||||
},
|
||||
},
|
||||
a: func() afero.Afero {
|
||||
fss := afero.Afero{Fs: afero.NewMemMapFs()}
|
||||
_ = fss.WriteFile("testdata/source/awsvpc.yaml",
|
||||
[]byte("apiVersion: ec2.aws.upbound.io/v1beta1\nkind: VPC\nmetadata:\n name: sample-vpc\nspec:\n forProvider:\n cidrBlock: 172.16.0.0/16\n region: us-west-1\n"),
|
||||
0600)
|
||||
return fss
|
||||
},
|
||||
},
|
||||
want: want{
|
||||
err: errors.New(fmt.Sprintf("%s: %s", "open testdata/source/awsvpc.yaml", afero.ErrFileNotFound)),
|
||||
},
|
||||
},
|
||||
}
|
||||
for name, tc := range cases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
files := tc.args.a()
|
||||
ft := NewFileSystemTarget(FtWithFileSystem(files))
|
||||
if err := ft.Delete(tc.args.o); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
_, err := ft.afero.ReadFile("testdata/source/awsvpc.yaml")
|
||||
if diff := cmp.Diff(tc.want.err.Error(), err.Error()); diff != "" {
|
||||
t.Errorf("\nNext(...): -want, +got:\n%s", diff)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -1,111 +0,0 @@
|
|||
// SPDX-FileCopyrightText: 2023 The Crossplane Authors <https://crossplane.io>
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package migration
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/crossplane/crossplane-runtime/pkg/logging"
|
||||
"github.com/pkg/errors"
|
||||
"k8s.io/utils/exec"
|
||||
)
|
||||
|
||||
const (
|
||||
errForkExecutorNotSupported = "step type should be Exec or step's manualExecution should be non-empty"
|
||||
errStepFailedFmt = "failed to execute the step %q"
|
||||
)
|
||||
|
||||
var _ Executor = &forkExecutor{}
|
||||
|
||||
// forkExecutor executes Exec steps or steps with the `manualExecution` hints
|
||||
// by forking processes.
|
||||
type forkExecutor struct {
|
||||
executor exec.Interface
|
||||
logger logging.Logger
|
||||
cwd string
|
||||
}
|
||||
|
||||
// ForkExecutorOption allows you to configure forkExecutor objects.
|
||||
type ForkExecutorOption func(executor *forkExecutor)
|
||||
|
||||
// WithLogger sets the logger of forkExecutor.
|
||||
func WithLogger(l logging.Logger) ForkExecutorOption {
|
||||
return func(e *forkExecutor) {
|
||||
e.logger = l
|
||||
}
|
||||
}
|
||||
|
||||
// WithExecutor sets the executor of ForkExecutor.
|
||||
func WithExecutor(e exec.Interface) ForkExecutorOption {
|
||||
return func(fe *forkExecutor) {
|
||||
fe.executor = e
|
||||
}
|
||||
}
|
||||
|
||||
// WithWorkingDir sets the current working directory for the executor.
|
||||
func WithWorkingDir(dir string) ForkExecutorOption {
|
||||
return func(e *forkExecutor) {
|
||||
e.cwd = dir
|
||||
}
|
||||
}
|
||||
|
||||
// NewForkExecutor returns a new fork executor using a process forker.
|
||||
func NewForkExecutor(opts ...ForkExecutorOption) Executor {
|
||||
fe := &forkExecutor{
|
||||
executor: exec.New(),
|
||||
logger: logging.NewNopLogger(),
|
||||
}
|
||||
for _, f := range opts {
|
||||
f(fe)
|
||||
}
|
||||
return fe
|
||||
}
|
||||
|
||||
func (f forkExecutor) Init(_ map[string]any) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f forkExecutor) Step(s Step, ctx map[string]any) error {
|
||||
var cmd exec.Cmd
|
||||
switch {
|
||||
case s.Type == StepTypeExec:
|
||||
f.logger.Debug("Command to be executed", "command", s.Exec.Command, "args", s.Exec.Args)
|
||||
return errors.Wrapf(f.exec(ctx, f.executor.Command(s.Exec.Command, s.Exec.Args...)), errStepFailedFmt, s.Name)
|
||||
// TODO: we had better have separate executors to handle the other types of
|
||||
// steps
|
||||
case len(s.ManualExecution) != 0:
|
||||
for _, c := range s.ManualExecution {
|
||||
f.logger.Debug("Command to be executed", "command", "sh", "args", []string{"-c", c})
|
||||
cmd = f.executor.Command("sh", "-c", c)
|
||||
if err := f.exec(ctx, cmd); err != nil {
|
||||
return errors.Wrapf(err, errStepFailedFmt, s.Name)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
default:
|
||||
return errors.Wrap(NewUnsupportedStepTypeError(s), errForkExecutorNotSupported)
|
||||
}
|
||||
}
|
||||
|
||||
func (f forkExecutor) exec(ctx map[string]any, cmd exec.Cmd) error {
|
||||
cmd.SetEnv(os.Environ())
|
||||
if f.cwd != "" {
|
||||
cmd.SetDir(f.cwd)
|
||||
}
|
||||
buff, err := cmd.CombinedOutput()
|
||||
logMsg := "Successfully executed command"
|
||||
if err != nil {
|
||||
logMsg = "Command execution failed"
|
||||
}
|
||||
f.logger.Debug(logMsg, "output", string(buff))
|
||||
if ctx != nil {
|
||||
ctx[KeyContextDiagnostics] = buff
|
||||
}
|
||||
return errors.Wrapf(err, "failed to execute command")
|
||||
}
|
||||
|
||||
func (f forkExecutor) Destroy() error {
|
||||
return nil
|
||||
}
|
|
@ -1,110 +0,0 @@
|
|||
// SPDX-FileCopyrightText: 2023 The Crossplane Authors <https://crossplane.io>
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package migration
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/crossplane/crossplane-runtime/pkg/test"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/pkg/errors"
|
||||
k8sExec "k8s.io/utils/exec"
|
||||
testingexec "k8s.io/utils/exec/testing"
|
||||
)
|
||||
|
||||
var (
|
||||
backupManagedStep = Step{
|
||||
Name: "backup-managed-resources",
|
||||
Type: StepTypeExec,
|
||||
Exec: &ExecStep{
|
||||
Command: "sh",
|
||||
Args: []string{"-c", "kubectl get managed -o yaml"},
|
||||
},
|
||||
}
|
||||
|
||||
wrongCommand = Step{
|
||||
Name: "wrong-command",
|
||||
Type: StepTypeExec,
|
||||
Exec: &ExecStep{
|
||||
Command: "sh",
|
||||
Args: []string{"-c", "nosuchcommand"},
|
||||
},
|
||||
}
|
||||
|
||||
wrongStepType = Step{
|
||||
Name: "wrong-step-type",
|
||||
Type: StepTypeDelete,
|
||||
}
|
||||
)
|
||||
|
||||
var errorWrongCommand = errors.New("exit status 127")
|
||||
|
||||
func newFakeExec(err error) *testingexec.FakeExec {
|
||||
return &testingexec.FakeExec{
|
||||
CommandScript: []testingexec.FakeCommandAction{
|
||||
func(_ string, _ ...string) k8sExec.Cmd {
|
||||
return &testingexec.FakeCmd{
|
||||
CombinedOutputScript: []testingexec.FakeAction{
|
||||
func() ([]byte, []byte, error) {
|
||||
return nil, nil, err
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func TestForkExecutorStep(t *testing.T) {
|
||||
type args struct {
|
||||
step Step
|
||||
fakeExec *testingexec.FakeExec
|
||||
}
|
||||
type want struct {
|
||||
err error
|
||||
}
|
||||
|
||||
cases := map[string]struct {
|
||||
args
|
||||
want
|
||||
}{
|
||||
"Success": {
|
||||
args: args{
|
||||
step: backupManagedStep,
|
||||
fakeExec: &testingexec.FakeExec{DisableScripts: true},
|
||||
},
|
||||
want: want{
|
||||
nil,
|
||||
},
|
||||
},
|
||||
"Failure": {
|
||||
args: args{
|
||||
step: wrongCommand,
|
||||
fakeExec: newFakeExec(errorWrongCommand),
|
||||
},
|
||||
want: want{
|
||||
errors.Wrap(errorWrongCommand, `failed to execute the step "wrong-command": failed to execute command`),
|
||||
},
|
||||
},
|
||||
"WrongStepType": {
|
||||
args: args{
|
||||
step: wrongStepType,
|
||||
},
|
||||
want: want{
|
||||
errors.Wrap(NewUnsupportedStepTypeError(wrongStepType), `step type should be Exec or step's manualExecution should be non-empty`),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range cases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
fe := NewForkExecutor(WithExecutor(tc.fakeExec))
|
||||
err := fe.Step(tc.step, nil)
|
||||
if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" {
|
||||
t.Errorf("\n%s\nStep(...): -want error, +got error:\n%s", name, diff)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -1,172 +0,0 @@
|
|||
// SPDX-FileCopyrightText: 2023 The Crossplane Authors <https://crossplane.io>
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package migration
|
||||
|
||||
import (
|
||||
"github.com/crossplane/crossplane-runtime/pkg/resource"
|
||||
xpv1 "github.com/crossplane/crossplane/apis/apiextensions/v1"
|
||||
xpmetav1 "github.com/crossplane/crossplane/apis/pkg/meta/v1"
|
||||
xpmetav1alpha1 "github.com/crossplane/crossplane/apis/pkg/meta/v1alpha1"
|
||||
xppkgv1 "github.com/crossplane/crossplane/apis/pkg/v1"
|
||||
xppkgv1beta1 "github.com/crossplane/crossplane/apis/pkg/v1beta1"
|
||||
)
|
||||
|
||||
// ResourceConverter converts a managed resource from
|
||||
// the migration source provider's schema to the migration target
|
||||
// provider's schema.
|
||||
type ResourceConverter interface {
|
||||
// Resource takes a managed resource and returns zero or more managed
|
||||
// resources to be created.
|
||||
Resource(mg resource.Managed) ([]resource.Managed, error)
|
||||
}
|
||||
|
||||
// ComposedTemplateConverter converts a Composition's ComposedTemplate
|
||||
// from the migration source provider's schema to the migration target
|
||||
// provider's schema. Conversion of the `Base` must be handled by
|
||||
// a ResourceConverter.
|
||||
type ComposedTemplateConverter interface {
|
||||
// ComposedTemplate receives a migration source v1.ComposedTemplate
|
||||
// that has been converted, by a resource converter, to the
|
||||
// v1.ComposedTemplates with the new shapes specified in the
|
||||
// `convertedTemplates` argument.
|
||||
// Conversion of the v1.ComposedTemplate.Bases is handled
|
||||
// via ResourceConverter.Resource and ComposedTemplate must only
|
||||
// convert the other fields (`Patches`, `ConnectionDetails`,
|
||||
// `PatchSet`s, etc.)
|
||||
// Returns any errors encountered.
|
||||
ComposedTemplate(sourceTemplate xpv1.ComposedTemplate, convertedTemplates ...*xpv1.ComposedTemplate) error
|
||||
}
|
||||
|
||||
// CompositionConverter converts a managed resource and a Composition's
|
||||
// ComposedTemplate that composes a managed resource of the same kind
|
||||
// from the migration source provider's schema to the migration target
|
||||
// provider's schema.
|
||||
type CompositionConverter interface {
|
||||
ResourceConverter
|
||||
ComposedTemplateConverter
|
||||
}
|
||||
|
||||
// PatchSetConverter converts patch sets of Compositions.
|
||||
// Any registered PatchSetConverters
|
||||
// will be called before any resource or ComposedTemplate conversion is done.
|
||||
// The rationale is to convert the Composition-wide patch sets before
|
||||
// any resource-specific conversions so that migration targets can
|
||||
// automatically inherit converted patch sets if their schemas match them.
|
||||
// Registered PatchSetConverters will be called in the order
|
||||
// they are registered.
|
||||
type PatchSetConverter interface {
|
||||
// PatchSets converts the `spec.patchSets` of a Composition
|
||||
// from the migration source provider's schema to the migration target
|
||||
// provider's schema.
|
||||
PatchSets(psMap map[string]*xpv1.PatchSet) error
|
||||
}
|
||||
|
||||
// ConfigurationMetadataConverter converts a Crossplane Configuration's metadata.
|
||||
type ConfigurationMetadataConverter interface {
|
||||
// ConfigurationMetadataV1 takes a Crossplane Configuration v1 metadata,
|
||||
// converts it, and stores the converted metadata in its argument.
|
||||
// Returns any errors encountered during the conversion.
|
||||
ConfigurationMetadataV1(configuration *xpmetav1.Configuration) error
|
||||
// ConfigurationMetadataV1Alpha1 takes a Crossplane Configuration v1alpha1
|
||||
// metadata, converts it, and stores the converted metadata in its
|
||||
// argument. Returns any errors encountered during the conversion.
|
||||
ConfigurationMetadataV1Alpha1(configuration *xpmetav1alpha1.Configuration) error
|
||||
}
|
||||
|
||||
// ConfigurationPackageConverter converts a Crossplane configuration package.
|
||||
type ConfigurationPackageConverter interface {
|
||||
// ConfigurationPackageV1 takes a Crossplane Configuration v1 package,
|
||||
// converts it possibly to multiple packages and returns
|
||||
// the converted configuration package.
|
||||
// Returns any errors encountered during the conversion.
|
||||
ConfigurationPackageV1(pkg *xppkgv1.Configuration) error
|
||||
}
|
||||
|
||||
// ProviderPackageConverter converts a Crossplane provider package.
|
||||
type ProviderPackageConverter interface {
|
||||
// ProviderPackageV1 takes a Crossplane Provider v1 package,
|
||||
// converts it possibly to multiple packages and returns the
|
||||
// converted provider packages.
|
||||
// Returns any errors encountered during the conversion.
|
||||
ProviderPackageV1(pkg xppkgv1.Provider) ([]xppkgv1.Provider, error)
|
||||
}
|
||||
|
||||
// PackageLockConverter converts a Crossplane package lock.
|
||||
type PackageLockConverter interface {
|
||||
// PackageLockV1Beta1 takes a Crossplane v1beta1 package lock,
|
||||
// converts it, and stores the converted lock in its argument.
|
||||
// Returns any errors encountered during the conversion.
|
||||
PackageLockV1Beta1(lock *xppkgv1beta1.Lock) error
|
||||
}
|
||||
|
||||
// Source is a source for reading resource manifests
|
||||
type Source interface {
|
||||
// HasNext returns `true` if the Source implementation has a next manifest
|
||||
// available to return with a call to Next. Any errors encountered while
|
||||
// determining whether a next manifest exists will also be reported.
|
||||
HasNext() (bool, error)
|
||||
// Next returns the next resource manifest available or
|
||||
// any errors encountered while reading the next resource manifest.
|
||||
Next() (UnstructuredWithMetadata, error)
|
||||
// Reset resets the Source so that it can read the manifests
|
||||
// from the beginning. There is no guarantee that the Source
|
||||
// will return the same set of manifests or it will return
|
||||
// them in the same order after a reset.
|
||||
Reset() error
|
||||
}
|
||||
|
||||
// Target is a target where resource manifests can be manipulated
|
||||
// (e.g., added, deleted, patched, etc.)
|
||||
type Target interface {
|
||||
// Put writes a resource manifest to this Target
|
||||
Put(o UnstructuredWithMetadata) error
|
||||
// Delete deletes a resource manifest from this Target
|
||||
Delete(o UnstructuredWithMetadata) error
|
||||
}
|
||||
|
||||
// Executor is a migration plan executor.
|
||||
type Executor interface {
|
||||
// Init initializes an executor using the supplied executor specific
|
||||
// configuration data.
|
||||
Init(config map[string]any) error
|
||||
// Step asks the executor to execute the next step passing any available
|
||||
// context from the previous step, and returns any new context to be passed
|
||||
// to the next step if there exists one.
|
||||
Step(s Step, ctx map[string]any) error
|
||||
// Destroy is called when all the steps have been executed,
|
||||
// or a step has returned an error, and we would like to stop
|
||||
// executing the plan.
|
||||
Destroy() error
|
||||
}
|
||||
|
||||
// UnstructuredPreProcessor allows manifests read by the Source
|
||||
// to be pre-processed before the converters are run
|
||||
// It's not possible to do any conversions via the pre-processors,
|
||||
// and they only allow migrators to extract information from
|
||||
// the manifests read by the Source before any converters are run.
|
||||
type UnstructuredPreProcessor interface {
|
||||
// PreProcess is called for a manifest read by the Source
|
||||
// before any converters are run.
|
||||
PreProcess(u UnstructuredWithMetadata) error
|
||||
}
|
||||
|
||||
// ManagedPreProcessor allows manifests read by the Source
|
||||
// to be pre-processed before the converters are run.
|
||||
// These pre-processors will work for GVKs that have ResourceConverter
|
||||
// registered.
|
||||
type ManagedPreProcessor interface {
|
||||
// ResourcePreProcessor is called for a manifest read by the Source
|
||||
// before any converters are run.
|
||||
ResourcePreProcessor(mg resource.Managed) error
|
||||
}
|
||||
|
||||
// CategoricalConverter is a converter that converts resources of a given
|
||||
// Category. Because it receives an unstructured argument, it should be
|
||||
// used for implementing generic conversion functions acting on a specific
|
||||
// category, such as setting a deletion policy on all the managed resources
|
||||
// observed by the migration Source.
|
||||
type CategoricalConverter interface {
|
||||
Convert(u *UnstructuredWithMetadata) error
|
||||
}
|
|
@ -1,331 +0,0 @@
|
|||
// SPDX-FileCopyrightText: 2023 The Crossplane Authors <https://crossplane.io>
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package migration
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/cli-runtime/pkg/resource"
|
||||
"k8s.io/client-go/discovery"
|
||||
"k8s.io/client-go/discovery/cached/disk"
|
||||
"k8s.io/client-go/dynamic"
|
||||
"k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/restmapper"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
"k8s.io/client-go/util/homedir"
|
||||
)
|
||||
|
||||
const (
|
||||
errKubernetesSourceInit = "failed to initialize the migration Kubernetes source"
|
||||
errCategoryGetFmt = "failed to get resources of category %q"
|
||||
)
|
||||
|
||||
var (
|
||||
_ Source = &KubernetesSource{}
|
||||
defaultCacheDir = filepath.Join(homedir.HomeDir(), ".kube", "cache")
|
||||
)
|
||||
|
||||
// KubernetesSource is a source implementation to read resources from Kubernetes
|
||||
// cluster.
|
||||
type KubernetesSource struct {
|
||||
registry *Registry
|
||||
categories []Category
|
||||
index int
|
||||
items []UnstructuredWithMetadata
|
||||
dynamicClient dynamic.Interface
|
||||
cachedDiscoveryClient discovery.CachedDiscoveryInterface
|
||||
restMapper meta.RESTMapper
|
||||
categoryExpander restmapper.CategoryExpander
|
||||
cacheDir string
|
||||
restConfig *rest.Config
|
||||
}
|
||||
|
||||
// KubernetesSourceOption sets an option for a KubernetesSource.
|
||||
type KubernetesSourceOption func(source *KubernetesSource)
|
||||
|
||||
// WithCacheDir sets the cache directory for the disk cached discovery client
|
||||
// used by a KubernetesSource.
|
||||
func WithCacheDir(cacheDir string) KubernetesSourceOption {
|
||||
return func(s *KubernetesSource) {
|
||||
s.cacheDir = cacheDir
|
||||
}
|
||||
}
|
||||
|
||||
// WithRegistry configures a KubernetesSource to use the specified registry
|
||||
// for determining the GVKs of resources which will be read from the
|
||||
// Kubernetes API server.
|
||||
func WithRegistry(r *Registry) KubernetesSourceOption {
|
||||
return func(s *KubernetesSource) {
|
||||
s.registry = r
|
||||
}
|
||||
}
|
||||
|
||||
// WithCategories configures a KubernetesSource so that it will fetch
|
||||
// all resources belonging to the specified categories.
|
||||
func WithCategories(c []Category) KubernetesSourceOption {
|
||||
return func(s *KubernetesSource) {
|
||||
s.categories = c
|
||||
}
|
||||
}
|
||||
|
||||
// NewKubernetesSourceFromKubeConfig initializes a new KubernetesSource using
|
||||
// the specified kube config file and KubernetesSourceOptions.
|
||||
func NewKubernetesSourceFromKubeConfig(kubeconfigPath string, opts ...KubernetesSourceOption) (*KubernetesSource, error) {
|
||||
ks := &KubernetesSource{}
|
||||
for _, o := range opts {
|
||||
o(ks)
|
||||
}
|
||||
|
||||
var err error
|
||||
ks.restConfig, err = clientcmd.BuildConfigFromFlags("", kubeconfigPath)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "cannot create rest config object")
|
||||
}
|
||||
ks.restConfig.ContentConfig = resource.UnstructuredPlusDefaultContentConfig()
|
||||
|
||||
ks.dynamicClient, err = InitializeDynamicClient(kubeconfigPath)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to initialize a Kubernetes dynamic client from kubeconfig: %s", kubeconfigPath)
|
||||
}
|
||||
ks.cachedDiscoveryClient, err = InitializeDiscoveryClient(kubeconfigPath, ks.cacheDir)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to initialize a Kubernetes discovery client from kubeconfig: %s", kubeconfigPath)
|
||||
}
|
||||
return ks, errors.Wrap(ks.init(), errKubernetesSourceInit)
|
||||
}
|
||||
|
||||
// NewKubernetesSource returns a KubernetesSource
|
||||
// DynamicClient is used here to query resources.
|
||||
// Elements of gvks (slice of GroupVersionKind) are passed to the Dynamic Client
|
||||
// in a loop to get list of resources.
|
||||
// An example element of gvks slice:
|
||||
// Group: "ec2.aws.upbound.io",
|
||||
// Version: "v1beta1",
|
||||
// Kind: "VPC",
|
||||
func NewKubernetesSource(dynamicClient dynamic.Interface, discoveryClient discovery.CachedDiscoveryInterface, opts ...KubernetesSourceOption) (*KubernetesSource, error) {
|
||||
ks := &KubernetesSource{
|
||||
dynamicClient: dynamicClient,
|
||||
cachedDiscoveryClient: discoveryClient,
|
||||
}
|
||||
for _, o := range opts {
|
||||
o(ks)
|
||||
}
|
||||
return ks, errors.Wrap(ks.init(), errKubernetesSourceInit)
|
||||
}
|
||||
|
||||
func (ks *KubernetesSource) init() error {
|
||||
ks.restMapper = restmapper.NewDeferredDiscoveryRESTMapper(ks.cachedDiscoveryClient)
|
||||
ks.categoryExpander = restmapper.NewDiscoveryCategoryExpander(ks.cachedDiscoveryClient)
|
||||
|
||||
for _, c := range ks.categories {
|
||||
if err := ks.getCategoryResources(c); err != nil {
|
||||
return errors.Wrapf(err, "cannot get resources of the category: %s", c)
|
||||
}
|
||||
}
|
||||
|
||||
if ks.registry == nil {
|
||||
return nil
|
||||
}
|
||||
if err := ks.getGVKResources(ks.registry.claimTypes, CategoryClaim); err != nil {
|
||||
return errors.Wrap(err, "cannot get claims")
|
||||
}
|
||||
if err := ks.getGVKResources(ks.registry.compositeTypes, CategoryComposite); err != nil {
|
||||
return errors.Wrap(err, "cannot get composites")
|
||||
}
|
||||
if err := ks.getGVKResources(ks.registry.GetCompositionGVKs(), CategoryComposition); err != nil {
|
||||
return errors.Wrap(err, "cannot get compositions")
|
||||
}
|
||||
if err := ks.getGVKResources(ks.registry.GetCrossplanePackageGVKs(), CategoryCrossplanePackage); err != nil {
|
||||
return errors.Wrap(err, "cannot get Crossplane packages")
|
||||
}
|
||||
return errors.Wrap(ks.getGVKResources(ks.registry.GetManagedResourceGVKs(), CategoryManaged), "cannot get managed resources")
|
||||
}
|
||||
|
||||
func (ks *KubernetesSource) getMappingFor(gr schema.GroupResource) (*meta.RESTMapping, error) {
|
||||
r := fmt.Sprintf("%s.%s", gr.Resource, gr.Group)
|
||||
fullySpecifiedGVR, groupResource := schema.ParseResourceArg(r)
|
||||
gvk := schema.GroupVersionKind{}
|
||||
if fullySpecifiedGVR != nil {
|
||||
gvk, _ = ks.restMapper.KindFor(*fullySpecifiedGVR)
|
||||
}
|
||||
if gvk.Empty() {
|
||||
gvk, _ = ks.restMapper.KindFor(groupResource.WithVersion(""))
|
||||
}
|
||||
if !gvk.Empty() {
|
||||
return ks.restMapper.RESTMapping(gvk.GroupKind(), gvk.Version)
|
||||
}
|
||||
fullySpecifiedGVK, groupKind := schema.ParseKindArg(r)
|
||||
if fullySpecifiedGVK == nil {
|
||||
gvk := groupKind.WithVersion("")
|
||||
fullySpecifiedGVK = &gvk
|
||||
}
|
||||
|
||||
if !fullySpecifiedGVK.Empty() {
|
||||
if mapping, err := ks.restMapper.RESTMapping(fullySpecifiedGVK.GroupKind(), fullySpecifiedGVK.Version); err == nil {
|
||||
return mapping, nil
|
||||
}
|
||||
}
|
||||
|
||||
mapping, err := ks.restMapper.RESTMapping(groupKind, gvk.Version)
|
||||
if err != nil {
|
||||
if meta.IsNoMatchError(err) {
|
||||
return nil, errors.Errorf("the server doesn't have a resource type %q", groupResource.Resource)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return mapping, nil
|
||||
}
|
||||
|
||||
// parts of this implement are taken from the implementation of
|
||||
// the "kubectl get" command:
|
||||
// https://github.com/kubernetes/kubernetes/tree/master/staging/src/k8s.io/kubectl/pkg/cmd/get
|
||||
func (ks *KubernetesSource) getCategoryResources(c Category) error {
|
||||
if ks.restConfig == nil {
|
||||
return errors.New("rest.Config not initialized")
|
||||
}
|
||||
grs, _ := ks.categoryExpander.Expand(c.String())
|
||||
for _, gr := range grs {
|
||||
mapping, err := ks.getMappingFor(gr)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, errCategoryGetFmt, c.String())
|
||||
}
|
||||
gv := mapping.GroupVersionKind.GroupVersion()
|
||||
ks.restConfig.GroupVersion = &gv
|
||||
if len(gv.Group) == 0 {
|
||||
ks.restConfig.APIPath = "/api"
|
||||
} else {
|
||||
ks.restConfig.APIPath = "/apis"
|
||||
}
|
||||
client, err := rest.RESTClientFor(ks.restConfig)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, errCategoryGetFmt, c.String())
|
||||
}
|
||||
helper := resource.NewHelper(client, mapping)
|
||||
list, err := helper.List("", mapping.GroupVersionKind.GroupVersion().String(), &metav1.ListOptions{})
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, errCategoryGetFmt, c.String())
|
||||
}
|
||||
ul, ok := list.(*unstructured.UnstructuredList)
|
||||
if !ok {
|
||||
return errors.New("expecting list to be of type *unstructured.UnstructuredList")
|
||||
}
|
||||
for _, u := range ul.Items {
|
||||
ks.items = append(ks.items, UnstructuredWithMetadata{
|
||||
Object: u,
|
||||
Metadata: Metadata{
|
||||
Path: string(u.GetUID()),
|
||||
Category: c,
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ks *KubernetesSource) getGVKResources(gvks []schema.GroupVersionKind, category Category) error {
|
||||
processed := map[schema.GroupVersionKind]struct{}{}
|
||||
for _, gvk := range gvks {
|
||||
if _, ok := processed[gvk]; ok {
|
||||
continue
|
||||
}
|
||||
m, err := ks.restMapper.RESTMapping(gvk.GroupKind(), gvk.Version)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "cannot get REST mappings for GVK: %s", gvk.String())
|
||||
}
|
||||
if err := ks.getResourcesFor(m.Resource, category); err != nil {
|
||||
return errors.Wrapf(err, "cannot get resources for GVK: %s", gvk.String())
|
||||
}
|
||||
processed[gvk] = struct{}{}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ks *KubernetesSource) getResourcesFor(gvr schema.GroupVersionResource, category Category) error {
|
||||
ri := ks.dynamicClient.Resource(gvr)
|
||||
unstructuredList, err := ri.List(context.TODO(), metav1.ListOptions{})
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "cannot list resources of GVR: %s", gvr.String())
|
||||
}
|
||||
for _, u := range unstructuredList.Items {
|
||||
ks.items = append(ks.items, UnstructuredWithMetadata{
|
||||
Object: u,
|
||||
Metadata: Metadata{
|
||||
Path: string(u.GetUID()),
|
||||
Category: category,
|
||||
},
|
||||
})
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// HasNext checks the next item
|
||||
func (ks *KubernetesSource) HasNext() (bool, error) {
|
||||
return ks.index < len(ks.items), nil
|
||||
}
|
||||
|
||||
// Next returns the next item of slice
|
||||
func (ks *KubernetesSource) Next() (UnstructuredWithMetadata, error) {
|
||||
if hasNext, _ := ks.HasNext(); hasNext {
|
||||
item := ks.items[ks.index]
|
||||
ks.index++
|
||||
return item, nil
|
||||
}
|
||||
return UnstructuredWithMetadata{}, errors.New("no more elements")
|
||||
}
|
||||
|
||||
// Reset resets the source so that resources can be reread from the beginning.
|
||||
func (ks *KubernetesSource) Reset() error {
|
||||
ks.index = 0
|
||||
return nil
|
||||
}
|
||||
|
||||
// InitializeDynamicClient returns a dynamic client
|
||||
func InitializeDynamicClient(kubeconfigPath string) (dynamic.Interface, error) {
|
||||
config, err := clientcmd.BuildConfigFromFlags("", kubeconfigPath)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "cannot create rest config object")
|
||||
}
|
||||
dynamicClient, err := dynamic.NewForConfig(config)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "cannot initialize dynamic client")
|
||||
}
|
||||
return dynamicClient, nil
|
||||
}
|
||||
|
||||
func InitializeDiscoveryClient(kubeconfigPath, cacheDir string) (*disk.CachedDiscoveryClient, error) {
|
||||
config, err := clientcmd.BuildConfigFromFlags("", kubeconfigPath)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "cannot create rest config object")
|
||||
}
|
||||
|
||||
if cacheDir == "" {
|
||||
cacheDir = defaultCacheDir
|
||||
}
|
||||
httpCacheDir := filepath.Join(cacheDir, "http")
|
||||
discoveryCacheDir := computeDiscoverCacheDir(filepath.Join(cacheDir, "discovery"), config.Host)
|
||||
return disk.NewCachedDiscoveryClientForConfig(config, discoveryCacheDir, httpCacheDir, 10*time.Minute)
|
||||
}
|
||||
|
||||
// overlyCautiousIllegalFileCharacters matches characters that *might* not be supported. Windows is really restrictive, so this is really restrictive
|
||||
var overlyCautiousIllegalFileCharacters = regexp.MustCompile(`[^(\w/.)]`)
|
||||
|
||||
// computeDiscoverCacheDir takes the parentDir and the host and comes up with a "usually non-colliding" name.
|
||||
func computeDiscoverCacheDir(parentDir, host string) string {
|
||||
// strip the optional scheme from host if its there:
|
||||
schemelessHost := strings.Replace(strings.Replace(host, "https://", "", 1), "http://", "", 1)
|
||||
// now do a simple collapse of non-AZ09 characters. Collisions are possible but unlikely. Even if we do collide the problem is short lived
|
||||
safeHost := overlyCautiousIllegalFileCharacters.ReplaceAllString(schemelessHost, "_")
|
||||
return filepath.Join(parentDir, safeHost)
|
||||
}
|
|
@ -1,156 +0,0 @@
|
|||
// SPDX-FileCopyrightText: 2023 The Crossplane Authors <https://crossplane.io>
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package migration
|
||||
|
||||
import (
|
||||
"cmp"
|
||||
"slices"
|
||||
"testing"
|
||||
|
||||
"github.com/crossplane/crossplane-runtime/pkg/test"
|
||||
gocmp "github.com/google/go-cmp/cmp"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/client-go/discovery/cached/memory"
|
||||
"k8s.io/client-go/dynamic/fake"
|
||||
fakeclientset "k8s.io/client-go/kubernetes/fake"
|
||||
)
|
||||
|
||||
func TestNewKubernetesSource(t *testing.T) {
|
||||
type args struct {
|
||||
gvks []schema.GroupVersionKind
|
||||
}
|
||||
type want struct {
|
||||
ks *KubernetesSource
|
||||
err error
|
||||
}
|
||||
|
||||
cases := map[string]struct {
|
||||
args
|
||||
want
|
||||
}{
|
||||
"Successful": {
|
||||
args: args{
|
||||
gvks: []schema.GroupVersionKind{
|
||||
{
|
||||
Group: "ec2.aws.crossplane.io",
|
||||
Version: "v1beta1",
|
||||
Kind: "VPC",
|
||||
},
|
||||
{
|
||||
Group: "azure.crossplane.io",
|
||||
Version: "v1beta1",
|
||||
Kind: "ResourceGroup",
|
||||
},
|
||||
},
|
||||
},
|
||||
want: want{
|
||||
ks: &KubernetesSource{
|
||||
items: []UnstructuredWithMetadata{
|
||||
{
|
||||
Object: unstructured.Unstructured{
|
||||
Object: unstructuredAwsVpc,
|
||||
},
|
||||
Metadata: Metadata{
|
||||
Category: CategoryManaged,
|
||||
},
|
||||
},
|
||||
{
|
||||
Object: unstructured.Unstructured{
|
||||
Object: unstructuredResourceGroup,
|
||||
},
|
||||
Metadata: Metadata{
|
||||
Category: CategoryManaged,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for name, tc := range cases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
s := runtime.NewScheme()
|
||||
r := NewRegistry(s)
|
||||
// register a dummy converter for the test GVKs
|
||||
r.resourceConverters = map[schema.GroupVersionKind]ResourceConverter{}
|
||||
for _, gvk := range tc.args.gvks {
|
||||
r.resourceConverters[gvk] = nil
|
||||
}
|
||||
dynamicClient := fake.NewSimpleDynamicClientWithCustomListKinds(s,
|
||||
map[schema.GroupVersionResource]string{
|
||||
{
|
||||
Group: "ec2.aws.crossplane.io",
|
||||
Version: "v1beta1",
|
||||
Resource: "vpcs",
|
||||
}: "VPCList",
|
||||
{
|
||||
Group: "azure.crossplane.io",
|
||||
Version: "v1beta1",
|
||||
Resource: "resourcegroups",
|
||||
}: "ResourceGroupList",
|
||||
},
|
||||
&unstructured.Unstructured{Object: unstructuredAwsVpc},
|
||||
&unstructured.Unstructured{Object: unstructuredResourceGroup})
|
||||
client := fakeclientset.NewSimpleClientset(
|
||||
&unstructured.Unstructured{Object: unstructuredAwsVpc},
|
||||
&unstructured.Unstructured{Object: unstructuredResourceGroup},
|
||||
)
|
||||
client.Fake.Resources = []*metav1.APIResourceList{
|
||||
{
|
||||
GroupVersion: "ec2.aws.crossplane.io/v1beta1",
|
||||
APIResources: []metav1.APIResource{
|
||||
{
|
||||
Name: "vpcs",
|
||||
Kind: "VPC",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
GroupVersion: "azure.crossplane.io/v1beta1",
|
||||
APIResources: []metav1.APIResource{
|
||||
{
|
||||
Name: "resourcegroups",
|
||||
Kind: "ResourceGroup",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
ks, err := NewKubernetesSource(dynamicClient, memory.NewMemCacheClient(client.Discovery()), WithRegistry(r))
|
||||
if diff := gocmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" {
|
||||
t.Errorf("\nNext(...): -want, +got:\n%s", diff)
|
||||
}
|
||||
slices.SortFunc(tc.want.ks.items, compareUnstructuredWithMetadata)
|
||||
slices.SortFunc(ks.items, compareUnstructuredWithMetadata)
|
||||
if diff := gocmp.Diff(tc.want.ks.items, ks.items); diff != "" {
|
||||
t.Errorf("\nNext(...): -want, +got:\n%s", diff)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// compareUnstructuredWithMetadata is used for sorting UnstructuredWithMetadata
|
||||
// slices based on their namespaced names and GVKs.
|
||||
func compareUnstructuredWithMetadata(a, b UnstructuredWithMetadata) int {
|
||||
switch {
|
||||
case a.Object.Object == nil && b.Object.Object == nil:
|
||||
return 0 // not comparable
|
||||
case a.Object.Object == nil && b.Object.Object != nil:
|
||||
return -1
|
||||
case a.Object.Object != nil && b.Object.Object == nil:
|
||||
return 1
|
||||
}
|
||||
fS := func(x *UnstructuredWithMetadata) string {
|
||||
return types.NamespacedName{
|
||||
Namespace: x.Object.GetNamespace(),
|
||||
Name: x.Object.GetName(),
|
||||
}.String() + ":" + x.Object.GetObjectKind().GroupVersionKind().String()
|
||||
}
|
||||
return cmp.Compare(fS(&a), fS(&b))
|
||||
}
|
|
@ -1,60 +0,0 @@
|
|||
// SPDX-FileCopyrightText: 2023 The Crossplane Authors <https://crossplane.io>
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package migration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
)
|
||||
|
||||
func (pg *PlanGenerator) convertPackageLock(o UnstructuredWithMetadata) error {
|
||||
lock, err := toPackageLock(o.Object)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
isConverted := false
|
||||
for _, lockConv := range pg.registry.packageLockConverters {
|
||||
if lockConv.re == nil || lockConv.converter == nil || !lockConv.re.MatchString(lock.GetName()) {
|
||||
continue
|
||||
}
|
||||
if err := lockConv.converter.PackageLockV1Beta1(lock); err != nil {
|
||||
return errors.Wrapf(err, "failed to call converter on package lock: %s", lock.GetName())
|
||||
}
|
||||
// TODO: if a lock converter does not convert the given lock,
|
||||
// we will have a false positive. Better to compute and check
|
||||
// a diff here.
|
||||
isConverted = true
|
||||
}
|
||||
if !isConverted {
|
||||
return nil
|
||||
}
|
||||
target := &UnstructuredWithMetadata{
|
||||
Object: ToSanitizedUnstructured(lock),
|
||||
Metadata: o.Metadata,
|
||||
}
|
||||
if err := pg.stepEditPackageLock(o, target); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (pg *PlanGenerator) stepEditPackageLock(source UnstructuredWithMetadata, t *UnstructuredWithMetadata) error {
|
||||
// add step for editing the package lock
|
||||
s := pg.stepConfiguration(stepEditPackageLock)
|
||||
t.Metadata.Path = fmt.Sprintf("%s/%s.yaml", s.Name, getVersionedName(t.Object))
|
||||
s.Patch.Files = append(s.Patch.Files, t.Metadata.Path)
|
||||
patchMap, err := computeJSONMergePathDoc(source.Object, t.Object)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return errors.Wrapf(pg.target.Put(UnstructuredWithMetadata{
|
||||
Object: unstructured.Unstructured{
|
||||
Object: addNameGVK(t.Object, patchMap),
|
||||
},
|
||||
Metadata: t.Metadata,
|
||||
}), errEditConfigurationPackageFmt, t.Object.GetName())
|
||||
}
|
|
@ -1,346 +0,0 @@
|
|||
// SPDX-FileCopyrightText: 2023 The Crossplane Authors <https://crossplane.io>
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package migration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
xpv1 "github.com/crossplane/crossplane/apis/apiextensions/v1"
|
||||
"github.com/pkg/errors"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
var (
|
||||
regexIndex = regexp.MustCompile(`(.+)\[(.+)]`)
|
||||
regexJSONTag = regexp.MustCompile(`([^,]+)?(,.+)?`)
|
||||
)
|
||||
|
||||
const (
|
||||
jsonTagInlined = ",inline"
|
||||
)
|
||||
|
||||
// isConverted looks up the specified name in the list of already converted
|
||||
// patch sets.
|
||||
func isConverted(convertedPS []string, psName string) bool {
|
||||
for _, n := range convertedPS {
|
||||
if psName == n {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// removeInvalidPatches removes the (inherited) patches from
|
||||
// a (split) migration target composed template. The migration target composed
|
||||
// templates inherit patches from migration source templates by default, and
|
||||
// this function is responsible for removing patches (including references to
|
||||
// patch sets) that do not conform to the target composed template's schema.
|
||||
func (pg *PlanGenerator) removeInvalidPatches(gvkSource, gvkTarget schema.GroupVersionKind, patchSets []xpv1.PatchSet, targetTemplate *xpv1.ComposedTemplate, convertedPS []string) error { //nolint:gocyclo // complexity (11) just above the threshold (10)
|
||||
c := pg.registry.scheme
|
||||
source, err := c.New(gvkSource)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to instantiate a new source object with GVK: %s", gvkSource.String())
|
||||
}
|
||||
target, err := c.New(gvkTarget)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to instantiate a new target object with GVK: %s", gvkTarget.String())
|
||||
}
|
||||
|
||||
newPatches := make([]xpv1.Patch, 0, len(targetTemplate.Patches))
|
||||
var patches []xpv1.Patch
|
||||
for _, p := range targetTemplate.Patches {
|
||||
s := source
|
||||
switch p.Type { //nolint:exhaustive
|
||||
case xpv1.PatchTypePatchSet:
|
||||
ps := getNamedPatchSet(p.PatchSetName, patchSets)
|
||||
if ps == nil {
|
||||
// something is wrong with the patchset ref,
|
||||
// we will just remove the ref
|
||||
continue
|
||||
}
|
||||
if isConverted(convertedPS, ps.Name) {
|
||||
// then do not use the source schema as the patch set
|
||||
// is already converted
|
||||
s = target
|
||||
}
|
||||
// assert each of the patches in the set
|
||||
// conform the target schema
|
||||
patches = ps.Patches
|
||||
default:
|
||||
patches = []xpv1.Patch{p}
|
||||
}
|
||||
keep := true
|
||||
for _, p := range patches {
|
||||
ok, err := assertPatchSchemaConformance(p, s, target)
|
||||
if err != nil {
|
||||
err := errors.Wrap(err, "failed to check whether the patch conforms to the target schema")
|
||||
if pg.ErrorOnInvalidPatchSchema {
|
||||
return err
|
||||
}
|
||||
log.Printf("Excluding the patch from the migration target because conformance checking has failed with: %v\n", err)
|
||||
// if we could not check the patch's schema conformance
|
||||
// and the plan generator is configured not to error,
|
||||
// assume the patch does not conform to the schema
|
||||
ok = false
|
||||
}
|
||||
if !ok {
|
||||
keep = false
|
||||
break
|
||||
}
|
||||
}
|
||||
if keep {
|
||||
newPatches = append(newPatches, p)
|
||||
}
|
||||
}
|
||||
targetTemplate.Patches = newPatches
|
||||
return nil
|
||||
}
|
||||
|
||||
// assertPatchSchemaConformance asserts that the specified patch actually
|
||||
// conforms the specified target schema. We also assert the patch conforms
|
||||
// to the migration source schema, which prevents an invalid patch from being
|
||||
// preserved after the conversion.
|
||||
func assertPatchSchemaConformance(p xpv1.Patch, source, target any) (bool, error) {
|
||||
var targetPath *string
|
||||
// because this is defaulting logic and what we default can be overridden
|
||||
// later in the convert, the type switch is not exhaustive
|
||||
// TODO: consider processing other patch types
|
||||
switch p.Type { //nolint:exhaustive
|
||||
case xpv1.PatchTypeFromCompositeFieldPath, "": // the default type
|
||||
targetPath = p.ToFieldPath
|
||||
case xpv1.PatchTypeToCompositeFieldPath:
|
||||
targetPath = p.FromFieldPath
|
||||
}
|
||||
if targetPath == nil {
|
||||
return false, nil
|
||||
}
|
||||
ok, err := assertNameAndTypeAtPath(reflect.TypeOf(source), reflect.TypeOf(target), splitPathComponents(*targetPath))
|
||||
return ok, errors.Wrapf(err, "failed to assert patch schema for path: %s", *targetPath)
|
||||
}
|
||||
|
||||
// splitPathComponents splits a fieldpath expression into its path components,
|
||||
// e.g., `m[a.b.c].a.b.c` is split into `m[a.b.c]`, `a`, `b`, `c`.
|
||||
func splitPathComponents(path string) []string {
|
||||
components := strings.Split(path, ".")
|
||||
result := make([]string, 0, len(components))
|
||||
indexedExpression := false
|
||||
for _, c := range components {
|
||||
switch {
|
||||
case indexedExpression:
|
||||
result[len(result)-1] = fmt.Sprintf("%s.%s", result[len(result)-1], c)
|
||||
if strings.Contains(c, "]") {
|
||||
indexedExpression = false
|
||||
}
|
||||
default:
|
||||
result = append(result, c)
|
||||
if strings.Contains(c, "[") && !strings.Contains(c, "]") {
|
||||
indexedExpression = true
|
||||
}
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func isRawExtension(source, target reflect.Type) bool {
|
||||
reType := reflect.TypeOf(runtime.RawExtension{})
|
||||
rePtrType := reflect.TypeOf(&runtime.RawExtension{})
|
||||
return (source == reType && target == reType) || (source == rePtrType && target == rePtrType)
|
||||
}
|
||||
|
||||
// assertNameAndTypeAtPath asserts that the migration source and target
|
||||
// templates both have the same kind for the type at the specified path.
|
||||
// Also validates the specific path is valid for the source.
|
||||
func assertNameAndTypeAtPath(source, target reflect.Type, pathComponents []string) (bool, error) { //nolint:gocyclo
|
||||
if len(pathComponents) < 1 {
|
||||
return compareKinds(source, target), nil
|
||||
}
|
||||
// if both source and target are runtime.RawExtensions,
|
||||
// then stop traversing the type hierarchy.
|
||||
if isRawExtension(source, target) {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
pathComponent := pathComponents[0]
|
||||
if len(pathComponent) == 0 {
|
||||
return false, errors.Errorf("failed to compare source and target structs. Invalid path: %s", strings.Join(pathComponents, "."))
|
||||
}
|
||||
m := regexIndex.FindStringSubmatch(pathComponent)
|
||||
if m != nil {
|
||||
// then a map component or a slicing component
|
||||
pathComponent = m[1]
|
||||
}
|
||||
|
||||
// assert the source and the target types
|
||||
fSource, err := getFieldWithSerializedName(source, pathComponent)
|
||||
if err != nil {
|
||||
return false, errors.Wrapf(err, "failed to assert source struct field kind at path: %s", strings.Join(pathComponents, "."))
|
||||
}
|
||||
if fSource == nil {
|
||||
// then source field could not be found
|
||||
return false, errors.Errorf("struct field %q does not exist for the source type %q at path: %s", pathComponent, source.String(), strings.Join(pathComponents, "."))
|
||||
}
|
||||
// now assert that this field actually exists for the target type
|
||||
// with the same type
|
||||
fTarget, err := getFieldWithSerializedName(target, pathComponent)
|
||||
if err != nil {
|
||||
return false, errors.Wrapf(err, "failed to assert target struct field kind at path: %s", strings.Join(pathComponents, "."))
|
||||
}
|
||||
if fTarget == nil || !fTarget.IsExported() || !compareKinds(fSource.Type, fTarget.Type) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
nextSource, nextTarget := fSource.Type, fTarget.Type
|
||||
if m != nil {
|
||||
// parents are of map or slice type
|
||||
nextSource = nextSource.Elem()
|
||||
nextTarget = nextTarget.Elem()
|
||||
}
|
||||
return assertNameAndTypeAtPath(nextSource, nextTarget, pathComponents[1:])
|
||||
}
|
||||
|
||||
// compareKinds compares the kinds of the specified types
|
||||
// dereferencing (following) pointer types.
|
||||
func compareKinds(s, t reflect.Type) bool {
|
||||
if s.Kind() == reflect.Pointer {
|
||||
s = s.Elem()
|
||||
}
|
||||
if t.Kind() == reflect.Pointer {
|
||||
t = t.Elem()
|
||||
}
|
||||
return s.Kind() == t.Kind()
|
||||
}
|
||||
|
||||
// getFieldWithSerializedName returns the field of a struct (if it exists)
|
||||
// with the specified serialized (JSON) name. Returns a nil (and a nil error)
|
||||
// if a field with the specified serialized name is not found
|
||||
// in the specified type.
|
||||
func getFieldWithSerializedName(t reflect.Type, name string) (*reflect.StructField, error) { //nolint:gocyclo
|
||||
if t.Kind() == reflect.Pointer {
|
||||
t = t.Elem()
|
||||
}
|
||||
if t.Kind() != reflect.Struct {
|
||||
return nil, errors.Errorf("type is not a struct: %s", t.Name())
|
||||
}
|
||||
for i := 0; i < t.NumField(); i++ {
|
||||
f := t.Field(i)
|
||||
serializedName := f.Name
|
||||
inlined := false
|
||||
if fTag, ok := f.Tag.Lookup("json"); ok {
|
||||
if m := regexJSONTag.FindStringSubmatch(fTag); m != nil && len(m[1]) > 0 {
|
||||
serializedName = m[1]
|
||||
}
|
||||
if strings.HasSuffix(fTag, jsonTagInlined) {
|
||||
inlined = true
|
||||
}
|
||||
}
|
||||
if name == serializedName {
|
||||
return &f, nil
|
||||
}
|
||||
if inlined {
|
||||
inlinedType := f.Type
|
||||
if inlinedType.Kind() == reflect.Pointer {
|
||||
inlinedType = inlinedType.Elem()
|
||||
}
|
||||
if inlinedType.Kind() == reflect.Struct {
|
||||
sf, err := getFieldWithSerializedName(inlinedType, name)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to search for field %q in inlined type: %s", name, inlinedType.String())
|
||||
}
|
||||
if sf != nil {
|
||||
return sf, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil, nil // not found
|
||||
}
|
||||
|
||||
// getNamedPatchSet returns the patch set with the specified name
|
||||
// from the specified patch set slice. Returns nil if a patch set
|
||||
// with the given name is not found.
|
||||
func getNamedPatchSet(name *string, patchSets []xpv1.PatchSet) *xpv1.PatchSet {
|
||||
if name == nil {
|
||||
// if name is not specified, do not attempt to find a named patchset
|
||||
return nil
|
||||
}
|
||||
for _, ps := range patchSets {
|
||||
if *name == ps.Name {
|
||||
return &ps
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// getConvertedPatchSetNames returns the names of patch sets that have been
|
||||
// converted by a PatchSetConverter.
|
||||
func getConvertedPatchSetNames(newPatchSets, oldPatchSets []xpv1.PatchSet) []string {
|
||||
converted := make([]string, 0, len(newPatchSets))
|
||||
for _, n := range newPatchSets {
|
||||
found := false
|
||||
for _, o := range oldPatchSets {
|
||||
if o.Name != n.Name {
|
||||
continue
|
||||
}
|
||||
found = true
|
||||
if !reflect.DeepEqual(o, n) {
|
||||
converted = append(converted, n.Name)
|
||||
}
|
||||
break
|
||||
}
|
||||
if !found {
|
||||
converted = append(converted, n.Name)
|
||||
}
|
||||
}
|
||||
return converted
|
||||
}
|
||||
|
||||
// convertToMap converts the given slice of patch sets to a map of
|
||||
// patch sets keyed by their names.
|
||||
func convertToMap(ps []xpv1.PatchSet) map[string]*xpv1.PatchSet {
|
||||
m := make(map[string]*xpv1.PatchSet, len(ps))
|
||||
for _, p := range ps {
|
||||
// Crossplane dereferences the last patch set with the same name,
|
||||
// so override with the last patch set with the same name.
|
||||
m[p.Name] = p.DeepCopy()
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// convertFromMap converts the specified map of patch sets back to a slice.
|
||||
// If filterDeleted is set, previously existing patch sets in the Composition
|
||||
// which have been removed from the map are also removed from the resulting
|
||||
// slice, and eventually from the Composition. PatchSetConverters are
|
||||
// allowed to remove patch sets, whereas Composition converters are
|
||||
// not, as Composition converters have a local view of the patch sets and
|
||||
// don't know about the other composed templates that may be sharing
|
||||
// patch sets with them.
|
||||
func convertFromMap(psMap map[string]*xpv1.PatchSet, oldPS []xpv1.PatchSet, filterDeleted bool) []xpv1.PatchSet {
|
||||
result := make([]xpv1.PatchSet, 0, len(psMap))
|
||||
for _, ps := range oldPS {
|
||||
if filterDeleted && psMap[ps.Name] == nil {
|
||||
// then patch set has been deleted
|
||||
continue
|
||||
}
|
||||
if psMap[ps.Name] == nil {
|
||||
result = append(result, ps)
|
||||
continue
|
||||
}
|
||||
result = append(result, *psMap[ps.Name])
|
||||
delete(psMap, ps.Name)
|
||||
}
|
||||
// add the new patch sets
|
||||
for _, ps := range psMap {
|
||||
if ps == nil {
|
||||
continue
|
||||
}
|
||||
result = append(result, *ps)
|
||||
}
|
||||
return result
|
||||
}
|
|
@ -1,79 +0,0 @@
|
|||
// SPDX-FileCopyrightText: 2023 The Crossplane Authors <https://crossplane.io>
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package migration
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
)
|
||||
|
||||
func TestSplitPathComponents(t *testing.T) {
|
||||
tests := map[string]struct {
|
||||
want []string
|
||||
}{
|
||||
`m['a.b.c']`: {
|
||||
want: []string{`m['a.b.c']`},
|
||||
},
|
||||
`m["a.b.c"]`: {
|
||||
want: []string{`m["a.b.c"]`},
|
||||
},
|
||||
`m[a.b.c]`: {
|
||||
want: []string{`m[a.b.c]`},
|
||||
},
|
||||
`m[a.b.c.d.e]`: {
|
||||
want: []string{`m[a.b.c.d.e]`},
|
||||
},
|
||||
`m['a.b.c.d.e']`: {
|
||||
want: []string{`m['a.b.c.d.e']`},
|
||||
},
|
||||
`m['a.b']`: {
|
||||
want: []string{`m['a.b']`},
|
||||
},
|
||||
`m['a']`: {
|
||||
want: []string{`m['a']`},
|
||||
},
|
||||
`m['a'].b`: {
|
||||
want: []string{`m['a']`, `b`},
|
||||
},
|
||||
`a`: {
|
||||
want: []string{`a`},
|
||||
},
|
||||
`a.b`: {
|
||||
want: []string{`a`, `b`},
|
||||
},
|
||||
`a.b.c`: {
|
||||
want: []string{`a`, `b`, `c`},
|
||||
},
|
||||
`a.b.c.m['a.b.c']`: {
|
||||
want: []string{`a`, `b`, `c`, `m['a.b.c']`},
|
||||
},
|
||||
`a.b.m['a.b.c'].c`: {
|
||||
want: []string{`a`, `b`, `m['a.b.c']`, `c`},
|
||||
},
|
||||
`m['a.b.c'].a.b.c`: {
|
||||
want: []string{`m['a.b.c']`, `a`, `b`, `c`},
|
||||
},
|
||||
`m[a.b.c].a.b.c`: {
|
||||
want: []string{`m[a.b.c]`, `a`, `b`, `c`},
|
||||
},
|
||||
`m[0]`: {
|
||||
want: []string{`m[0]`},
|
||||
},
|
||||
`a.b.c.m[0]`: {
|
||||
want: []string{`a`, `b`, `c`, `m[0]`},
|
||||
},
|
||||
`m[0].a.b.c`: {
|
||||
want: []string{`m[0]`, `a`, `b`, `c`},
|
||||
},
|
||||
}
|
||||
for name, tt := range tests {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
if diff := cmp.Diff(tt.want, splitPathComponents(name)); diff != "" {
|
||||
t.Errorf("splitPathComponents(%s): -want, +got:\n%s\n", name, diff)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -1,129 +0,0 @@
|
|||
// SPDX-FileCopyrightText: 2023 The Crossplane Authors <https://crossplane.io>
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package migration
|
||||
|
||||
import "github.com/pkg/errors"
|
||||
|
||||
const (
|
||||
// KeyContextDiagnostics is the executor step context key for
|
||||
// storing any extra diagnostics information from
|
||||
// the executor.
|
||||
KeyContextDiagnostics = "diagnostics"
|
||||
)
|
||||
|
||||
// PlanExecutor drives the execution of a plan's steps and
|
||||
// uses the configured `executors` to execute those steps.
|
||||
type PlanExecutor struct {
|
||||
executors []Executor
|
||||
plan Plan
|
||||
callback ExecutorCallback
|
||||
}
|
||||
|
||||
// Action represents an action to be taken by the PlanExecutor.
|
||||
// An Action is dictated by a ExecutorCallback implementation
|
||||
// to the PlanExecutor for each step.
|
||||
type Action int
|
||||
|
||||
const (
|
||||
// ActionContinue tells the PlanExecutor to continue with the execution
|
||||
// of a Step.
|
||||
ActionContinue Action = iota
|
||||
// ActionSkip tells the PlanExecutor to skip the execution
|
||||
// of the current Step.
|
||||
ActionSkip
|
||||
// ActionCancel tells the PlanExecutor to stop executing
|
||||
// the Steps of a Plan.
|
||||
ActionCancel
|
||||
// ActionRepeat tells the PlanExecutor to repeat the execution
|
||||
// of the current Step.
|
||||
ActionRepeat
|
||||
)
|
||||
|
||||
// CallbackResult is the type of a value returned from one of the callback
|
||||
// methods of ExecutorCallback implementations.
|
||||
type CallbackResult struct {
|
||||
Action Action
|
||||
}
|
||||
|
||||
// PlanExecutorOption is a mutator function for setting an option of a
|
||||
// PlanExecutor.
|
||||
type PlanExecutorOption func(executor *PlanExecutor)
|
||||
|
||||
// WithExecutorCallback configures an ExecutorCallback for a PlanExecutor
|
||||
// to be notified as the Plan's Step's are executed.
|
||||
func WithExecutorCallback(cb ExecutorCallback) PlanExecutorOption {
|
||||
return func(pe *PlanExecutor) {
|
||||
pe.callback = cb
|
||||
}
|
||||
}
|
||||
|
||||
// ExecutorCallback is the interface for the callback implementations
|
||||
// to be notified while executing each Step of a migration Plan.
|
||||
type ExecutorCallback interface {
|
||||
// StepToExecute is called just before a migration Plan's Step is executed.
|
||||
// Can be used to cancel the execution of the Plan, or to continue/skip
|
||||
// the Step's execution.
|
||||
StepToExecute(s Step, index int) CallbackResult
|
||||
// StepSucceeded is called after a migration Plan's Step is
|
||||
// successfully executed.
|
||||
// Can be used to cancel the execution of the Plan, or to
|
||||
// continue/skip/repeat the Step's execution.
|
||||
StepSucceeded(s Step, index int, diagnostics any) CallbackResult
|
||||
// StepFailed is called after a migration Plan's Step has
|
||||
// failed to execute.
|
||||
// Can be used to cancel the execution of the Plan, or to
|
||||
// continue/skip/repeat the Step's execution.
|
||||
StepFailed(s Step, index int, diagnostics any, err error) CallbackResult
|
||||
}
|
||||
|
||||
// NewPlanExecutor returns a new plan executor for executing the steps
|
||||
// of a migration plan.
|
||||
func NewPlanExecutor(plan Plan, executors []Executor, opts ...PlanExecutorOption) *PlanExecutor {
|
||||
pe := &PlanExecutor{
|
||||
executors: executors,
|
||||
plan: plan,
|
||||
}
|
||||
for _, o := range opts {
|
||||
o(pe)
|
||||
}
|
||||
return pe
|
||||
}
|
||||
|
||||
func (pe *PlanExecutor) Execute() error { //nolint:gocyclo // easier to follow this way
|
||||
ctx := make(map[string]any)
|
||||
for i := 0; i < len(pe.plan.Spec.Steps); i++ {
|
||||
var r CallbackResult
|
||||
if pe.callback != nil {
|
||||
r = pe.callback.StepToExecute(pe.plan.Spec.Steps[i], i)
|
||||
switch r.Action {
|
||||
case ActionCancel:
|
||||
return nil
|
||||
case ActionSkip:
|
||||
continue
|
||||
case ActionContinue, ActionRepeat:
|
||||
}
|
||||
}
|
||||
|
||||
err := pe.executors[0].Step(pe.plan.Spec.Steps[i], ctx)
|
||||
diag := ctx[KeyContextDiagnostics]
|
||||
if err != nil {
|
||||
if pe.callback != nil {
|
||||
r = pe.callback.StepFailed(pe.plan.Spec.Steps[i], i, diag, err)
|
||||
}
|
||||
} else if pe.callback != nil {
|
||||
r = pe.callback.StepSucceeded(pe.plan.Spec.Steps[i], i, diag)
|
||||
}
|
||||
|
||||
switch r.Action {
|
||||
case ActionCancel:
|
||||
return errors.Wrapf(err, "failed to execute step %q at index %d", pe.plan.Spec.Steps[i].Name, i)
|
||||
case ActionContinue, ActionSkip:
|
||||
continue
|
||||
case ActionRepeat:
|
||||
i--
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -1,536 +0,0 @@
|
|||
// SPDX-FileCopyrightText: 2023 The Crossplane Authors <https://crossplane.io>
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package migration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
"github.com/crossplane/crossplane-runtime/pkg/fieldpath"
|
||||
"github.com/crossplane/crossplane-runtime/pkg/resource"
|
||||
xpv1 "github.com/crossplane/crossplane/apis/apiextensions/v1"
|
||||
xpmetav1 "github.com/crossplane/crossplane/apis/pkg/meta/v1"
|
||||
xpmetav1alpha1 "github.com/crossplane/crossplane/apis/pkg/meta/v1alpha1"
|
||||
xppkgv1 "github.com/crossplane/crossplane/apis/pkg/v1"
|
||||
xppkgv1beta1 "github.com/crossplane/crossplane/apis/pkg/v1beta1"
|
||||
"github.com/pkg/errors"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/util/rand"
|
||||
)
|
||||
|
||||
const (
|
||||
errSourceHasNext = "failed to generate migration plan: Could not check next object from source"
|
||||
errSourceNext = "failed to generate migration plan: Could not get next object from source"
|
||||
errPreProcessFmt = "failed to pre-process the manifest of category %q"
|
||||
errSourceReset = "failed to generate migration plan: Could not get reset the source"
|
||||
errUnstructuredConvert = "failed to convert from unstructured object to v1.Composition"
|
||||
errUnstructuredMarshal = "failed to marshal unstructured object to JSON"
|
||||
errResourceMigrate = "failed to migrate resource"
|
||||
errCompositePause = "failed to pause composite resource"
|
||||
errCompositesEdit = "failed to edit composite resources"
|
||||
errCompositesStart = "failed to start composite resources"
|
||||
errCompositionMigrateFmt = "failed to migrate the composition: %s"
|
||||
errConfigurationMetadataMigrateFmt = "failed to migrate the configuration metadata: %s"
|
||||
errConfigurationPackageMigrateFmt = "failed to migrate the configuration package: %s"
|
||||
errProviderMigrateFmt = "failed to migrate the Provider package: %s"
|
||||
errLockMigrateFmt = "failed to migrate the package lock: %s"
|
||||
errComposedTemplateBase = "failed to migrate the base of a composed template"
|
||||
errComposedTemplateMigrate = "failed to migrate the composed templates of the composition"
|
||||
errResourceOutput = "failed to output migrated resource"
|
||||
errResourceOrphan = "failed to orphan managed resource"
|
||||
errResourceRemoveFinalizer = "failed to remove finalizers of managed resource"
|
||||
errCompositionOutput = "failed to output migrated composition"
|
||||
errCompositeOutput = "failed to output migrated composite"
|
||||
errClaimOutput = "failed to output migrated claim"
|
||||
errClaimsEdit = "failed to edit claims"
|
||||
errPlanGeneration = "failed to generate the migration plan"
|
||||
errPause = "failed to store a paused manifest"
|
||||
errMissingGVK = "managed resource is missing its GVK. Resource converters must set GVKs on any managed resources they newly generate."
|
||||
)
|
||||
|
||||
const (
|
||||
versionV010 = "0.1.0"
|
||||
|
||||
keyCompositionRef = "compositionRef"
|
||||
keyResourceRefs = "resourceRefs"
|
||||
)
|
||||
|
||||
// PlanGeneratorOption configures a PlanGenerator
|
||||
type PlanGeneratorOption func(generator *PlanGenerator)
|
||||
|
||||
// WithErrorOnInvalidPatchSchema returns a PlanGeneratorOption for configuring
|
||||
// whether the PlanGenerator should error and stop the migration plan
|
||||
// generation in case an error is encountered while checking a patch
|
||||
// statement's conformance to the migration source or target.
|
||||
func WithErrorOnInvalidPatchSchema(e bool) PlanGeneratorOption {
|
||||
return func(pg *PlanGenerator) {
|
||||
pg.ErrorOnInvalidPatchSchema = e
|
||||
}
|
||||
}
|
||||
|
||||
// WithSkipGVKs configures the set of GVKs to skip for conversion
|
||||
// during a migration.
|
||||
func WithSkipGVKs(gvk ...schema.GroupVersionKind) PlanGeneratorOption {
|
||||
return func(pg *PlanGenerator) {
|
||||
pg.SkipGVKs = gvk
|
||||
}
|
||||
}
|
||||
|
||||
// WithMultipleSources can be used to configure multiple sources for a
|
||||
// PlanGenerator.
|
||||
func WithMultipleSources(source ...Source) PlanGeneratorOption {
|
||||
return func(pg *PlanGenerator) {
|
||||
pg.source = &sources{backends: source}
|
||||
}
|
||||
}
|
||||
|
||||
// WithEnableConfigurationMigrationSteps enables only
|
||||
// the configuration migration steps.
|
||||
// TODO: to be replaced with a higher abstraction encapsulating
|
||||
// migration scenarios.
|
||||
func WithEnableConfigurationMigrationSteps() PlanGeneratorOption {
|
||||
return func(pg *PlanGenerator) {
|
||||
pg.enabledSteps = getConfigurationMigrationSteps()
|
||||
}
|
||||
}
|
||||
|
||||
func WithEnableOnlyFileSystemAPISteps() PlanGeneratorOption {
|
||||
return func(pg *PlanGenerator) {
|
||||
pg.enabledSteps = getAPIMigrationStepsFileSystemMode()
|
||||
}
|
||||
}
|
||||
|
||||
type sources struct {
|
||||
backends []Source
|
||||
i int
|
||||
}
|
||||
|
||||
func (s *sources) HasNext() (bool, error) {
|
||||
if s.i >= len(s.backends) {
|
||||
return false, nil
|
||||
}
|
||||
ok, err := s.backends[s.i].HasNext()
|
||||
if err != nil || ok {
|
||||
return ok, err
|
||||
}
|
||||
s.i++
|
||||
return s.HasNext()
|
||||
}
|
||||
|
||||
func (s *sources) Next() (UnstructuredWithMetadata, error) {
|
||||
return s.backends[s.i].Next()
|
||||
}
|
||||
|
||||
func (s *sources) Reset() error {
|
||||
for _, src := range s.backends {
|
||||
if err := src.Reset(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
s.i = 0
|
||||
return nil
|
||||
}
|
||||
|
||||
// PlanGenerator generates a migration.Plan reading the manifests available
|
||||
// from `source`, converting managed resources and compositions using the
|
||||
// available `migration.Converter`s registered in the `registry` and
|
||||
// writing the output manifests to the specified `target`.
|
||||
type PlanGenerator struct {
|
||||
source Source
|
||||
target Target
|
||||
registry *Registry
|
||||
subSteps map[step]string
|
||||
enabledSteps []step
|
||||
// Plan is the migration.Plan whose steps are expected
|
||||
// to complete a migration when they're executed in order.
|
||||
Plan Plan
|
||||
// ErrorOnInvalidPatchSchema errors and stops plan generation in case
|
||||
// an error is encountered while checking the conformance of a patch
|
||||
// statement against the migration source or the migration target.
|
||||
ErrorOnInvalidPatchSchema bool
|
||||
// GVKs of managed resources that
|
||||
// should be skipped for conversion during the migration, if no
|
||||
// converters are registered for them. If any of the GVK components
|
||||
// is left empty, it will be a wildcard component.
|
||||
// Exact matching with an empty group name is not possible.
|
||||
SkipGVKs []schema.GroupVersionKind
|
||||
}
|
||||
|
||||
// NewPlanGenerator constructs a new PlanGenerator using the specified
|
||||
// Source and Target and the default converter Registry.
|
||||
func NewPlanGenerator(registry *Registry, source Source, target Target, opts ...PlanGeneratorOption) PlanGenerator {
|
||||
pg := &PlanGenerator{
|
||||
source: &sources{backends: []Source{source}},
|
||||
target: target,
|
||||
registry: registry,
|
||||
subSteps: map[step]string{},
|
||||
enabledSteps: getAPIMigrationSteps(),
|
||||
}
|
||||
for _, o := range opts {
|
||||
o(pg)
|
||||
}
|
||||
return *pg
|
||||
}
|
||||
|
||||
// GeneratePlan generates a migration plan for the manifests available from
|
||||
// the configured Source and writing them to the configured Target using the
|
||||
// configured converter Registry. The generated Plan is available in the
|
||||
// PlanGenerator.Plan variable if the generation is successful
|
||||
// (i.e., no errors are reported).
|
||||
func (pg *PlanGenerator) GeneratePlan() error {
|
||||
pg.Plan.Spec.stepMap = make(map[string]*Step)
|
||||
pg.Plan.Version = versionV010
|
||||
defer pg.commitSteps()
|
||||
if err := pg.preProcess(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := pg.source.Reset(); err != nil {
|
||||
return errors.Wrap(err, errSourceReset)
|
||||
}
|
||||
return errors.Wrap(pg.convert(), errPlanGeneration)
|
||||
}
|
||||
|
||||
func (pg *PlanGenerator) preProcess() error {
|
||||
if len(pg.registry.unstructuredPreProcessors) == 0 {
|
||||
return nil
|
||||
}
|
||||
for hasNext, err := pg.source.HasNext(); ; hasNext, err = pg.source.HasNext() {
|
||||
if err != nil {
|
||||
return errors.Wrap(err, errSourceHasNext)
|
||||
}
|
||||
if !hasNext {
|
||||
break
|
||||
}
|
||||
o, err := pg.source.Next()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, errSourceNext)
|
||||
}
|
||||
for _, pp := range pg.registry.unstructuredPreProcessors[o.Metadata.Category] {
|
||||
if err := pp.PreProcess(o); err != nil {
|
||||
return errors.Wrapf(err, errPreProcessFmt, o.Metadata.Category)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (pg *PlanGenerator) convertPatchSets(o UnstructuredWithMetadata) ([]string, error) {
|
||||
var converted []string
|
||||
for _, psConv := range pg.registry.patchSetConverters {
|
||||
if psConv.re == nil || psConv.converter == nil {
|
||||
continue
|
||||
}
|
||||
if !psConv.re.MatchString(o.Object.GetName()) {
|
||||
continue
|
||||
}
|
||||
c, err := ToComposition(o.Object)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, errUnstructuredConvert)
|
||||
}
|
||||
oldPatchSets := make([]xpv1.PatchSet, len(c.Spec.PatchSets))
|
||||
for i, ps := range c.Spec.PatchSets {
|
||||
oldPatchSets[i] = *ps.DeepCopy()
|
||||
}
|
||||
psMap := convertToMap(c.Spec.PatchSets)
|
||||
if err := psConv.converter.PatchSets(psMap); err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to call PatchSet converter on Composition: %s", c.GetName())
|
||||
}
|
||||
newPatchSets := convertFromMap(psMap, oldPatchSets, true)
|
||||
converted = append(converted, getConvertedPatchSetNames(newPatchSets, oldPatchSets)...)
|
||||
pv := fieldpath.Pave(o.Object.Object)
|
||||
if err := pv.SetValue("spec.patchSets", newPatchSets); err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to set converted patch sets on Composition: %s", c.GetName())
|
||||
}
|
||||
}
|
||||
return converted, nil
|
||||
}
|
||||
|
||||
func (pg *PlanGenerator) categoricalConvert(u *UnstructuredWithMetadata) error {
|
||||
if u.Metadata.Category == categoryUnknown {
|
||||
return nil
|
||||
}
|
||||
source := *u
|
||||
source.Object = *u.Object.DeepCopy()
|
||||
converters := pg.registry.categoricalConverters[u.Metadata.Category]
|
||||
if converters == nil {
|
||||
return nil
|
||||
}
|
||||
// TODO: if a categorical converter does not convert the given object,
|
||||
// we will have a false positive. Better to compute and check
|
||||
// a diff here.
|
||||
for _, converter := range converters {
|
||||
if err := converter.Convert(u); err != nil {
|
||||
return errors.Wrapf(err, "failed to convert unstructured object of category: %s", u.Metadata.Category)
|
||||
}
|
||||
}
|
||||
return pg.stepEditCategory(source, u)
|
||||
}
|
||||
|
||||
func (pg *PlanGenerator) convert() error { //nolint: gocyclo
|
||||
convertedMR := make(map[corev1.ObjectReference][]UnstructuredWithMetadata)
|
||||
convertedComposition := make(map[string]string)
|
||||
var composites []UnstructuredWithMetadata
|
||||
var claims []UnstructuredWithMetadata
|
||||
for hasNext, err := pg.source.HasNext(); ; hasNext, err = pg.source.HasNext() {
|
||||
if err != nil {
|
||||
return errors.Wrap(err, errSourceHasNext)
|
||||
}
|
||||
if !hasNext {
|
||||
break
|
||||
}
|
||||
o, err := pg.source.Next()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, errSourceNext)
|
||||
}
|
||||
|
||||
if err := pg.categoricalConvert(&o); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch gvk := o.Object.GroupVersionKind(); gvk {
|
||||
case xppkgv1.ConfigurationGroupVersionKind:
|
||||
if err := pg.convertConfigurationPackage(o); err != nil {
|
||||
return errors.Wrapf(err, errConfigurationPackageMigrateFmt, o.Object.GetName())
|
||||
}
|
||||
case xpmetav1.ConfigurationGroupVersionKind, xpmetav1alpha1.ConfigurationGroupVersionKind:
|
||||
if err := pg.convertConfigurationMetadata(o); err != nil {
|
||||
return errors.Wrapf(err, errConfigurationMetadataMigrateFmt, o.Object.GetName())
|
||||
}
|
||||
pg.stepBackupAllResources()
|
||||
pg.stepBuildConfiguration()
|
||||
pg.stepPushConfiguration()
|
||||
case xpv1.CompositionGroupVersionKind:
|
||||
target, converted, err := pg.convertComposition(o)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, errCompositionMigrateFmt, o.Object.GetName())
|
||||
}
|
||||
if converted {
|
||||
migratedName := fmt.Sprintf("%s-migrated", o.Object.GetName())
|
||||
convertedComposition[o.Object.GetName()] = migratedName
|
||||
target.Object.SetName(migratedName)
|
||||
if err := pg.stepNewComposition(target); err != nil {
|
||||
return errors.Wrapf(err, errCompositionMigrateFmt, o.Object.GetName())
|
||||
}
|
||||
}
|
||||
case xppkgv1.ProviderGroupVersionKind:
|
||||
isConverted, err := pg.convertProviderPackage(o)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, errProviderMigrateFmt)
|
||||
}
|
||||
if isConverted {
|
||||
if err := pg.stepDeleteMonolith(o); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
case xppkgv1beta1.LockGroupVersionKind:
|
||||
if err := pg.convertPackageLock(o); err != nil {
|
||||
return errors.Wrapf(err, errLockMigrateFmt, o.Object.GetName())
|
||||
}
|
||||
default:
|
||||
if o.Metadata.Category == CategoryComposite {
|
||||
if err := pg.stepPauseComposite(&o); err != nil {
|
||||
return errors.Wrap(err, errCompositePause)
|
||||
}
|
||||
composites = append(composites, o)
|
||||
continue
|
||||
}
|
||||
|
||||
if o.Metadata.Category == CategoryClaim {
|
||||
claims = append(claims, o)
|
||||
continue
|
||||
}
|
||||
|
||||
targets, converted, err := pg.convertResource(o, false)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, errResourceMigrate)
|
||||
}
|
||||
if converted {
|
||||
convertedMR[corev1.ObjectReference{
|
||||
Kind: gvk.Kind,
|
||||
Name: o.Object.GetName(),
|
||||
APIVersion: gvk.GroupVersion().String(),
|
||||
}] = targets
|
||||
for _, tu := range targets {
|
||||
tu := tu
|
||||
if err := pg.stepNewManagedResource(&tu); err != nil {
|
||||
return errors.Wrap(err, errResourceMigrate)
|
||||
}
|
||||
if err := pg.stepStartManagedResource(&tu); err != nil {
|
||||
return errors.Wrap(err, errResourceMigrate)
|
||||
}
|
||||
}
|
||||
} else if _, ok, _ := toManagedResource(pg.registry.scheme, o.Object); ok {
|
||||
if err := pg.stepStartManagedResource(&o); err != nil {
|
||||
return errors.Wrap(err, errResourceMigrate)
|
||||
}
|
||||
}
|
||||
}
|
||||
if err := pg.addStepsForManagedResource(&o); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := pg.stepEditComposites(composites, convertedMR, convertedComposition); err != nil {
|
||||
return errors.Wrap(err, errCompositesEdit)
|
||||
}
|
||||
if err := pg.stepStartComposites(composites); err != nil {
|
||||
return errors.Wrap(err, errCompositesStart)
|
||||
}
|
||||
if err := pg.stepEditClaims(claims, convertedComposition); err != nil {
|
||||
return errors.Wrap(err, errClaimsEdit)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (pg *PlanGenerator) convertResource(o UnstructuredWithMetadata, compositionContext bool) ([]UnstructuredWithMetadata, bool, error) {
|
||||
gvk := o.Object.GroupVersionKind()
|
||||
conv := pg.registry.resourceConverters[gvk]
|
||||
if conv == nil {
|
||||
return []UnstructuredWithMetadata{o}, false, nil
|
||||
}
|
||||
// we have already ensured that the GVK belongs to a managed resource type
|
||||
mg, _, err := toManagedResource(pg.registry.scheme, o.Object)
|
||||
if err != nil {
|
||||
return nil, false, errors.Wrap(err, errResourceMigrate)
|
||||
}
|
||||
if pg.registry.resourcePreProcessors != nil {
|
||||
for _, pp := range pg.registry.resourcePreProcessors {
|
||||
if err = pp.ResourcePreProcessor(mg); err != nil {
|
||||
return nil, false, errors.Wrap(err, errResourceMigrate)
|
||||
}
|
||||
}
|
||||
}
|
||||
resources, err := conv.Resource(mg)
|
||||
if err != nil {
|
||||
return nil, false, errors.Wrap(err, errResourceMigrate)
|
||||
}
|
||||
if err := assertGVK(resources); err != nil {
|
||||
return nil, true, errors.Wrap(err, errResourceMigrate)
|
||||
}
|
||||
if !compositionContext {
|
||||
assertMetadataName(mg.GetName(), resources)
|
||||
}
|
||||
converted := make([]UnstructuredWithMetadata, 0, len(resources))
|
||||
for _, mg := range resources {
|
||||
converted = append(converted, UnstructuredWithMetadata{
|
||||
Object: ToSanitizedUnstructured(mg),
|
||||
Metadata: o.Metadata,
|
||||
})
|
||||
}
|
||||
return converted, true, nil
|
||||
}
|
||||
|
||||
func assertGVK(resources []resource.Managed) error {
|
||||
for _, r := range resources {
|
||||
if reflect.ValueOf(r.GetObjectKind().GroupVersionKind()).IsZero() {
|
||||
return errors.New(errMissingGVK)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func assertMetadataName(parentName string, resources []resource.Managed) {
|
||||
for i, r := range resources {
|
||||
if len(r.GetName()) != 0 || len(r.GetGenerateName()) != 0 {
|
||||
continue
|
||||
}
|
||||
resources[i].SetGenerateName(fmt.Sprintf("%s-", parentName))
|
||||
}
|
||||
}
|
||||
|
||||
func (pg *PlanGenerator) convertComposition(o UnstructuredWithMetadata) (*UnstructuredWithMetadata, bool, error) { //nolint:gocyclo
|
||||
convertedPS, err := pg.convertPatchSets(o)
|
||||
if err != nil {
|
||||
return nil, false, errors.Wrap(err, "failed to convert patch sets")
|
||||
}
|
||||
comp, err := ToComposition(o.Object)
|
||||
if err != nil {
|
||||
return nil, false, errors.Wrap(err, errUnstructuredConvert)
|
||||
}
|
||||
var targetResources []*xpv1.ComposedTemplate
|
||||
isConverted := false
|
||||
for _, cmp := range comp.Spec.Resources {
|
||||
u, err := FromRawExtension(cmp.Base)
|
||||
if err != nil {
|
||||
return nil, false, errors.Wrapf(err, errCompositionMigrateFmt, o.Object.GetName())
|
||||
}
|
||||
gvk := u.GroupVersionKind()
|
||||
converted, ok, err := pg.convertResource(UnstructuredWithMetadata{
|
||||
Object: u,
|
||||
Metadata: o.Metadata,
|
||||
}, true)
|
||||
if err != nil {
|
||||
return nil, false, errors.Wrap(err, errComposedTemplateBase)
|
||||
}
|
||||
isConverted = isConverted || ok
|
||||
cmps := make([]*xpv1.ComposedTemplate, 0, len(converted))
|
||||
sourceNameUsed := false
|
||||
for _, u := range converted {
|
||||
buff, err := u.Object.MarshalJSON()
|
||||
if err != nil {
|
||||
return nil, false, errors.Wrap(err, errUnstructuredMarshal)
|
||||
}
|
||||
c := cmp.DeepCopy()
|
||||
c.Base = runtime.RawExtension{
|
||||
Raw: buff,
|
||||
}
|
||||
if err := pg.setDefaultsOnTargetTemplate(cmp.Name, &sourceNameUsed, gvk, u.Object.GroupVersionKind(), c, comp.Spec.PatchSets, convertedPS); err != nil {
|
||||
return nil, false, errors.Wrap(err, errComposedTemplateMigrate)
|
||||
}
|
||||
cmps = append(cmps, c)
|
||||
}
|
||||
conv := pg.registry.templateConverters[gvk]
|
||||
if conv != nil {
|
||||
if err := conv.ComposedTemplate(cmp, cmps...); err != nil {
|
||||
return nil, false, errors.Wrap(err, errComposedTemplateMigrate)
|
||||
}
|
||||
}
|
||||
targetResources = append(targetResources, cmps...)
|
||||
}
|
||||
comp.Spec.Resources = make([]xpv1.ComposedTemplate, 0, len(targetResources))
|
||||
for _, cmp := range targetResources {
|
||||
comp.Spec.Resources = append(comp.Spec.Resources, *cmp)
|
||||
}
|
||||
return &UnstructuredWithMetadata{
|
||||
Object: ToSanitizedUnstructured(&comp),
|
||||
Metadata: o.Metadata,
|
||||
}, isConverted, nil
|
||||
}
|
||||
|
||||
func (pg *PlanGenerator) isGVKSkipped(sourceGVK schema.GroupVersionKind) bool {
|
||||
for _, gvk := range pg.SkipGVKs {
|
||||
if (len(gvk.Group) == 0 || gvk.Group == sourceGVK.Group) &&
|
||||
(len(gvk.Version) == 0 || gvk.Version == sourceGVK.Version) &&
|
||||
(len(gvk.Kind) == 0 || gvk.Kind == sourceGVK.Kind) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (pg *PlanGenerator) setDefaultsOnTargetTemplate(sourceName *string, sourceNameUsed *bool, gvkSource, gvkTarget schema.GroupVersionKind, target *xpv1.ComposedTemplate, patchSets []xpv1.PatchSet, convertedPS []string) error {
|
||||
if pg.isGVKSkipped(gvkSource) {
|
||||
return nil
|
||||
}
|
||||
// remove invalid patches that do not conform to the migration target's schema
|
||||
if err := pg.removeInvalidPatches(gvkSource, gvkTarget, patchSets, target, convertedPS); err != nil {
|
||||
return errors.Wrap(err, "failed to set the defaults on the migration target composed template")
|
||||
}
|
||||
if *sourceNameUsed || gvkSource.Kind != gvkTarget.Kind {
|
||||
if sourceName != nil && len(*sourceName) > 0 {
|
||||
targetName := fmt.Sprintf("%s-%s", *sourceName, rand.String(5))
|
||||
target.Name = &targetName
|
||||
}
|
||||
} else {
|
||||
*sourceNameUsed = true
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
}
|
|
@ -1,646 +0,0 @@
|
|||
// SPDX-FileCopyrightText: 2023 The Crossplane Authors <https://crossplane.io>
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package migration
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"testing"
|
||||
|
||||
xpresource "github.com/crossplane/crossplane-runtime/pkg/resource"
|
||||
"github.com/crossplane/crossplane-runtime/pkg/test"
|
||||
v1 "github.com/crossplane/crossplane/apis/apiextensions/v1"
|
||||
xpmetav1 "github.com/crossplane/crossplane/apis/pkg/meta/v1"
|
||||
xpmetav1alpha1 "github.com/crossplane/crossplane/apis/pkg/meta/v1alpha1"
|
||||
xppkgv1 "github.com/crossplane/crossplane/apis/pkg/v1"
|
||||
xppkgv1beta1 "github.com/crossplane/crossplane/apis/pkg/v1beta1"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/google/go-cmp/cmp/cmpopts"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/util/yaml"
|
||||
"k8s.io/utils/ptr"
|
||||
k8syaml "sigs.k8s.io/yaml"
|
||||
|
||||
"github.com/crossplane/upjet/pkg/migration/fake"
|
||||
)
|
||||
|
||||
func TestGeneratePlan(t *testing.T) {
|
||||
type fields struct {
|
||||
source Source
|
||||
target *testTarget
|
||||
registry *Registry
|
||||
opts []PlanGeneratorOption
|
||||
}
|
||||
type want struct {
|
||||
err error
|
||||
migrationPlanPath string
|
||||
// names of resource files to be loaded
|
||||
migratedResourceNames []string
|
||||
preProcessResults map[Category][]string
|
||||
}
|
||||
tests := map[string]struct {
|
||||
fields fields
|
||||
want want
|
||||
}{
|
||||
"EmptyPlan": {
|
||||
fields: fields{
|
||||
source: newTestSource(map[string]Metadata{}),
|
||||
target: newTestTarget(),
|
||||
registry: getRegistry(),
|
||||
},
|
||||
want: want{},
|
||||
},
|
||||
"PreProcess": {
|
||||
fields: fields{
|
||||
source: newTestSource(map[string]Metadata{
|
||||
"testdata/plan/composition.yaml": {Category: CategoryComposition},
|
||||
}),
|
||||
target: newTestTarget(),
|
||||
registry: getRegistry(withPreProcessor(CategoryComposition, &preProcessor{})),
|
||||
},
|
||||
want: want{
|
||||
preProcessResults: map[Category][]string{
|
||||
CategoryComposition: {"example.compositions.apiextensions.crossplane.io_v1"},
|
||||
},
|
||||
},
|
||||
},
|
||||
"PlanWithManagedResourceAndClaim": {
|
||||
fields: fields{
|
||||
source: newTestSource(map[string]Metadata{
|
||||
"testdata/plan/sourcevpc.yaml": {Category: CategoryManaged},
|
||||
"testdata/plan/claim.yaml": {Category: CategoryClaim},
|
||||
"testdata/plan/composition.yaml": {},
|
||||
"testdata/plan/xrd.yaml": {},
|
||||
"testdata/plan/xr.yaml": {Category: CategoryComposite}}),
|
||||
target: newTestTarget(),
|
||||
registry: getRegistry(
|
||||
withPreProcessor(CategoryManaged, &preProcessor{}),
|
||||
withDelegatingConverter(fake.MigrationSourceGVK, delegatingConverter{
|
||||
rFn: func(mg xpresource.Managed) ([]xpresource.Managed, error) {
|
||||
s := mg.(*fake.MigrationSourceObject)
|
||||
t := &fake.MigrationTargetObject{}
|
||||
if _, err := CopyInto(s, t, fake.MigrationTargetGVK, "spec.forProvider.tags", "mockManaged"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
t.Spec.ForProvider.Tags = make(map[string]string, len(s.Spec.ForProvider.Tags))
|
||||
for _, tag := range s.Spec.ForProvider.Tags {
|
||||
v := tag.Value
|
||||
t.Spec.ForProvider.Tags[tag.Key] = v
|
||||
}
|
||||
return []xpresource.Managed{
|
||||
t,
|
||||
}, nil
|
||||
},
|
||||
cmpFn: func(_ v1.ComposedTemplate, convertedTemplates ...*v1.ComposedTemplate) error {
|
||||
// convert patches in the migration target composed templates
|
||||
for i := range convertedTemplates {
|
||||
convertedTemplates[i].Patches = append([]v1.Patch{
|
||||
{FromFieldPath: ptrFromString("spec.parameters.tagValue"),
|
||||
ToFieldPath: ptrFromString(`spec.forProvider.tags["key1"]`),
|
||||
}, {
|
||||
FromFieldPath: ptrFromString("spec.parameters.tagValue"),
|
||||
ToFieldPath: ptrFromString(`spec.forProvider.tags["key2"]`),
|
||||
},
|
||||
}, convertedTemplates[i].Patches...)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}),
|
||||
withPatchSetConverter(patchSetConverter{
|
||||
re: AllCompositions,
|
||||
converter: &testConverter{},
|
||||
})),
|
||||
},
|
||||
want: want{
|
||||
migrationPlanPath: "testdata/plan/generated/migration_plan.yaml",
|
||||
migratedResourceNames: []string{
|
||||
"pause-managed/sample-vpc.vpcs.fakesourceapi.yaml",
|
||||
"edit-claims/my-resource.myresources.test.com.yaml",
|
||||
"start-managed/sample-vpc.vpcs.faketargetapi.yaml",
|
||||
"pause-composites/my-resource-dwjgh.xmyresources.test.com.yaml",
|
||||
"edit-composites/my-resource-dwjgh.xmyresources.test.com.yaml",
|
||||
"deletion-policy-orphan/sample-vpc.vpcs.fakesourceapi.yaml",
|
||||
"remove-finalizers/sample-vpc.vpcs.fakesourceapi.yaml",
|
||||
"new-compositions/example-migrated.compositions.apiextensions.crossplane.io.yaml",
|
||||
"start-composites/my-resource-dwjgh.xmyresources.test.com.yaml",
|
||||
"create-new-managed/sample-vpc.vpcs.faketargetapi.yaml",
|
||||
},
|
||||
preProcessResults: map[Category][]string{
|
||||
CategoryManaged: {"sample-vpc.vpcs.fakesourceapi_v1alpha1"},
|
||||
},
|
||||
},
|
||||
},
|
||||
"PlanWithManagedResourceAndClaimForFileSystemMode": {
|
||||
fields: fields{
|
||||
source: newTestSource(map[string]Metadata{
|
||||
"testdata/plan/sourcevpc.yaml": {Category: CategoryManaged},
|
||||
"testdata/plan/claim.yaml": {Category: CategoryClaim},
|
||||
"testdata/plan/composition.yaml": {},
|
||||
"testdata/plan/xrd.yaml": {},
|
||||
"testdata/plan/xr.yaml": {Category: CategoryComposite}}),
|
||||
target: newTestTarget(),
|
||||
registry: getRegistry(
|
||||
withPreProcessor(CategoryManaged, &preProcessor{}),
|
||||
withDelegatingConverter(fake.MigrationSourceGVK, delegatingConverter{
|
||||
rFn: func(mg xpresource.Managed) ([]xpresource.Managed, error) {
|
||||
s := mg.(*fake.MigrationSourceObject)
|
||||
t := &fake.MigrationTargetObject{}
|
||||
if _, err := CopyInto(s, t, fake.MigrationTargetGVK, "spec.forProvider.tags", "mockManaged"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
t.Spec.ForProvider.Tags = make(map[string]string, len(s.Spec.ForProvider.Tags))
|
||||
for _, tag := range s.Spec.ForProvider.Tags {
|
||||
v := tag.Value
|
||||
t.Spec.ForProvider.Tags[tag.Key] = v
|
||||
}
|
||||
return []xpresource.Managed{
|
||||
t,
|
||||
}, nil
|
||||
},
|
||||
cmpFn: func(_ v1.ComposedTemplate, convertedTemplates ...*v1.ComposedTemplate) error {
|
||||
// convert patches in the migration target composed templates
|
||||
for i := range convertedTemplates {
|
||||
convertedTemplates[i].Patches = append([]v1.Patch{
|
||||
{FromFieldPath: ptrFromString("spec.parameters.tagValue"),
|
||||
ToFieldPath: ptrFromString(`spec.forProvider.tags["key1"]`),
|
||||
}, {
|
||||
FromFieldPath: ptrFromString("spec.parameters.tagValue"),
|
||||
ToFieldPath: ptrFromString(`spec.forProvider.tags["key2"]`),
|
||||
},
|
||||
}, convertedTemplates[i].Patches...)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}),
|
||||
withPatchSetConverter(patchSetConverter{
|
||||
re: AllCompositions,
|
||||
converter: &testConverter{},
|
||||
})),
|
||||
opts: []PlanGeneratorOption{WithEnableOnlyFileSystemAPISteps()},
|
||||
},
|
||||
want: want{
|
||||
migrationPlanPath: "testdata/plan/generated/migration_plan_filesystem.yaml",
|
||||
migratedResourceNames: []string{
|
||||
"edit-claims/my-resource.myresources.test.com.yaml",
|
||||
"start-managed/sample-vpc.vpcs.faketargetapi.yaml",
|
||||
"edit-composites/my-resource-dwjgh.xmyresources.test.com.yaml",
|
||||
"new-compositions/example-migrated.compositions.apiextensions.crossplane.io.yaml",
|
||||
"start-composites/my-resource-dwjgh.xmyresources.test.com.yaml",
|
||||
"create-new-managed/sample-vpc.vpcs.faketargetapi.yaml",
|
||||
},
|
||||
preProcessResults: map[Category][]string{
|
||||
CategoryManaged: {"sample-vpc.vpcs.fakesourceapi_v1alpha1"},
|
||||
},
|
||||
},
|
||||
},
|
||||
"PlanWithConfigurationMetaV1": {
|
||||
fields: fields{
|
||||
source: newTestSource(map[string]Metadata{
|
||||
"testdata/plan/configurationv1.yaml": {}}),
|
||||
target: newTestTarget(),
|
||||
registry: getRegistry(
|
||||
withConfigurationMetadataConverter(configurationMetadataConverter{
|
||||
re: AllConfigurations,
|
||||
converter: &configurationMetaTestConverter{},
|
||||
})),
|
||||
opts: []PlanGeneratorOption{WithEnableConfigurationMigrationSteps()},
|
||||
},
|
||||
want: want{
|
||||
migrationPlanPath: "testdata/plan/generated/configurationv1_migration_plan.yaml",
|
||||
migratedResourceNames: []string{
|
||||
"edit-configuration-metadata/platform-ref-aws.configurations.meta.pkg.crossplane.io_v1.yaml",
|
||||
},
|
||||
},
|
||||
},
|
||||
"PlanWithConfigurationMetaV1Alpha1": {
|
||||
fields: fields{
|
||||
source: newTestSource(map[string]Metadata{
|
||||
"testdata/plan/configurationv1alpha1.yaml": {}}),
|
||||
target: newTestTarget(),
|
||||
registry: getRegistry(
|
||||
withConfigurationMetadataConverter(configurationMetadataConverter{
|
||||
re: AllConfigurations,
|
||||
converter: &configurationMetaTestConverter{},
|
||||
})),
|
||||
opts: []PlanGeneratorOption{WithEnableConfigurationMigrationSteps()},
|
||||
},
|
||||
want: want{
|
||||
migrationPlanPath: "testdata/plan/generated/configurationv1alpha1_migration_plan.yaml",
|
||||
migratedResourceNames: []string{
|
||||
"edit-configuration-metadata/platform-ref-aws.configurations.meta.pkg.crossplane.io_v1alpha1.yaml",
|
||||
},
|
||||
},
|
||||
},
|
||||
"PlanWithProviderPackageV1": {
|
||||
fields: fields{
|
||||
source: newTestSource(map[string]Metadata{
|
||||
"testdata/plan/providerv1.yaml": {}}),
|
||||
target: newTestTarget(),
|
||||
registry: getRegistry(
|
||||
withProviderPackageConverter(providerPackageConverter{
|
||||
re: regexp.MustCompile(`xpkg.upbound.io/upbound/provider-aws:.+`),
|
||||
converter: &monolithProviderToFamilyConfigConverter{},
|
||||
}),
|
||||
withProviderPackageConverter(providerPackageConverter{
|
||||
re: regexp.MustCompile(`xpkg.upbound.io/upbound/provider-aws:.+`),
|
||||
converter: &monolithicProviderToSSOPConverter{},
|
||||
})),
|
||||
opts: []PlanGeneratorOption{WithEnableConfigurationMigrationSteps()},
|
||||
},
|
||||
want: want{
|
||||
migrationPlanPath: "testdata/plan/generated/providerv1_migration_plan.yaml",
|
||||
migratedResourceNames: []string{
|
||||
"new-ssop/provider-family-aws.providers.pkg.crossplane.io_v1.yaml",
|
||||
"new-ssop/provider-aws-ec2.providers.pkg.crossplane.io_v1.yaml",
|
||||
"new-ssop/provider-aws-eks.providers.pkg.crossplane.io_v1.yaml",
|
||||
"activate-ssop/provider-family-aws.providers.pkg.crossplane.io_v1.yaml",
|
||||
"activate-ssop/provider-aws-ec2.providers.pkg.crossplane.io_v1.yaml",
|
||||
"activate-ssop/provider-aws-eks.providers.pkg.crossplane.io_v1.yaml",
|
||||
},
|
||||
},
|
||||
},
|
||||
"PlanForConfigurationPackageMigration": {
|
||||
fields: fields{
|
||||
source: newTestSource(map[string]Metadata{
|
||||
"testdata/plan/providerv1.yaml": {},
|
||||
"testdata/plan/configurationv1.yaml": {},
|
||||
"testdata/plan/configurationpkgv1.yaml": {},
|
||||
"testdata/plan/lockv1beta1.yaml": {},
|
||||
"testdata/plan/sourcevpc.yaml": {Category: CategoryManaged},
|
||||
"testdata/plan/sourcevpc2.yaml": {Category: CategoryManaged},
|
||||
}),
|
||||
target: newTestTarget(),
|
||||
registry: getRegistry(
|
||||
withConfigurationMetadataConverter(configurationMetadataConverter{
|
||||
re: AllConfigurations,
|
||||
converter: &configurationMetaTestConverter{},
|
||||
}),
|
||||
withConfigurationPackageConverter(configurationPackageConverter{
|
||||
re: regexp.MustCompile(`xpkg.upbound.io/upbound/provider-ref-aws:.+`),
|
||||
converter: &configurationPackageTestConverter{},
|
||||
}),
|
||||
withProviderPackageConverter(providerPackageConverter{
|
||||
re: regexp.MustCompile(`xpkg.upbound.io/upbound/provider-aws:.+`),
|
||||
converter: &monolithProviderToFamilyConfigConverter{},
|
||||
}),
|
||||
withProviderPackageConverter(providerPackageConverter{
|
||||
re: regexp.MustCompile(`xpkg.upbound.io/upbound/provider-aws:.+`),
|
||||
converter: &monolithicProviderToSSOPConverter{},
|
||||
}),
|
||||
withPackageLockConverter(packageLockConverter{
|
||||
re: CrossplaneLockName,
|
||||
converter: &lockConverter{},
|
||||
}),
|
||||
),
|
||||
opts: []PlanGeneratorOption{WithEnableConfigurationMigrationSteps()},
|
||||
},
|
||||
want: want{
|
||||
migrationPlanPath: "testdata/plan/generated/configurationv1_pkg_migration_plan.yaml",
|
||||
migratedResourceNames: []string{
|
||||
"disable-dependency-resolution/platform-ref-aws.configurations.pkg.crossplane.io_v1.yaml",
|
||||
"edit-configuration-package/platform-ref-aws.configurations.pkg.crossplane.io_v1.yaml",
|
||||
"enable-dependency-resolution/platform-ref-aws.configurations.pkg.crossplane.io_v1.yaml",
|
||||
"edit-configuration-metadata/platform-ref-aws.configurations.meta.pkg.crossplane.io_v1.yaml",
|
||||
"new-ssop/provider-family-aws.providers.pkg.crossplane.io_v1.yaml",
|
||||
"new-ssop/provider-aws-ec2.providers.pkg.crossplane.io_v1.yaml",
|
||||
"new-ssop/provider-aws-eks.providers.pkg.crossplane.io_v1.yaml",
|
||||
"activate-ssop/provider-family-aws.providers.pkg.crossplane.io_v1.yaml",
|
||||
"activate-ssop/provider-aws-ec2.providers.pkg.crossplane.io_v1.yaml",
|
||||
"activate-ssop/provider-aws-eks.providers.pkg.crossplane.io_v1.yaml",
|
||||
"edit-package-lock/lock.locks.pkg.crossplane.io_v1beta1.yaml",
|
||||
"deletion-policy-orphan/sample-vpc.vpcs.fakesourceapi_v1alpha1.yaml",
|
||||
"deletion-policy-delete/sample-vpc.vpcs.fakesourceapi_v1alpha1.yaml",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for name, tt := range tests {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
pg := NewPlanGenerator(tt.fields.registry, tt.fields.source, tt.fields.target, tt.fields.opts...)
|
||||
err := pg.GeneratePlan()
|
||||
// compare error state
|
||||
if diff := cmp.Diff(tt.want.err, err, test.EquateErrors()); diff != "" {
|
||||
t.Fatalf("GeneratePlan(): -wantError, +gotError: %s", diff)
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// compare preprocessor results
|
||||
for c, results := range tt.want.preProcessResults {
|
||||
pps := tt.fields.registry.unstructuredPreProcessors[c]
|
||||
if len(pps) != 1 {
|
||||
t.Fatalf("One pre-processor must have been registered for category: %s", c)
|
||||
}
|
||||
pp := pps[0].(*preProcessor)
|
||||
if diff := cmp.Diff(results, pp.results); diff != "" {
|
||||
t.Errorf("GeneratePlan(): -wantPreProcessorResults, +gotPreProcessorResults: %s", diff)
|
||||
}
|
||||
}
|
||||
// compare generated plan with the expected plan
|
||||
p, err := loadPlan(tt.want.migrationPlanPath)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to load plan file from path %s: %v", tt.want.migrationPlanPath, err)
|
||||
}
|
||||
if diff := cmp.Diff(p, &pg.Plan, cmpopts.IgnoreUnexported(Spec{})); diff != "" {
|
||||
t.Errorf("GeneratePlan(): -wantPlan, +gotPlan: %s", diff)
|
||||
}
|
||||
// compare generated migration files with the expected ones
|
||||
for _, name := range tt.want.migratedResourceNames {
|
||||
path := filepath.Join("testdata/plan/generated", name)
|
||||
buff, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to read a generated migration resource from path %s: %v", path, err)
|
||||
}
|
||||
u := unstructured.Unstructured{}
|
||||
if err := k8syaml.Unmarshal(buff, &u); err != nil {
|
||||
t.Fatalf("Failed to unmarshal a generated migration resource from path %s: %v", path, err)
|
||||
}
|
||||
gU, ok := tt.fields.target.targetManifests[name]
|
||||
if !ok {
|
||||
t.Errorf("GeneratePlan(): Expected generated migration resource file not found: %s", name)
|
||||
continue
|
||||
}
|
||||
removeNilValuedKeys(u.Object)
|
||||
if diff := cmp.Diff(u, gU.Object); diff != "" {
|
||||
t.Errorf("GeneratePlan(): -wantMigratedResource, +gotMigratedResource with name %q: %s", name, diff)
|
||||
}
|
||||
delete(tt.fields.target.targetManifests, name)
|
||||
}
|
||||
// check for unexpected generated migration files
|
||||
for name := range tt.fields.target.targetManifests {
|
||||
t.Errorf("GeneratePlan(): Unexpected generated migration file: %s", name)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
type testSource struct {
|
||||
sourceManifests map[string]Metadata
|
||||
paths []string
|
||||
index int
|
||||
}
|
||||
|
||||
func newTestSource(sourceManifests map[string]Metadata) *testSource {
|
||||
result := &testSource{sourceManifests: sourceManifests}
|
||||
result.paths = make([]string, 0, len(result.sourceManifests))
|
||||
for k := range result.sourceManifests {
|
||||
result.paths = append(result.paths, k)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (f *testSource) HasNext() (bool, error) {
|
||||
return f.index <= len(f.paths)-1, nil
|
||||
}
|
||||
|
||||
func (f *testSource) Next() (UnstructuredWithMetadata, error) {
|
||||
um := UnstructuredWithMetadata{
|
||||
Metadata: f.sourceManifests[f.paths[f.index]],
|
||||
Object: unstructured.Unstructured{},
|
||||
}
|
||||
um.Metadata.Path = f.paths[f.index]
|
||||
buff, err := os.ReadFile(f.paths[f.index])
|
||||
if err != nil {
|
||||
return um, err
|
||||
}
|
||||
decoder := yaml.NewYAMLOrJSONDecoder(bytes.NewBufferString(string(buff)), 1024)
|
||||
if err := decoder.Decode(&um.Object); err != nil {
|
||||
return um, err
|
||||
}
|
||||
f.index++
|
||||
return um, nil
|
||||
}
|
||||
|
||||
func (f *testSource) Reset() error {
|
||||
f.index = 0
|
||||
return nil
|
||||
}
|
||||
|
||||
type testTarget struct {
|
||||
targetManifests map[string]UnstructuredWithMetadata
|
||||
}
|
||||
|
||||
func newTestTarget() *testTarget {
|
||||
return &testTarget{
|
||||
targetManifests: make(map[string]UnstructuredWithMetadata),
|
||||
}
|
||||
}
|
||||
|
||||
func (f *testTarget) Put(o UnstructuredWithMetadata) error {
|
||||
f.targetManifests[o.Metadata.Path] = o
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *testTarget) Delete(o UnstructuredWithMetadata) error {
|
||||
delete(f.targetManifests, o.Metadata.Path)
|
||||
return nil
|
||||
}
|
||||
|
||||
// can be utilized to populate test artifacts
|
||||
/*func (f *testTarget) dumpFiles(parentDir string) error {
|
||||
for f, u := range f.targetManifests {
|
||||
path := filepath.Join(parentDir, f)
|
||||
buff, err := k8syaml.Marshal(u.Object.Object)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := os.WriteFile(path, buff, 0o600); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}*/
|
||||
|
||||
type testConverter struct{}
|
||||
|
||||
func (f *testConverter) PatchSets(psMap map[string]*v1.PatchSet) error {
|
||||
psMap["ps1"].Patches[0].ToFieldPath = ptrFromString(`spec.forProvider.tags["key3"]`)
|
||||
psMap["ps6"].Patches[0].ToFieldPath = ptrFromString(`spec.forProvider.tags["key4"]`)
|
||||
return nil
|
||||
}
|
||||
|
||||
func ptrFromString(s string) *string {
|
||||
return &s
|
||||
}
|
||||
|
||||
type registryOption func(*Registry)
|
||||
|
||||
func withDelegatingConverter(gvk schema.GroupVersionKind, d delegatingConverter) registryOption {
|
||||
return func(r *Registry) {
|
||||
r.RegisterAPIConversionFunctions(gvk, d.rFn, d.cmpFn, nil)
|
||||
}
|
||||
}
|
||||
|
||||
func withPatchSetConverter(c patchSetConverter) registryOption {
|
||||
return func(r *Registry) {
|
||||
r.RegisterPatchSetConverter(c.re, c.converter)
|
||||
}
|
||||
}
|
||||
|
||||
func withConfigurationMetadataConverter(c configurationMetadataConverter) registryOption {
|
||||
return func(r *Registry) {
|
||||
r.RegisterConfigurationMetadataConverter(c.re, c.converter)
|
||||
}
|
||||
}
|
||||
|
||||
func withConfigurationPackageConverter(c configurationPackageConverter) registryOption {
|
||||
return func(r *Registry) {
|
||||
r.RegisterConfigurationPackageConverter(c.re, c.converter)
|
||||
}
|
||||
}
|
||||
|
||||
func withProviderPackageConverter(c providerPackageConverter) registryOption {
|
||||
return func(r *Registry) {
|
||||
r.RegisterProviderPackageConverter(c.re, c.converter)
|
||||
}
|
||||
}
|
||||
|
||||
func withPackageLockConverter(c packageLockConverter) registryOption {
|
||||
return func(r *Registry) {
|
||||
r.RegisterPackageLockConverter(c.re, c.converter)
|
||||
}
|
||||
}
|
||||
|
||||
func withPreProcessor(c Category, pp UnstructuredPreProcessor) registryOption {
|
||||
return func(r *Registry) {
|
||||
r.RegisterPreProcessor(c, pp)
|
||||
}
|
||||
}
|
||||
|
||||
func getRegistry(opts ...registryOption) *Registry {
|
||||
scheme := runtime.NewScheme()
|
||||
scheme.AddKnownTypeWithName(fake.MigrationSourceGVK, &fake.MigrationSourceObject{})
|
||||
scheme.AddKnownTypeWithName(fake.MigrationTargetGVK, &fake.MigrationTargetObject{})
|
||||
r := NewRegistry(scheme)
|
||||
for _, o := range opts {
|
||||
o(r)
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func loadPlan(planPath string) (*Plan, error) {
|
||||
if planPath == "" {
|
||||
return emptyPlan(), nil
|
||||
}
|
||||
buff, err := os.ReadFile(planPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
p := &Plan{}
|
||||
return p, k8syaml.Unmarshal(buff, p)
|
||||
}
|
||||
|
||||
func emptyPlan() *Plan {
|
||||
return &Plan{
|
||||
Version: versionV010,
|
||||
}
|
||||
}
|
||||
|
||||
type configurationPackageTestConverter struct{}
|
||||
|
||||
func (c *configurationPackageTestConverter) ConfigurationPackageV1(pkg *xppkgv1.Configuration) error {
|
||||
pkg.Spec.Package = "xpkg.upbound.io/upbound/provider-ref-aws:v0.2.0-ssop"
|
||||
return nil
|
||||
}
|
||||
|
||||
type configurationMetaTestConverter struct{}
|
||||
|
||||
func (cc *configurationMetaTestConverter) ConfigurationMetadataV1(c *xpmetav1.Configuration) error {
|
||||
c.Spec.DependsOn = []xpmetav1.Dependency{
|
||||
{
|
||||
Provider: ptrFromString("xpkg.upbound.io/upbound/provider-aws-eks"),
|
||||
Version: ">=v0.17.0",
|
||||
},
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cc *configurationMetaTestConverter) ConfigurationMetadataV1Alpha1(c *xpmetav1alpha1.Configuration) error {
|
||||
c.Spec.DependsOn = []xpmetav1alpha1.Dependency{
|
||||
{
|
||||
Provider: ptrFromString("xpkg.upbound.io/upbound/provider-aws-eks"),
|
||||
Version: ">=v0.17.0",
|
||||
},
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type monolithProviderToFamilyConfigConverter struct{}
|
||||
|
||||
func (c *monolithProviderToFamilyConfigConverter) ProviderPackageV1(_ xppkgv1.Provider) ([]xppkgv1.Provider, error) {
|
||||
ap := xppkgv1.ManualActivation
|
||||
return []xppkgv1.Provider{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "provider-family-aws",
|
||||
},
|
||||
Spec: xppkgv1.ProviderSpec{
|
||||
PackageSpec: xppkgv1.PackageSpec{
|
||||
Package: "xpkg.upbound.io/upbound/provider-family-aws:v0.37.0",
|
||||
RevisionActivationPolicy: &ap,
|
||||
},
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
type monolithicProviderToSSOPConverter struct{}
|
||||
|
||||
func (c *monolithicProviderToSSOPConverter) ProviderPackageV1(_ xppkgv1.Provider) ([]xppkgv1.Provider, error) {
|
||||
ap := xppkgv1.ManualActivation
|
||||
return []xppkgv1.Provider{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "provider-aws-ec2",
|
||||
},
|
||||
Spec: xppkgv1.ProviderSpec{
|
||||
PackageSpec: xppkgv1.PackageSpec{
|
||||
Package: "xpkg.upbound.io/upbound/provider-aws-ec2:v0.37.0",
|
||||
RevisionActivationPolicy: &ap,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "provider-aws-eks",
|
||||
},
|
||||
Spec: xppkgv1.ProviderSpec{
|
||||
PackageSpec: xppkgv1.PackageSpec{
|
||||
Package: "xpkg.upbound.io/upbound/provider-aws-eks:v0.37.0",
|
||||
RevisionActivationPolicy: &ap,
|
||||
},
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
type lockConverter struct{}
|
||||
|
||||
func (p *lockConverter) PackageLockV1Beta1(lock *xppkgv1beta1.Lock) error {
|
||||
lock.Packages = append(lock.Packages, xppkgv1beta1.LockPackage{
|
||||
Name: "test-provider",
|
||||
Type: ptr.To(xppkgv1beta1.ProviderPackageType),
|
||||
Source: "xpkg.upbound.io/upbound/test-provider",
|
||||
Version: "vX.Y.Z",
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
type preProcessor struct {
|
||||
results []string
|
||||
}
|
||||
|
||||
func (pp *preProcessor) PreProcess(u UnstructuredWithMetadata) error {
|
||||
pp.results = append(pp.results, getVersionedName(u.Object))
|
||||
return nil
|
||||
}
|
|
@ -1,177 +0,0 @@
|
|||
// SPDX-FileCopyrightText: 2023 The Crossplane Authors <https://crossplane.io>
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package migration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/util/json"
|
||||
"k8s.io/apimachinery/pkg/util/jsonmergepatch"
|
||||
"k8s.io/apimachinery/pkg/util/rand"
|
||||
)
|
||||
|
||||
type step int
|
||||
|
||||
const (
|
||||
errMarshalSourceForPatch = "failed to marshal source object for computing JSON merge patch"
|
||||
errMarshalTargetForPatch = "failed to marshal target object for computing JSON merge patch"
|
||||
errMergePatch = "failed to compute the JSON merge patch document"
|
||||
errMergePatchMap = "failed to unmarshal the JSON merge patch document into map"
|
||||
errInvalidStepFmt = "invalid step ID: %d"
|
||||
)
|
||||
|
||||
func setApplyStep(name string, s *Step) {
|
||||
s.Name = name
|
||||
s.Type = StepTypeApply
|
||||
s.Apply = &ApplyStep{}
|
||||
}
|
||||
|
||||
func setPatchStep(name string, s *Step) {
|
||||
s.Name = name
|
||||
s.Type = StepTypePatch
|
||||
s.Patch = &PatchStep{}
|
||||
s.Patch.Type = PatchTypeMerge
|
||||
}
|
||||
|
||||
func setDeleteStep(name string, s *Step) {
|
||||
s.Name = name
|
||||
s.Type = StepTypeDelete
|
||||
deletePolicy := FinalizerPolicyRemove
|
||||
s.Delete = &DeleteStep{
|
||||
Options: &DeleteOptions{
|
||||
FinalizerPolicy: &deletePolicy,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func setExecStep(name string, s *Step) {
|
||||
s.Name = name
|
||||
s.Type = StepTypeExec
|
||||
s.Exec = &ExecStep{
|
||||
Command: "sh",
|
||||
}
|
||||
}
|
||||
|
||||
func (pg *PlanGenerator) commitSteps() { //nolint: gocyclo
|
||||
if len(pg.Plan.Spec.stepMap) == 0 {
|
||||
return
|
||||
}
|
||||
pg.Plan.Spec.Steps = make([]Step, 0, len(pg.Plan.Spec.stepMap))
|
||||
keys := make([]string, 0, len(pg.Plan.Spec.stepMap))
|
||||
for s := range pg.Plan.Spec.stepMap {
|
||||
keys = append(keys, s)
|
||||
}
|
||||
// keys slice consist of the step keys of enabled migration steps.
|
||||
// step keys are the string representation of integer or float64 numbers,
|
||||
// which correspond to the step execution order (greater number executes later)
|
||||
// therefore needs to be sorted according to their numeric values.
|
||||
// otherwise, sorting the strings directly causes faulty behavior e.g "1" < "10" < "2"
|
||||
// sorting will panic if a non-numeric step key is found in keys
|
||||
sort.SliceStable(keys, func(i, j int) bool {
|
||||
fi, err := strconv.ParseFloat(keys[i], 64)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fj, err := strconv.ParseFloat(keys[j], 64)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return fi < fj
|
||||
})
|
||||
addManualExecution := true
|
||||
switch t := pg.source.(type) {
|
||||
case *sources:
|
||||
for _, source := range t.backends {
|
||||
if _, ok := source.(*FileSystemSource); ok {
|
||||
addManualExecution = false
|
||||
break
|
||||
}
|
||||
}
|
||||
case *FileSystemSource:
|
||||
addManualExecution = false
|
||||
}
|
||||
|
||||
if addManualExecution {
|
||||
for _, s := range keys {
|
||||
AddManualExecution(pg.Plan.Spec.stepMap[s])
|
||||
pg.Plan.Spec.Steps = append(pg.Plan.Spec.Steps, *pg.Plan.Spec.stepMap[s])
|
||||
}
|
||||
} else {
|
||||
for _, s := range keys {
|
||||
pg.Plan.Spec.Steps = append(pg.Plan.Spec.Steps, *pg.Plan.Spec.stepMap[s])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// AddManualExecution sets the manual execution hint for
|
||||
// the specified step.
|
||||
func AddManualExecution(s *Step) {
|
||||
switch s.Type {
|
||||
case StepTypeExec:
|
||||
s.ManualExecution = []string{fmt.Sprintf("%s %s %q", s.Exec.Command, s.Exec.Args[0], strings.Join(s.Exec.Args[1:], " "))}
|
||||
case StepTypePatch:
|
||||
for _, f := range s.Patch.Files {
|
||||
s.ManualExecution = append(s.ManualExecution, fmt.Sprintf("kubectl patch --type='%s' -f %s --patch-file %s", s.Patch.Type, f, f))
|
||||
}
|
||||
case StepTypeApply:
|
||||
for _, f := range s.Apply.Files {
|
||||
s.ManualExecution = append(s.ManualExecution, fmt.Sprintf("kubectl apply -f %s", f))
|
||||
}
|
||||
case StepTypeDelete:
|
||||
for _, r := range s.Delete.Resources {
|
||||
s.ManualExecution = append(s.ManualExecution, fmt.Sprintf("kubectl delete %s %s", strings.Join([]string{r.Kind, r.Group}, "."), r.Name))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (pg *PlanGenerator) stepEnabled(s step) bool {
|
||||
for _, i := range pg.enabledSteps {
|
||||
if i == s {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func computeJSONMergePathDoc(source, target unstructured.Unstructured) (map[string]any, error) {
|
||||
sourceBuff, err := source.MarshalJSON()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, errMarshalSourceForPatch)
|
||||
}
|
||||
targetBuff, err := target.MarshalJSON()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, errMarshalTargetForPatch)
|
||||
}
|
||||
patch, err := jsonmergepatch.CreateThreeWayJSONMergePatch(sourceBuff, targetBuff, sourceBuff)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, errMergePatch)
|
||||
}
|
||||
|
||||
var result map[string]any
|
||||
return result, errors.Wrap(json.Unmarshal(patch, &result), errMergePatchMap)
|
||||
}
|
||||
|
||||
func getQualifiedName(u unstructured.Unstructured) string {
|
||||
namePrefix := u.GetName()
|
||||
if len(namePrefix) == 0 {
|
||||
namePrefix = fmt.Sprintf("%s%s", u.GetGenerateName(), rand.String(5))
|
||||
}
|
||||
gvk := u.GroupVersionKind()
|
||||
return fmt.Sprintf("%s.%ss.%s", namePrefix, strings.ToLower(gvk.Kind), gvk.Group)
|
||||
}
|
||||
|
||||
func getVersionedName(u unstructured.Unstructured) string {
|
||||
v := u.GroupVersionKind().Version
|
||||
qName := getQualifiedName(u)
|
||||
if v == "" {
|
||||
return qName
|
||||
}
|
||||
return fmt.Sprintf("%s_%s", qName, v)
|
||||
}
|
|
@ -1,146 +0,0 @@
|
|||
// SPDX-FileCopyrightText: 2023 The Crossplane Authors <https://crossplane.io>
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package migration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/crossplane/crossplane-runtime/pkg/fieldpath"
|
||||
"github.com/pkg/errors"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
)
|
||||
|
||||
const (
|
||||
errPutSSOPPackageFmt = "failed to put the SSOP package: %s"
|
||||
errActivateSSOP = "failed to put the activated SSOP package: %s"
|
||||
)
|
||||
|
||||
func (pg *PlanGenerator) convertProviderPackage(o UnstructuredWithMetadata) (bool, error) { //nolint:gocyclo
|
||||
pkg, err := toProviderPackage(o.Object)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
isConverted := false
|
||||
for _, pkgConv := range pg.registry.providerPackageConverters {
|
||||
if pkgConv.re == nil || pkgConv.converter == nil || !pkgConv.re.MatchString(pkg.Spec.Package) {
|
||||
continue
|
||||
}
|
||||
targetPkgs, err := pkgConv.converter.ProviderPackageV1(*pkg)
|
||||
if err != nil {
|
||||
return false, errors.Wrapf(err, "failed to call converter on Provider package: %s", pkg.Spec.Package)
|
||||
}
|
||||
if len(targetPkgs) == 0 {
|
||||
continue
|
||||
}
|
||||
// TODO: if a configuration converter only converts a specific version,
|
||||
// (or does not convert the given configuration),
|
||||
// we will have a false positive. Better to compute and check
|
||||
// a diff here.
|
||||
isConverted = true
|
||||
converted := make([]*UnstructuredWithMetadata, 0, len(targetPkgs))
|
||||
for _, p := range targetPkgs {
|
||||
p := p
|
||||
converted = append(converted, &UnstructuredWithMetadata{
|
||||
Object: ToSanitizedUnstructured(&p),
|
||||
Metadata: o.Metadata,
|
||||
})
|
||||
}
|
||||
if err := pg.stepNewSSOPs(o, converted); err != nil {
|
||||
return false, err
|
||||
}
|
||||
if err := pg.stepActivateSSOPs(converted); err != nil {
|
||||
return false, err
|
||||
}
|
||||
if err := pg.stepCheckHealthOfNewProvider(o, converted); err != nil {
|
||||
return false, err
|
||||
}
|
||||
if err := pg.stepCheckInstallationOfNewProvider(o, converted); err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
return isConverted, nil
|
||||
}
|
||||
|
||||
func (pg *PlanGenerator) stepDeleteMonolith(source UnstructuredWithMetadata) error {
|
||||
// delete the monolithic provider package
|
||||
s := pg.stepConfigurationWithSubStep(stepDeleteMonolithicProvider, true)
|
||||
source.Metadata.Path = fmt.Sprintf("%s/%s.yaml", s.Name, getVersionedName(source.Object))
|
||||
s.Delete.Resources = []Resource{
|
||||
{
|
||||
GroupVersionKind: FromGroupVersionKind(source.Object.GroupVersionKind()),
|
||||
Name: source.Object.GetName(),
|
||||
},
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// add steps for the new SSOPs
|
||||
func (pg *PlanGenerator) stepNewSSOPs(source UnstructuredWithMetadata, targets []*UnstructuredWithMetadata) error {
|
||||
var s *Step
|
||||
isFamilyConfig, err := checkContainsFamilyConfigProvider(targets)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "could not decide whether the provider family config")
|
||||
}
|
||||
if isFamilyConfig {
|
||||
s = pg.stepConfigurationWithSubStep(stepNewFamilyProvider, true)
|
||||
} else {
|
||||
s = pg.stepConfigurationWithSubStep(stepNewServiceScopedProvider, true)
|
||||
}
|
||||
for _, t := range targets {
|
||||
t.Object.Object = addGVK(source.Object, t.Object.Object)
|
||||
t.Metadata.Path = fmt.Sprintf("%s/%s.yaml", s.Name, getVersionedName(t.Object))
|
||||
s.Apply.Files = append(s.Apply.Files, t.Metadata.Path)
|
||||
if err := pg.target.Put(*t); err != nil {
|
||||
return errors.Wrapf(err, errPutSSOPPackageFmt, t.Metadata.Path)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// add steps for activating SSOPs
|
||||
func (pg *PlanGenerator) stepActivateSSOPs(targets []*UnstructuredWithMetadata) error {
|
||||
var s *Step
|
||||
isFamilyConfig, err := checkContainsFamilyConfigProvider(targets)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "could not decide whether the provider family config")
|
||||
}
|
||||
if isFamilyConfig {
|
||||
s = pg.stepConfigurationWithSubStep(stepActivateFamilyProviderRevision, true)
|
||||
} else {
|
||||
s = pg.stepConfigurationWithSubStep(stepActivateServiceScopedProviderRevision, true)
|
||||
}
|
||||
for _, t := range targets {
|
||||
t.Metadata.Path = fmt.Sprintf("%s/%s.yaml", s.Name, getVersionedName(t.Object))
|
||||
s.Patch.Files = append(s.Patch.Files, t.Metadata.Path)
|
||||
if err := pg.target.Put(UnstructuredWithMetadata{
|
||||
Object: unstructured.Unstructured{
|
||||
Object: addNameGVK(t.Object, map[string]any{
|
||||
"spec": map[string]any{
|
||||
"revisionActivationPolicy": "Automatic",
|
||||
},
|
||||
}),
|
||||
},
|
||||
Metadata: t.Metadata,
|
||||
}); err != nil {
|
||||
return errors.Wrapf(err, errActivateSSOP, t.Metadata.Path)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkContainsFamilyConfigProvider(targets []*UnstructuredWithMetadata) (bool, error) {
|
||||
for _, t := range targets {
|
||||
paved := fieldpath.Pave(t.Object.Object)
|
||||
pkg, err := paved.GetString("spec.package")
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, "could not get package of provider")
|
||||
}
|
||||
if strings.Contains(pkg, "provider-family") {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
return false, nil
|
||||
}
|
|
@ -1,542 +0,0 @@
|
|||
// SPDX-FileCopyrightText: 2023 The Crossplane Authors <https://crossplane.io>
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package migration
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
|
||||
"github.com/crossplane/crossplane-runtime/pkg/resource"
|
||||
xpv1 "github.com/crossplane/crossplane/apis/apiextensions/v1"
|
||||
xpmetav1 "github.com/crossplane/crossplane/apis/pkg/meta/v1"
|
||||
xpmetav1alpha1 "github.com/crossplane/crossplane/apis/pkg/meta/v1alpha1"
|
||||
xppkgv1 "github.com/crossplane/crossplane/apis/pkg/v1"
|
||||
xppkgv1beta1 "github.com/crossplane/crossplane/apis/pkg/v1beta1"
|
||||
"github.com/pkg/errors"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
var (
|
||||
// AllCompositions matches all v1.Composition names.
|
||||
AllCompositions = regexp.MustCompile(`.*`)
|
||||
// AllConfigurations matches all metav1.Configuration names.
|
||||
AllConfigurations = regexp.MustCompile(`.*`)
|
||||
// CrossplaneLockName is the Crossplane package lock's `metadata.name`
|
||||
CrossplaneLockName = regexp.MustCompile(`^lock$`)
|
||||
)
|
||||
|
||||
const (
|
||||
errAddToScheme = "failed to register types with the registry's scheme"
|
||||
errFmtNewObject = "failed to instantiate a new runtime.Object using runtime.Scheme for: %s"
|
||||
errFmtNotManagedResource = "specified GVK does not belong to a managed resource: %s"
|
||||
)
|
||||
|
||||
type patchSetConverter struct {
|
||||
// re is the regular expression against which a Composition's name
|
||||
// will be matched to determine whether the conversion function
|
||||
// will be invoked.
|
||||
re *regexp.Regexp
|
||||
// converter is the PatchSetConverter to be run on the Composition's
|
||||
// patch sets.
|
||||
converter PatchSetConverter
|
||||
}
|
||||
|
||||
type configurationMetadataConverter struct {
|
||||
// re is the regular expression against which a Configuration's name
|
||||
// will be matched to determine whether the conversion function
|
||||
// will be invoked.
|
||||
re *regexp.Regexp
|
||||
// converter is the ConfigurationMetadataConverter to be run on the Configuration's
|
||||
// metadata.
|
||||
converter ConfigurationMetadataConverter
|
||||
}
|
||||
|
||||
type configurationPackageConverter struct {
|
||||
// re is the regular expression against which a Configuration package's
|
||||
// reference will be matched to determine whether the conversion function
|
||||
// will be invoked.
|
||||
re *regexp.Regexp
|
||||
// converter is the ConfigurationPackageConverter to be run on the
|
||||
// Configuration package.
|
||||
converter ConfigurationPackageConverter
|
||||
}
|
||||
|
||||
type providerPackageConverter struct {
|
||||
// re is the regular expression against which a Provider package's
|
||||
// reference will be matched to determine whether the conversion function
|
||||
// will be invoked.
|
||||
re *regexp.Regexp
|
||||
// converter is the ProviderPackageConverter to be run on the
|
||||
// Provider package.
|
||||
converter ProviderPackageConverter
|
||||
}
|
||||
|
||||
type packageLockConverter struct {
|
||||
// re is the regular expression against which a package Lock's name
|
||||
// will be matched to determine whether the conversion function
|
||||
// will be invoked.
|
||||
re *regexp.Regexp
|
||||
// converter is the PackageLockConverter to be run on the package Lock.
|
||||
converter PackageLockConverter
|
||||
}
|
||||
|
||||
// Registry is a registry of `migration.Converter`s keyed with
|
||||
// the associated `schema.GroupVersionKind`s and an associated
|
||||
// runtime.Scheme with which the corresponding types are registered.
|
||||
type Registry struct {
|
||||
unstructuredPreProcessors map[Category][]UnstructuredPreProcessor
|
||||
resourcePreProcessors []ManagedPreProcessor
|
||||
resourceConverters map[schema.GroupVersionKind]ResourceConverter
|
||||
templateConverters map[schema.GroupVersionKind]ComposedTemplateConverter
|
||||
patchSetConverters []patchSetConverter
|
||||
configurationMetaConverters []configurationMetadataConverter
|
||||
configurationPackageConverters []configurationPackageConverter
|
||||
providerPackageConverters []providerPackageConverter
|
||||
packageLockConverters []packageLockConverter
|
||||
categoricalConverters map[Category][]CategoricalConverter
|
||||
scheme *runtime.Scheme
|
||||
claimTypes []schema.GroupVersionKind
|
||||
compositeTypes []schema.GroupVersionKind
|
||||
}
|
||||
|
||||
// NewRegistry returns a new Registry initialized with
|
||||
// the specified runtime.Scheme.
|
||||
func NewRegistry(scheme *runtime.Scheme) *Registry {
|
||||
return &Registry{
|
||||
resourceConverters: make(map[schema.GroupVersionKind]ResourceConverter),
|
||||
templateConverters: make(map[schema.GroupVersionKind]ComposedTemplateConverter),
|
||||
categoricalConverters: make(map[Category][]CategoricalConverter),
|
||||
unstructuredPreProcessors: make(map[Category][]UnstructuredPreProcessor),
|
||||
scheme: scheme,
|
||||
}
|
||||
}
|
||||
|
||||
// make sure a converter is being registered for a managed resource,
|
||||
// and it's registered with our runtime scheme.
|
||||
// This will be needed, during runtime, for properly converting resources.
|
||||
func (r *Registry) assertManagedResource(gvk schema.GroupVersionKind) {
|
||||
obj, err := r.scheme.New(gvk)
|
||||
if err != nil {
|
||||
panic(errors.Wrapf(err, errFmtNewObject, gvk))
|
||||
}
|
||||
if _, ok := obj.(resource.Managed); !ok {
|
||||
panic(errors.Errorf(errFmtNotManagedResource, gvk))
|
||||
}
|
||||
}
|
||||
|
||||
// RegisterResourceConverter registers the specified ResourceConverter
|
||||
// for the specified GVK with this Registry.
|
||||
func (r *Registry) RegisterResourceConverter(gvk schema.GroupVersionKind, conv ResourceConverter) {
|
||||
r.assertManagedResource(gvk)
|
||||
r.resourceConverters[gvk] = conv
|
||||
}
|
||||
|
||||
// RegisterTemplateConverter registers the specified ComposedTemplateConverter
|
||||
// for the specified GVK with this Registry.
|
||||
func (r *Registry) RegisterTemplateConverter(gvk schema.GroupVersionKind, conv ComposedTemplateConverter) {
|
||||
r.assertManagedResource(gvk)
|
||||
r.templateConverters[gvk] = conv
|
||||
}
|
||||
|
||||
// RegisterCompositionConverter is a convenience method for registering both
|
||||
// a ResourceConverter and a ComposedTemplateConverter that act on the same
|
||||
// managed resource kind and are implemented by the same type.
|
||||
func (r *Registry) RegisterCompositionConverter(gvk schema.GroupVersionKind, conv CompositionConverter) {
|
||||
r.RegisterResourceConverter(gvk, conv)
|
||||
r.RegisterTemplateConverter(gvk, conv)
|
||||
}
|
||||
|
||||
// RegisterPatchSetConverter registers the given PatchSetConverter for
|
||||
// the compositions whose name match the given regular expression.
|
||||
func (r *Registry) RegisterPatchSetConverter(re *regexp.Regexp, psConv PatchSetConverter) {
|
||||
r.patchSetConverters = append(r.patchSetConverters, patchSetConverter{
|
||||
re: re,
|
||||
converter: psConv,
|
||||
})
|
||||
}
|
||||
|
||||
// RegisterConfigurationMetadataConverter registers the given ConfigurationMetadataConverter
|
||||
// for the configurations whose name match the given regular expression.
|
||||
func (r *Registry) RegisterConfigurationMetadataConverter(re *regexp.Regexp, confConv ConfigurationMetadataConverter) {
|
||||
r.configurationMetaConverters = append(r.configurationMetaConverters, configurationMetadataConverter{
|
||||
re: re,
|
||||
converter: confConv,
|
||||
})
|
||||
}
|
||||
|
||||
// RegisterConfigurationMetadataV1ConversionFunction registers the specified
|
||||
// ConfigurationMetadataV1ConversionFn for the v1 configurations whose name match
|
||||
// the given regular expression.
|
||||
func (r *Registry) RegisterConfigurationMetadataV1ConversionFunction(re *regexp.Regexp, confConversionFn ConfigurationMetadataV1ConversionFn) {
|
||||
r.RegisterConfigurationMetadataConverter(re, &delegatingConverter{
|
||||
confMetaV1Fn: confConversionFn,
|
||||
})
|
||||
}
|
||||
|
||||
// RegisterConfigurationMetadataV1Alpha1ConversionFunction registers the specified
|
||||
// ConfigurationMetadataV1Alpha1ConversionFn for the v1alpha1 configurations
|
||||
// whose name match the given regular expression.
|
||||
func (r *Registry) RegisterConfigurationMetadataV1Alpha1ConversionFunction(re *regexp.Regexp, confConversionFn ConfigurationMetadataV1Alpha1ConversionFn) {
|
||||
r.RegisterConfigurationMetadataConverter(re, &delegatingConverter{
|
||||
confMetaV1Alpha1Fn: confConversionFn,
|
||||
})
|
||||
}
|
||||
|
||||
// RegisterConfigurationPackageConverter registers the specified
|
||||
// ConfigurationPackageConverter for the Configuration v1 packages whose reference
|
||||
// match the given regular expression.
|
||||
func (r *Registry) RegisterConfigurationPackageConverter(re *regexp.Regexp, pkgConv ConfigurationPackageConverter) {
|
||||
r.configurationPackageConverters = append(r.configurationPackageConverters, configurationPackageConverter{
|
||||
re: re,
|
||||
converter: pkgConv,
|
||||
})
|
||||
}
|
||||
|
||||
// RegisterConfigurationPackageV1ConversionFunction registers the specified
|
||||
// ConfigurationPackageV1ConversionFn for the Configuration v1 packages whose reference
|
||||
// match the given regular expression.
|
||||
func (r *Registry) RegisterConfigurationPackageV1ConversionFunction(re *regexp.Regexp, confConversionFn ConfigurationPackageV1ConversionFn) {
|
||||
r.RegisterConfigurationPackageConverter(re, &delegatingConverter{
|
||||
confPackageV1Fn: confConversionFn,
|
||||
})
|
||||
}
|
||||
|
||||
// RegisterProviderPackageConverter registers the given ProviderPackageConverter
|
||||
// for the provider packages whose references match the given regular expression.
|
||||
func (r *Registry) RegisterProviderPackageConverter(re *regexp.Regexp, pkgConv ProviderPackageConverter) {
|
||||
r.providerPackageConverters = append(r.providerPackageConverters, providerPackageConverter{
|
||||
re: re,
|
||||
converter: pkgConv,
|
||||
})
|
||||
}
|
||||
|
||||
// RegisterProviderPackageV1ConversionFunction registers the specified
|
||||
// ProviderPackageV1ConversionFn for the provider v1 packages whose reference
|
||||
// match the given regular expression.
|
||||
func (r *Registry) RegisterProviderPackageV1ConversionFunction(re *regexp.Regexp, pkgConversionFn ProviderPackageV1ConversionFn) {
|
||||
r.RegisterProviderPackageConverter(re, &delegatingConverter{
|
||||
providerPackageV1Fn: pkgConversionFn,
|
||||
})
|
||||
}
|
||||
|
||||
// RegisterPackageLockConverter registers the given PackageLockConverter.
|
||||
func (r *Registry) RegisterPackageLockConverter(re *regexp.Regexp, lockConv PackageLockConverter) {
|
||||
r.packageLockConverters = append(r.packageLockConverters, packageLockConverter{
|
||||
re: re,
|
||||
converter: lockConv,
|
||||
})
|
||||
}
|
||||
|
||||
// RegisterCategoricalConverter registers the specified CategoricalConverter
|
||||
// for the specified Category of resources.
|
||||
func (r *Registry) RegisterCategoricalConverter(c Category, converter CategoricalConverter) {
|
||||
r.categoricalConverters[c] = append(r.categoricalConverters[c], converter)
|
||||
}
|
||||
|
||||
// RegisterCategoricalConverterFunction registers the specified
|
||||
// CategoricalConverterFunctionFn for the specified Category.
|
||||
func (r *Registry) RegisterCategoricalConverterFunction(c Category, converterFn CategoricalConverterFunctionFn) {
|
||||
r.RegisterCategoricalConverter(c, &delegatingConverter{
|
||||
categoricalConverterFn: converterFn,
|
||||
})
|
||||
}
|
||||
|
||||
// RegisterPackageLockV1Beta1ConversionFunction registers the specified
|
||||
// RegisterPackageLockV1Beta1ConversionFunction for the package v1beta1 locks.
|
||||
func (r *Registry) RegisterPackageLockV1Beta1ConversionFunction(re *regexp.Regexp, lockConversionFn PackageLockV1Beta1ConversionFn) {
|
||||
r.RegisterPackageLockConverter(re, &delegatingConverter{
|
||||
packageLockV1Beta1Fn: lockConversionFn,
|
||||
})
|
||||
}
|
||||
|
||||
// AddToScheme registers types with this Registry's runtime.Scheme
|
||||
func (r *Registry) AddToScheme(sb func(scheme *runtime.Scheme) error) error {
|
||||
return errors.Wrap(sb(r.scheme), errAddToScheme)
|
||||
}
|
||||
|
||||
// AddCompositionTypes registers the Composition types with
|
||||
// the registry's scheme. Only the v1 API of Compositions
|
||||
// is currently supported.
|
||||
func (r *Registry) AddCompositionTypes() error {
|
||||
return r.AddToScheme(xpv1.AddToScheme)
|
||||
}
|
||||
|
||||
// AddCrossplanePackageTypes registers the
|
||||
// {Provider,Configuration,Lock, etc.}.pkg types with
|
||||
// the registry's scheme.
|
||||
func (r *Registry) AddCrossplanePackageTypes() error {
|
||||
if err := r.AddToScheme(xppkgv1beta1.AddToScheme); err != nil {
|
||||
return err
|
||||
}
|
||||
return r.AddToScheme(xppkgv1.AddToScheme)
|
||||
}
|
||||
|
||||
// AddClaimType registers a new composite resource claim type
|
||||
// with the given GVK
|
||||
func (r *Registry) AddClaimType(gvk schema.GroupVersionKind) {
|
||||
r.claimTypes = append(r.claimTypes, gvk)
|
||||
}
|
||||
|
||||
// AddCompositeType registers a new composite resource type with the given GVK
|
||||
func (r *Registry) AddCompositeType(gvk schema.GroupVersionKind) {
|
||||
r.compositeTypes = append(r.compositeTypes, gvk)
|
||||
}
|
||||
|
||||
// GetManagedResourceGVKs returns a list of all registered managed resource
|
||||
// GVKs
|
||||
func (r *Registry) GetManagedResourceGVKs() []schema.GroupVersionKind {
|
||||
gvks := make([]schema.GroupVersionKind, 0, len(r.resourceConverters)+len(r.templateConverters))
|
||||
for gvk := range r.resourceConverters {
|
||||
gvks = append(gvks, gvk)
|
||||
}
|
||||
for gvk := range r.templateConverters {
|
||||
gvks = append(gvks, gvk)
|
||||
}
|
||||
return gvks
|
||||
}
|
||||
|
||||
// GetCompositionGVKs returns the registered Composition GVKs.
|
||||
func (r *Registry) GetCompositionGVKs() []schema.GroupVersionKind {
|
||||
// Composition types are registered with this registry's scheme
|
||||
if _, ok := r.scheme.AllKnownTypes()[xpv1.CompositionGroupVersionKind]; ok {
|
||||
return []schema.GroupVersionKind{xpv1.CompositionGroupVersionKind}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetCrossplanePackageGVKs returns the registered Crossplane package GVKs.
|
||||
func (r *Registry) GetCrossplanePackageGVKs() []schema.GroupVersionKind {
|
||||
if r.scheme.AllKnownTypes()[xppkgv1.ProviderGroupVersionKind] == nil ||
|
||||
r.scheme.AllKnownTypes()[xppkgv1.ConfigurationGroupVersionKind] == nil ||
|
||||
r.scheme.AllKnownTypes()[xppkgv1beta1.LockGroupVersionKind] == nil {
|
||||
return nil
|
||||
}
|
||||
return []schema.GroupVersionKind{
|
||||
xppkgv1.ProviderGroupVersionKind,
|
||||
xppkgv1.ConfigurationGroupVersionKind,
|
||||
xppkgv1beta1.LockGroupVersionKind,
|
||||
}
|
||||
}
|
||||
|
||||
// GetAllRegisteredGVKs returns a list of registered GVKs
|
||||
// including v1.CompositionGroupVersionKind,
|
||||
// metav1.ConfigurationGroupVersionKind,
|
||||
// metav1alpha1.ConfigurationGroupVersionKind
|
||||
// pkg.ConfigurationGroupVersionKind,
|
||||
// pkg.ProviderGroupVersionKind,
|
||||
// pkg.LockGroupVersionKind.
|
||||
func (r *Registry) GetAllRegisteredGVKs() []schema.GroupVersionKind {
|
||||
gvks := make([]schema.GroupVersionKind, 0, len(r.claimTypes)+len(r.compositeTypes)+len(r.resourceConverters)+len(r.templateConverters)+1)
|
||||
gvks = append(gvks, r.claimTypes...)
|
||||
gvks = append(gvks, r.compositeTypes...)
|
||||
gvks = append(gvks, r.GetManagedResourceGVKs()...)
|
||||
gvks = append(gvks, xpv1.CompositionGroupVersionKind, xpmetav1.ConfigurationGroupVersionKind, xpmetav1alpha1.ConfigurationGroupVersionKind,
|
||||
xppkgv1.ConfigurationGroupVersionKind, xppkgv1.ProviderGroupVersionKind, xppkgv1beta1.LockGroupVersionKind)
|
||||
return gvks
|
||||
}
|
||||
|
||||
// ResourceConversionFn is a function that converts the specified migration
|
||||
// source managed resource to one or more migration target managed resources.
|
||||
type ResourceConversionFn func(mg resource.Managed) ([]resource.Managed, error)
|
||||
|
||||
// ComposedTemplateConversionFn is a function that converts from the specified
|
||||
// migration source v1.ComposedTemplate to one or more migration
|
||||
// target v1.ComposedTemplates.
|
||||
type ComposedTemplateConversionFn func(sourceTemplate xpv1.ComposedTemplate, convertedTemplates ...*xpv1.ComposedTemplate) error
|
||||
|
||||
// PatchSetsConversionFn is a function that converts
|
||||
// the `spec.patchSets` of a Composition from the migration source provider's
|
||||
// schema to the migration target provider's schema.
|
||||
type PatchSetsConversionFn func(psMap map[string]*xpv1.PatchSet) error
|
||||
|
||||
// ConfigurationMetadataV1ConversionFn is a function that converts the specified
|
||||
// migration source Configuration v1 metadata to the migration target
|
||||
// Configuration metadata.
|
||||
type ConfigurationMetadataV1ConversionFn func(configuration *xpmetav1.Configuration) error
|
||||
|
||||
// ConfigurationMetadataV1Alpha1ConversionFn is a function that converts the specified
|
||||
// migration source Configuration v1alpha1 metadata to the migration target
|
||||
// Configuration metadata.
|
||||
type ConfigurationMetadataV1Alpha1ConversionFn func(configuration *xpmetav1alpha1.Configuration) error
|
||||
|
||||
// PackageLockV1Beta1ConversionFn is a function that converts the specified
|
||||
// migration source package v1beta1 lock to the migration target
|
||||
// package lock.
|
||||
type PackageLockV1Beta1ConversionFn func(pkg *xppkgv1beta1.Lock) error
|
||||
|
||||
// ConfigurationPackageV1ConversionFn is a function that converts the specified
|
||||
// migration source Configuration v1 package to the migration target
|
||||
// Configuration package(s).
|
||||
type ConfigurationPackageV1ConversionFn func(pkg *xppkgv1.Configuration) error
|
||||
|
||||
// ProviderPackageV1ConversionFn is a function that converts the specified
|
||||
// migration source provider v1 package to the migration target
|
||||
// Provider package(s).
|
||||
type ProviderPackageV1ConversionFn func(pkg xppkgv1.Provider) ([]xppkgv1.Provider, error)
|
||||
|
||||
// CategoricalConverterFunctionFn is a function that converts resources of a
|
||||
// Category. Because it receives an unstructured argument, it should be
|
||||
// used for implementing generic conversion functions acting on a specific
|
||||
// category.
|
||||
type CategoricalConverterFunctionFn func(u *UnstructuredWithMetadata) error
|
||||
|
||||
type delegatingConverter struct {
|
||||
rFn ResourceConversionFn
|
||||
cmpFn ComposedTemplateConversionFn
|
||||
psFn PatchSetsConversionFn
|
||||
confMetaV1Fn ConfigurationMetadataV1ConversionFn
|
||||
confMetaV1Alpha1Fn ConfigurationMetadataV1Alpha1ConversionFn
|
||||
confPackageV1Fn ConfigurationPackageV1ConversionFn
|
||||
providerPackageV1Fn ProviderPackageV1ConversionFn
|
||||
packageLockV1Beta1Fn PackageLockV1Beta1ConversionFn
|
||||
categoricalConverterFn CategoricalConverterFunctionFn
|
||||
}
|
||||
|
||||
func (d *delegatingConverter) Convert(u *UnstructuredWithMetadata) error {
|
||||
if d.categoricalConverterFn == nil {
|
||||
return nil
|
||||
}
|
||||
return d.categoricalConverterFn(u)
|
||||
}
|
||||
|
||||
func (d *delegatingConverter) ConfigurationPackageV1(pkg *xppkgv1.Configuration) error {
|
||||
if d.confPackageV1Fn == nil {
|
||||
return nil
|
||||
}
|
||||
return d.confPackageV1Fn(pkg)
|
||||
}
|
||||
|
||||
func (d *delegatingConverter) PackageLockV1Beta1(lock *xppkgv1beta1.Lock) error {
|
||||
if d.packageLockV1Beta1Fn == nil {
|
||||
return nil
|
||||
}
|
||||
return d.packageLockV1Beta1Fn(lock)
|
||||
}
|
||||
|
||||
func (d *delegatingConverter) ProviderPackageV1(pkg xppkgv1.Provider) ([]xppkgv1.Provider, error) {
|
||||
if d.providerPackageV1Fn == nil {
|
||||
return []xppkgv1.Provider{pkg}, nil
|
||||
}
|
||||
return d.providerPackageV1Fn(pkg)
|
||||
}
|
||||
|
||||
func (d *delegatingConverter) ConfigurationMetadataV1(c *xpmetav1.Configuration) error {
|
||||
if d.confMetaV1Fn == nil {
|
||||
return nil
|
||||
}
|
||||
return d.confMetaV1Fn(c)
|
||||
}
|
||||
|
||||
func (d *delegatingConverter) ConfigurationMetadataV1Alpha1(c *xpmetav1alpha1.Configuration) error {
|
||||
if d.confMetaV1Alpha1Fn == nil {
|
||||
return nil
|
||||
}
|
||||
return d.confMetaV1Alpha1Fn(c)
|
||||
}
|
||||
|
||||
func (d *delegatingConverter) PatchSets(psMap map[string]*xpv1.PatchSet) error {
|
||||
if d.psFn == nil {
|
||||
return nil
|
||||
}
|
||||
return d.psFn(psMap)
|
||||
}
|
||||
|
||||
// Resource takes a managed resource and returns zero or more managed
|
||||
// resources to be created by calling the configured ResourceConversionFn.
|
||||
func (d *delegatingConverter) Resource(mg resource.Managed) ([]resource.Managed, error) {
|
||||
if d.rFn == nil {
|
||||
return []resource.Managed{mg}, nil
|
||||
}
|
||||
return d.rFn(mg)
|
||||
}
|
||||
|
||||
// ComposedTemplate converts from the specified migration source
|
||||
// v1.ComposedTemplate to the migration target schema by calling the configured
|
||||
// ComposedTemplateConversionFn.
|
||||
func (d *delegatingConverter) ComposedTemplate(sourceTemplate xpv1.ComposedTemplate, convertedTemplates ...*xpv1.ComposedTemplate) error {
|
||||
if d.cmpFn == nil {
|
||||
return nil
|
||||
}
|
||||
return d.cmpFn(sourceTemplate, convertedTemplates...)
|
||||
}
|
||||
|
||||
// DefaultCompositionConverter is a generic composition converter
|
||||
// conversionMap: is fieldpath map for conversion
|
||||
// Key of the conversionMap points to the source field
|
||||
// Value of the conversionMap points to the target field
|
||||
// Example: "spec.forProvider.assumeRolePolicyDocument": "spec.forProvider.assumeRolePolicy",
|
||||
// fns are functions that manipulate the patchsets
|
||||
func DefaultCompositionConverter(conversionMap map[string]string, fns ...func(sourceTemplate xpv1.ComposedTemplate) ([]xpv1.Patch, error)) ComposedTemplateConversionFn {
|
||||
return func(sourceTemplate xpv1.ComposedTemplate, convertedTemplates ...*xpv1.ComposedTemplate) error {
|
||||
var patchesToAdd []xpv1.Patch
|
||||
for _, fn := range fns {
|
||||
patches, err := fn(sourceTemplate)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "cannot run the patch sets converter function")
|
||||
}
|
||||
patchesToAdd = append(patchesToAdd, patches...)
|
||||
}
|
||||
patchesToAdd = append(patchesToAdd, ConvertComposedTemplatePatchesMap(sourceTemplate, conversionMap)...)
|
||||
for i := range convertedTemplates {
|
||||
convertedTemplates[i].Patches = append(convertedTemplates[i].Patches, patchesToAdd...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// RegisterAPIConversionFunctions registers the supplied ResourceConversionFn and
|
||||
// ComposedTemplateConversionFn for the specified GVK, and the supplied
|
||||
// PatchSetsConversionFn for all the discovered Compositions.
|
||||
// The specified GVK must belong to a Crossplane managed resource type and
|
||||
// the type must already have been registered with this registry's scheme
|
||||
// by calling Registry.AddToScheme.
|
||||
func (r *Registry) RegisterAPIConversionFunctions(gvk schema.GroupVersionKind, rFn ResourceConversionFn, cmpFn ComposedTemplateConversionFn, psFn PatchSetsConversionFn) {
|
||||
d := &delegatingConverter{
|
||||
rFn: rFn,
|
||||
cmpFn: cmpFn,
|
||||
psFn: psFn,
|
||||
}
|
||||
r.RegisterPatchSetConverter(AllCompositions, d)
|
||||
r.RegisterCompositionConverter(gvk, d)
|
||||
}
|
||||
|
||||
// RegisterConversionFunctions registers the supplied ResourceConversionFn and
|
||||
// ComposedTemplateConversionFn for the specified GVK, and the supplied
|
||||
// PatchSetsConversionFn for all the discovered Compositions.
|
||||
// The specified GVK must belong to a Crossplane managed resource type and
|
||||
// the type must already have been registered with this registry's scheme
|
||||
// by calling Registry.AddToScheme.
|
||||
// Deprecated: Use RegisterAPIConversionFunctions instead.
|
||||
func (r *Registry) RegisterConversionFunctions(gvk schema.GroupVersionKind, rFn ResourceConversionFn, cmpFn ComposedTemplateConversionFn, psFn PatchSetsConversionFn) {
|
||||
r.RegisterAPIConversionFunctions(gvk, rFn, cmpFn, psFn)
|
||||
}
|
||||
|
||||
func (r *Registry) RegisterPreProcessor(category Category, pp UnstructuredPreProcessor) {
|
||||
r.unstructuredPreProcessors[category] = append(r.unstructuredPreProcessors[category], pp)
|
||||
}
|
||||
|
||||
// PreProcessor is a function type to convert pre-processor functions to
|
||||
// UnstructuredPreProcessor.
|
||||
type PreProcessor func(u UnstructuredWithMetadata) error
|
||||
|
||||
func (pp PreProcessor) PreProcess(u UnstructuredWithMetadata) error {
|
||||
if pp == nil {
|
||||
return nil
|
||||
}
|
||||
return pp(u)
|
||||
}
|
||||
|
||||
func (r *Registry) RegisterResourcePreProcessor(pp ManagedPreProcessor) {
|
||||
r.resourcePreProcessors = append(r.resourcePreProcessors, pp)
|
||||
}
|
||||
|
||||
type ResourcePreProcessor func(mg resource.Managed) error
|
||||
|
||||
func (pp ResourcePreProcessor) ResourcePreProcessor(mg resource.Managed) error {
|
||||
if pp == nil {
|
||||
return nil
|
||||
}
|
||||
return pp(mg)
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
# SPDX-FileCopyrightText: 2023 The Crossplane Authors <https://crossplane.io>
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
apiVersion: test.com/v1alpha1
|
||||
kind: MyResource
|
||||
metadata:
|
||||
name: my-resource
|
||||
namespace: upbound-system
|
||||
spec:
|
||||
compositionRef:
|
||||
name: example
|
||||
parameters:
|
||||
tagValue: demo-test
|
||||
region: us-west-1
|
|
@ -1,78 +0,0 @@
|
|||
# SPDX-FileCopyrightText: 2023 The Crossplane Authors <https://crossplane.io>
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
apiVersion: apiextensions.crossplane.io/v1
|
||||
kind: Composition
|
||||
metadata:
|
||||
labels:
|
||||
purpose: example
|
||||
name: example
|
||||
spec:
|
||||
compositeTypeRef:
|
||||
apiVersion: test.com/v1alpha1
|
||||
kind: XMyResource
|
||||
patchSets:
|
||||
- name: not-referenced
|
||||
patches:
|
||||
- fromFieldPath: "spec.parameters.tagValue"
|
||||
toFieldPath: spec.forProvider.myTag
|
||||
- name: ps1
|
||||
patches:
|
||||
- fromFieldPath: "spec.parameters.tagValue"
|
||||
toFieldPath: spec.forProvider.tags[2].value
|
||||
- name: ps2
|
||||
patches:
|
||||
- fromFieldPath: "spec.parameters.region"
|
||||
toFieldPath: spec.forProvider.region
|
||||
- name: ps3
|
||||
patches:
|
||||
- fromFieldPath: "spec.parameters.tagValue"
|
||||
toFieldPath: metadata.labels[a.b.c.d/tag-value]
|
||||
- name: ps4
|
||||
patches:
|
||||
- fromFieldPath: "spec.parameters.tagValue"
|
||||
toFieldPath: metadata.labels['a.b.c.d.e/tag-value']
|
||||
- name: ps5
|
||||
patches:
|
||||
- fromFieldPath: "spec.parameters.tagValue"
|
||||
toFieldPath: metadata.labels["a.b.c.d.e.f/tag-value"]
|
||||
- name: ps6
|
||||
patches:
|
||||
- fromFieldPath: "spec.parameters.tagValue"
|
||||
toFieldPath: spec.forProvider.tags[3].value
|
||||
resources:
|
||||
- base:
|
||||
apiVersion: fakesourceapi/v1alpha1
|
||||
kind: VPC
|
||||
spec:
|
||||
forProvider:
|
||||
cidrBlock: "192.168.0.0/16"
|
||||
region: "us-west-1"
|
||||
tags:
|
||||
- key: key1
|
||||
value: val1
|
||||
- key: key2
|
||||
value: val2
|
||||
- key: key3
|
||||
value: val3
|
||||
name: vpc
|
||||
patches:
|
||||
- fromFieldPath: "spec.parameters.tagValue"
|
||||
toFieldPath: spec.forProvider.tags[0].value
|
||||
- fromFieldPath: "spec.parameters.tagValue"
|
||||
toFieldPath: spec.forProvider.tags[1].value
|
||||
- type: PatchSet
|
||||
patchSetName: ps1
|
||||
- type: PatchSet
|
||||
patchSetName: ps2
|
||||
- type: PatchSet
|
||||
patchSetName: ps3
|
||||
- type: PatchSet
|
||||
patchSetName: ps4
|
||||
- type: PatchSet
|
||||
patchSetName: ps5
|
||||
- type: PatchSet
|
||||
patchSetName: ps6
|
||||
- fromFieldPath: "spec.parameters.tagValue"
|
||||
toFieldPath: spec.forProvider.param
|
|
@ -1,10 +0,0 @@
|
|||
# SPDX-FileCopyrightText: 2023 The Crossplane Authors <https://crossplane.io>
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
apiVersion: pkg.crossplane.io/v1
|
||||
kind: Configuration
|
||||
metadata:
|
||||
name: platform-ref-aws
|
||||
spec:
|
||||
package: xpkg.upbound.io/upbound/provider-ref-aws:v0.1.0
|
|
@ -1,40 +0,0 @@
|
|||
# SPDX-FileCopyrightText: 2023 The Crossplane Authors <https://crossplane.io>
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
apiVersion: meta.pkg.crossplane.io/v1
|
||||
kind: Configuration
|
||||
metadata:
|
||||
name: platform-ref-aws
|
||||
annotations:
|
||||
meta.crossplane.io/maintainer: Upbound <support@upbound.io>
|
||||
meta.crossplane.io/source: github.com/upbound/platform-ref-aws
|
||||
meta.crossplane.io/license: Apache-2.0
|
||||
meta.crossplane.io/description: |
|
||||
This reference platform Configuration for Kubernetes and Data Services
|
||||
is a starting point to build, run, and operate your own internal cloud
|
||||
platform and offer a self-service console and API to your internal teams.
|
||||
|
||||
meta.crossplane.io/readme: |
|
||||
This reference platform `Configuration` for Kubernetes and Data Services
|
||||
is a starting point to build, run, and operate your own internal cloud
|
||||
platform and offer a self-service console and API to your internal teams.
|
||||
It provides platform APIs to provision fully configured EKS clusters,
|
||||
with secure networking, and stateful cloud services (RDS) designed to
|
||||
securely connect to the nodes in each EKS cluster -- all composed using
|
||||
cloud service primitives from the [Upbound Official AWS
|
||||
Provider](https://marketplace.upbound.io/providers/upbound/provider-aws). App
|
||||
deployments can securely connect to the infrastructure they need using
|
||||
secrets distributed directly to the app namespace.
|
||||
|
||||
To learn more checkout the [GitHub
|
||||
repo](https://github.com/upbound/platform-ref-aws/) that you can copy and
|
||||
customize to meet the exact needs of your organization!
|
||||
spec:
|
||||
crossplane:
|
||||
version: ">=v1.7.0-0"
|
||||
dependsOn:
|
||||
- provider: xpkg.upbound.io/upbound/provider-aws
|
||||
version: ">=v0.15.0"
|
||||
- provider: xpkg.upbound.io/crossplane-contrib/provider-helm
|
||||
version: ">=v0.12.0"
|
|
@ -1,40 +0,0 @@
|
|||
# SPDX-FileCopyrightText: 2023 The Crossplane Authors <https://crossplane.io>
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
apiVersion: meta.pkg.crossplane.io/v1alpha1
|
||||
kind: Configuration
|
||||
metadata:
|
||||
name: platform-ref-aws
|
||||
annotations:
|
||||
meta.crossplane.io/maintainer: Upbound <support@upbound.io>
|
||||
meta.crossplane.io/source: github.com/upbound/platform-ref-aws
|
||||
meta.crossplane.io/license: Apache-2.0
|
||||
meta.crossplane.io/description: |
|
||||
This reference platform Configuration for Kubernetes and Data Services
|
||||
is a starting point to build, run, and operate your own internal cloud
|
||||
platform and offer a self-service console and API to your internal teams.
|
||||
|
||||
meta.crossplane.io/readme: |
|
||||
This reference platform `Configuration` for Kubernetes and Data Services
|
||||
is a starting point to build, run, and operate your own internal cloud
|
||||
platform and offer a self-service console and API to your internal teams.
|
||||
It provides platform APIs to provision fully configured EKS clusters,
|
||||
with secure networking, and stateful cloud services (RDS) designed to
|
||||
securely connect to the nodes in each EKS cluster -- all composed using
|
||||
cloud service primitives from the [Upbound Official AWS
|
||||
Provider](https://marketplace.upbound.io/providers/upbound/provider-aws). App
|
||||
deployments can securely connect to the infrastructure they need using
|
||||
secrets distributed directly to the app namespace.
|
||||
|
||||
To learn more checkout the [GitHub
|
||||
repo](https://github.com/upbound/platform-ref-aws/) that you can copy and
|
||||
customize to meet the exact needs of your organization!
|
||||
spec:
|
||||
crossplane:
|
||||
version: ">=v1.7.0-0"
|
||||
dependsOn:
|
||||
- provider: xpkg.upbound.io/upbound/provider-aws
|
||||
version: ">=v0.15.0"
|
||||
- provider: xpkg.upbound.io/crossplane-contrib/provider-helm
|
||||
version: ">=v0.12.0"
|
|
@ -1,10 +0,0 @@
|
|||
# SPDX-FileCopyrightText: 2023 The Crossplane Authors <https://crossplane.io>
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
apiVersion: pkg.crossplane.io/v1
|
||||
kind: Provider
|
||||
metadata:
|
||||
name: provider-aws-ec2
|
||||
spec:
|
||||
revisionActivationPolicy: Automatic
|
|
@ -1,10 +0,0 @@
|
|||
# SPDX-FileCopyrightText: 2023 The Crossplane Authors <https://crossplane.io>
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
apiVersion: pkg.crossplane.io/v1
|
||||
kind: Provider
|
||||
metadata:
|
||||
name: provider-aws-eks
|
||||
spec:
|
||||
revisionActivationPolicy: Automatic
|
|
@ -1,10 +0,0 @@
|
|||
# SPDX-FileCopyrightText: 2023 The Crossplane Authors <https://crossplane.io>
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
apiVersion: pkg.crossplane.io/v1
|
||||
kind: Provider
|
||||
metadata:
|
||||
name: provider-family-aws
|
||||
spec:
|
||||
revisionActivationPolicy: Automatic
|
|
@ -1,67 +0,0 @@
|
|||
# SPDX-FileCopyrightText: 2023 The Crossplane Authors <https://crossplane.io>
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
spec:
|
||||
steps:
|
||||
- exec:
|
||||
command: sh
|
||||
args:
|
||||
- "-c"
|
||||
- "kubectl get managed -o yaml > backup/managed-resources.yaml"
|
||||
name: backup-managed-resources
|
||||
manualExecution:
|
||||
- sh -c "kubectl get managed -o yaml > backup/managed-resources.yaml"
|
||||
type: Exec
|
||||
|
||||
- exec:
|
||||
command: sh
|
||||
args:
|
||||
- "-c"
|
||||
- "kubectl get composite -o yaml > backup/composite-resources.yaml"
|
||||
name: backup-composite-resources
|
||||
manualExecution:
|
||||
- sh -c "kubectl get composite -o yaml > backup/composite-resources.yaml"
|
||||
type: Exec
|
||||
|
||||
- exec:
|
||||
command: sh
|
||||
args:
|
||||
- "-c"
|
||||
- "kubectl get claim --all-namespaces -o yaml > backup/claim-resources.yaml"
|
||||
name: backup-claim-resources
|
||||
manualExecution:
|
||||
- sh -c "kubectl get claim --all-namespaces -o yaml > backup/claim-resources.yaml"
|
||||
type: Exec
|
||||
|
||||
- exec:
|
||||
command: sh
|
||||
args:
|
||||
- "-c"
|
||||
- "cp edit-configuration-metadata/platform-ref-aws.configurations.meta.pkg.crossplane.io_v1.yaml testdata/plan/configurationv1.yaml"
|
||||
name: edit-configuration-metadata
|
||||
manualExecution:
|
||||
- sh -c "cp edit-configuration-metadata/platform-ref-aws.configurations.meta.pkg.crossplane.io_v1.yaml testdata/plan/configurationv1.yaml"
|
||||
type: Exec
|
||||
|
||||
- exec:
|
||||
command: sh
|
||||
args:
|
||||
- "-c"
|
||||
- "up xpkg build --package-root={{PKG_ROOT}} --examples-root={{EXAMPLES_ROOT}} -o {{PKG_PATH}}"
|
||||
name: build-configuration
|
||||
manualExecution:
|
||||
- sh -c "up xpkg build --package-root={{PKG_ROOT}} --examples-root={{EXAMPLES_ROOT}} -o {{PKG_PATH}}"
|
||||
type: Exec
|
||||
|
||||
- exec:
|
||||
command: sh
|
||||
args:
|
||||
- "-c"
|
||||
- "up xpkg push {{TARGET_CONFIGURATION_PACKAGE}} -f {{PKG_PATH}}"
|
||||
name: push-configuration
|
||||
manualExecution:
|
||||
- sh -c "up xpkg push {{TARGET_CONFIGURATION_PACKAGE}} -f {{PKG_PATH}}"
|
||||
type: Exec
|
||||
|
||||
version: 0.1.0
|
|
@ -1,232 +0,0 @@
|
|||
# SPDX-FileCopyrightText: 2023 The Crossplane Authors <https://crossplane.io>
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
spec:
|
||||
steps:
|
||||
- exec:
|
||||
command: sh
|
||||
args:
|
||||
- "-c"
|
||||
- "kubectl get managed -o yaml > backup/managed-resources.yaml"
|
||||
name: backup-managed-resources
|
||||
manualExecution:
|
||||
- sh -c "kubectl get managed -o yaml > backup/managed-resources.yaml"
|
||||
type: Exec
|
||||
|
||||
- exec:
|
||||
command: sh
|
||||
args:
|
||||
- "-c"
|
||||
- "kubectl get composite -o yaml > backup/composite-resources.yaml"
|
||||
name: backup-composite-resources
|
||||
manualExecution:
|
||||
- sh -c "kubectl get composite -o yaml > backup/composite-resources.yaml"
|
||||
type: Exec
|
||||
|
||||
- exec:
|
||||
command: sh
|
||||
args:
|
||||
- "-c"
|
||||
- "kubectl get claim --all-namespaces -o yaml > backup/claim-resources.yaml"
|
||||
name: backup-claim-resources
|
||||
manualExecution:
|
||||
- sh -c "kubectl get claim --all-namespaces -o yaml > backup/claim-resources.yaml"
|
||||
type: Exec
|
||||
|
||||
- patch:
|
||||
type: merge
|
||||
files:
|
||||
- deletion-policy-orphan/sample-vpc.vpcs.fakesourceapi_v1alpha1.yaml
|
||||
name: deletion-policy-orphan
|
||||
manualExecution:
|
||||
- "kubectl patch --type='merge' -f deletion-policy-orphan/sample-vpc.vpcs.fakesourceapi_v1alpha1.yaml --patch-file deletion-policy-orphan/sample-vpc.vpcs.fakesourceapi_v1alpha1.yaml"
|
||||
type: Patch
|
||||
|
||||
- apply:
|
||||
files:
|
||||
- new-ssop/provider-family-aws.providers.pkg.crossplane.io_v1.yaml
|
||||
name: new-ssop
|
||||
manualExecution:
|
||||
- "kubectl apply -f new-ssop/provider-family-aws.providers.pkg.crossplane.io_v1.yaml"
|
||||
type: Apply
|
||||
|
||||
- exec:
|
||||
command: sh
|
||||
args:
|
||||
- "-c"
|
||||
- "kubectl wait provider.pkg provider-family-aws --for condition=Healthy"
|
||||
name: wait-for-healthy
|
||||
manualExecution:
|
||||
- sh -c "kubectl wait provider.pkg provider-family-aws --for condition=Healthy"
|
||||
type: Exec
|
||||
|
||||
- apply:
|
||||
files:
|
||||
- new-ssop/provider-aws-ec2.providers.pkg.crossplane.io_v1.yaml
|
||||
- new-ssop/provider-aws-eks.providers.pkg.crossplane.io_v1.yaml
|
||||
name: new-ssop
|
||||
manualExecution:
|
||||
- "kubectl apply -f new-ssop/provider-aws-ec2.providers.pkg.crossplane.io_v1.yaml"
|
||||
- "kubectl apply -f new-ssop/provider-aws-eks.providers.pkg.crossplane.io_v1.yaml"
|
||||
type: Apply
|
||||
|
||||
- exec:
|
||||
command: sh
|
||||
args:
|
||||
- "-c"
|
||||
- "kubectl wait provider.pkg provider-aws-ec2 --for condition=Healthy"
|
||||
name: wait-for-healthy
|
||||
manualExecution:
|
||||
- sh -c "kubectl wait provider.pkg provider-aws-ec2 --for condition=Healthy"
|
||||
type: Exec
|
||||
|
||||
- exec:
|
||||
command: sh
|
||||
args:
|
||||
- "-c"
|
||||
- "kubectl wait provider.pkg provider-aws-eks --for condition=Healthy"
|
||||
name: wait-for-healthy
|
||||
manualExecution:
|
||||
- sh -c "kubectl wait provider.pkg provider-aws-eks --for condition=Healthy"
|
||||
type: Exec
|
||||
|
||||
- patch:
|
||||
type: merge
|
||||
files:
|
||||
- disable-dependency-resolution/platform-ref-aws.configurations.pkg.crossplane.io_v1.yaml
|
||||
name: disable-dependency-resolution
|
||||
manualExecution:
|
||||
- "kubectl patch --type='merge' -f disable-dependency-resolution/platform-ref-aws.configurations.pkg.crossplane.io_v1.yaml --patch-file disable-dependency-resolution/platform-ref-aws.configurations.pkg.crossplane.io_v1.yaml"
|
||||
type: Patch
|
||||
|
||||
- patch:
|
||||
type: merge
|
||||
files:
|
||||
- edit-package-lock/lock.locks.pkg.crossplane.io_v1beta1.yaml
|
||||
name: edit-package-lock
|
||||
manualExecution:
|
||||
- "kubectl patch --type='merge' -f edit-package-lock/lock.locks.pkg.crossplane.io_v1beta1.yaml --patch-file edit-package-lock/lock.locks.pkg.crossplane.io_v1beta1.yaml"
|
||||
type: Patch
|
||||
|
||||
- delete:
|
||||
options:
|
||||
finalizerPolicy: Remove
|
||||
resources:
|
||||
- group: pkg.crossplane.io
|
||||
kind: Provider
|
||||
name: provider-aws
|
||||
version: v1
|
||||
name: delete-monolithic-provider
|
||||
manualExecution:
|
||||
- "kubectl delete Provider.pkg.crossplane.io provider-aws"
|
||||
type: Delete
|
||||
|
||||
- patch:
|
||||
type: merge
|
||||
files:
|
||||
- activate-ssop/provider-family-aws.providers.pkg.crossplane.io_v1.yaml
|
||||
name: activate-ssop
|
||||
manualExecution:
|
||||
- "kubectl patch --type='merge' -f activate-ssop/provider-family-aws.providers.pkg.crossplane.io_v1.yaml --patch-file activate-ssop/provider-family-aws.providers.pkg.crossplane.io_v1.yaml"
|
||||
type: Patch
|
||||
|
||||
- exec:
|
||||
command: sh
|
||||
args:
|
||||
- "-c"
|
||||
- "kubectl wait provider.pkg provider-family-aws --for condition=Installed"
|
||||
name: wait-for-installed
|
||||
manualExecution:
|
||||
- sh -c "kubectl wait provider.pkg provider-family-aws --for condition=Installed"
|
||||
type: Exec
|
||||
|
||||
- patch:
|
||||
type: merge
|
||||
files:
|
||||
- activate-ssop/provider-aws-ec2.providers.pkg.crossplane.io_v1.yaml
|
||||
- activate-ssop/provider-aws-eks.providers.pkg.crossplane.io_v1.yaml
|
||||
name: activate-ssop
|
||||
manualExecution:
|
||||
- "kubectl patch --type='merge' -f activate-ssop/provider-aws-ec2.providers.pkg.crossplane.io_v1.yaml --patch-file activate-ssop/provider-aws-ec2.providers.pkg.crossplane.io_v1.yaml"
|
||||
- "kubectl patch --type='merge' -f activate-ssop/provider-aws-eks.providers.pkg.crossplane.io_v1.yaml --patch-file activate-ssop/provider-aws-eks.providers.pkg.crossplane.io_v1.yaml"
|
||||
type: Patch
|
||||
|
||||
- exec:
|
||||
command: sh
|
||||
args:
|
||||
- "-c"
|
||||
- "kubectl wait provider.pkg provider-aws-ec2 --for condition=Installed"
|
||||
name: wait-for-installed
|
||||
manualExecution:
|
||||
- sh -c "kubectl wait provider.pkg provider-aws-ec2 --for condition=Installed"
|
||||
type: Exec
|
||||
|
||||
- exec:
|
||||
command: sh
|
||||
args:
|
||||
- "-c"
|
||||
- "kubectl wait provider.pkg provider-aws-eks --for condition=Installed"
|
||||
name: wait-for-installed
|
||||
manualExecution:
|
||||
- sh -c "kubectl wait provider.pkg provider-aws-eks --for condition=Installed"
|
||||
type: Exec
|
||||
|
||||
- exec:
|
||||
command: sh
|
||||
args:
|
||||
- "-c"
|
||||
- "cp edit-configuration-metadata/platform-ref-aws.configurations.meta.pkg.crossplane.io_v1.yaml testdata/plan/configurationv1.yaml"
|
||||
name: edit-configuration-metadata
|
||||
manualExecution:
|
||||
- sh -c "cp edit-configuration-metadata/platform-ref-aws.configurations.meta.pkg.crossplane.io_v1.yaml testdata/plan/configurationv1.yaml"
|
||||
type: Exec
|
||||
|
||||
- exec:
|
||||
command: sh
|
||||
args:
|
||||
- "-c"
|
||||
- "up xpkg build --package-root={{PKG_ROOT}} --examples-root={{EXAMPLES_ROOT}} -o {{PKG_PATH}}"
|
||||
name: build-configuration
|
||||
manualExecution:
|
||||
- sh -c "up xpkg build --package-root={{PKG_ROOT}} --examples-root={{EXAMPLES_ROOT}} -o {{PKG_PATH}}"
|
||||
type: Exec
|
||||
|
||||
- exec:
|
||||
command: sh
|
||||
args:
|
||||
- "-c"
|
||||
- "up xpkg push {{TARGET_CONFIGURATION_PACKAGE}} -f {{PKG_PATH}}"
|
||||
name: push-configuration
|
||||
manualExecution:
|
||||
- sh -c "up xpkg push {{TARGET_CONFIGURATION_PACKAGE}} -f {{PKG_PATH}}"
|
||||
type: Exec
|
||||
|
||||
- patch:
|
||||
type: merge
|
||||
files:
|
||||
- edit-configuration-package/platform-ref-aws.configurations.pkg.crossplane.io_v1.yaml
|
||||
name: edit-configuration-package
|
||||
manualExecution:
|
||||
- "kubectl patch --type='merge' -f edit-configuration-package/platform-ref-aws.configurations.pkg.crossplane.io_v1.yaml --patch-file edit-configuration-package/platform-ref-aws.configurations.pkg.crossplane.io_v1.yaml"
|
||||
type: Patch
|
||||
|
||||
- patch:
|
||||
type: merge
|
||||
files:
|
||||
- enable-dependency-resolution/platform-ref-aws.configurations.pkg.crossplane.io_v1.yaml
|
||||
name: enable-dependency-resolution
|
||||
manualExecution:
|
||||
- "kubectl patch --type='merge' -f enable-dependency-resolution/platform-ref-aws.configurations.pkg.crossplane.io_v1.yaml --patch-file enable-dependency-resolution/platform-ref-aws.configurations.pkg.crossplane.io_v1.yaml"
|
||||
type: Patch
|
||||
|
||||
- patch:
|
||||
type: merge
|
||||
files:
|
||||
- deletion-policy-delete/sample-vpc.vpcs.fakesourceapi_v1alpha1.yaml
|
||||
name: deletion-policy-delete
|
||||
manualExecution:
|
||||
- "kubectl patch --type='merge' -f deletion-policy-delete/sample-vpc.vpcs.fakesourceapi_v1alpha1.yaml --patch-file deletion-policy-delete/sample-vpc.vpcs.fakesourceapi_v1alpha1.yaml"
|
||||
type: Patch
|
||||
|
||||
version: 0.1.0
|
|
@ -1,67 +0,0 @@
|
|||
# SPDX-FileCopyrightText: 2023 The Crossplane Authors <https://crossplane.io>
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
spec:
|
||||
steps:
|
||||
- exec:
|
||||
command: sh
|
||||
args:
|
||||
- "-c"
|
||||
- "kubectl get managed -o yaml > backup/managed-resources.yaml"
|
||||
name: backup-managed-resources
|
||||
manualExecution:
|
||||
- sh -c "kubectl get managed -o yaml > backup/managed-resources.yaml"
|
||||
type: Exec
|
||||
|
||||
- exec:
|
||||
command: sh
|
||||
args:
|
||||
- "-c"
|
||||
- "kubectl get composite -o yaml > backup/composite-resources.yaml"
|
||||
name: backup-composite-resources
|
||||
manualExecution:
|
||||
- sh -c "kubectl get composite -o yaml > backup/composite-resources.yaml"
|
||||
type: Exec
|
||||
|
||||
- exec:
|
||||
command: sh
|
||||
args:
|
||||
- "-c"
|
||||
- "kubectl get claim --all-namespaces -o yaml > backup/claim-resources.yaml"
|
||||
name: backup-claim-resources
|
||||
manualExecution:
|
||||
- sh -c "kubectl get claim --all-namespaces -o yaml > backup/claim-resources.yaml"
|
||||
type: Exec
|
||||
|
||||
- exec:
|
||||
command: sh
|
||||
args:
|
||||
- "-c"
|
||||
- "cp edit-configuration-metadata/platform-ref-aws.configurations.meta.pkg.crossplane.io_v1alpha1.yaml testdata/plan/configurationv1alpha1.yaml"
|
||||
name: edit-configuration-metadata
|
||||
manualExecution:
|
||||
- sh -c "cp edit-configuration-metadata/platform-ref-aws.configurations.meta.pkg.crossplane.io_v1alpha1.yaml testdata/plan/configurationv1alpha1.yaml"
|
||||
type: Exec
|
||||
|
||||
- exec:
|
||||
command: sh
|
||||
args:
|
||||
- "-c"
|
||||
- "up xpkg build --package-root={{PKG_ROOT}} --examples-root={{EXAMPLES_ROOT}} -o {{PKG_PATH}}"
|
||||
name: build-configuration
|
||||
manualExecution:
|
||||
- sh -c "up xpkg build --package-root={{PKG_ROOT}} --examples-root={{EXAMPLES_ROOT}} -o {{PKG_PATH}}"
|
||||
type: Exec
|
||||
|
||||
- exec:
|
||||
command: sh
|
||||
args:
|
||||
- "-c"
|
||||
- "up xpkg push {{TARGET_CONFIGURATION_PACKAGE}} -f {{PKG_PATH}}"
|
||||
name: push-configuration
|
||||
manualExecution:
|
||||
- sh -c "up xpkg push {{TARGET_CONFIGURATION_PACKAGE}} -f {{PKG_PATH}}"
|
||||
type: Exec
|
||||
|
||||
version: 0.1.0
|
|
@ -1,19 +0,0 @@
|
|||
# SPDX-FileCopyrightText: 2023 The Crossplane Authors <https://crossplane.io>
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
apiVersion: faketargetapi/v1alpha1
|
||||
kind: VPC
|
||||
metadata:
|
||||
annotations:
|
||||
crossplane.io/paused: "true"
|
||||
name: sample-vpc
|
||||
mockManaged:
|
||||
ctrl: null
|
||||
recorder: null
|
||||
spec:
|
||||
forProvider:
|
||||
cidrBlock: 172.16.0.0/16
|
||||
region: us-west-1
|
||||
tags:
|
||||
tag1: value1
|
|
@ -1,10 +0,0 @@
|
|||
# SPDX-FileCopyrightText: 2023 The Crossplane Authors <https://crossplane.io>
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
apiVersion: fakesourceapi/v1alpha1
|
||||
kind: VPC
|
||||
metadata:
|
||||
name: sample-vpc
|
||||
spec:
|
||||
deletionPolicy: Delete
|
|
@ -1,10 +0,0 @@
|
|||
# SPDX-FileCopyrightText: 2023 The Crossplane Authors <https://crossplane.io>
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
apiVersion: fakesourceapi/v1alpha1
|
||||
kind: VPC
|
||||
metadata:
|
||||
name: sample-vpc
|
||||
spec:
|
||||
deletionPolicy: Orphan
|
|
@ -1,10 +0,0 @@
|
|||
# SPDX-FileCopyrightText: 2023 The Crossplane Authors <https://crossplane.io>
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
apiVersion: fakesourceapi/v1alpha1
|
||||
kind: VPC
|
||||
metadata:
|
||||
name: sample-vpc
|
||||
spec:
|
||||
deletionPolicy: Orphan
|
|
@ -1,10 +0,0 @@
|
|||
# SPDX-FileCopyrightText: 2023 The Crossplane Authors <https://crossplane.io>
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
apiVersion: pkg.crossplane.io/v1
|
||||
kind: Configuration
|
||||
metadata:
|
||||
name: platform-ref-aws
|
||||
spec:
|
||||
skipDependencyResolution: true
|
|
@ -1,12 +0,0 @@
|
|||
# SPDX-FileCopyrightText: 2023 The Crossplane Authors <https://crossplane.io>
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
apiVersion: test.com/v1alpha1
|
||||
kind: MyResource
|
||||
metadata:
|
||||
name: my-resource
|
||||
namespace: upbound-system
|
||||
spec:
|
||||
compositionRef:
|
||||
name: example-migrated
|
|
@ -1,15 +0,0 @@
|
|||
# SPDX-FileCopyrightText: 2023 The Crossplane Authors <https://crossplane.io>
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
apiVersion: test.com/v1alpha1
|
||||
kind: XMyResource
|
||||
metadata:
|
||||
name: my-resource-dwjgh
|
||||
spec:
|
||||
compositionRef:
|
||||
name: example-migrated
|
||||
resourceRefs:
|
||||
- apiVersion: faketargetapi/v1alpha1
|
||||
kind: VPC
|
||||
name: sample-vpc
|
|
@ -1,38 +0,0 @@
|
|||
# SPDX-FileCopyrightText: 2023 The Crossplane Authors <https://crossplane.io>
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
apiVersion: meta.pkg.crossplane.io/v1
|
||||
kind: Configuration
|
||||
metadata:
|
||||
name: platform-ref-aws
|
||||
annotations:
|
||||
meta.crossplane.io/maintainer: Upbound <support@upbound.io>
|
||||
meta.crossplane.io/source: github.com/upbound/platform-ref-aws
|
||||
meta.crossplane.io/license: Apache-2.0
|
||||
meta.crossplane.io/description: |
|
||||
This reference platform Configuration for Kubernetes and Data Services
|
||||
is a starting point to build, run, and operate your own internal cloud
|
||||
platform and offer a self-service console and API to your internal teams.
|
||||
|
||||
meta.crossplane.io/readme: |
|
||||
This reference platform `Configuration` for Kubernetes and Data Services
|
||||
is a starting point to build, run, and operate your own internal cloud
|
||||
platform and offer a self-service console and API to your internal teams.
|
||||
It provides platform APIs to provision fully configured EKS clusters,
|
||||
with secure networking, and stateful cloud services (RDS) designed to
|
||||
securely connect to the nodes in each EKS cluster -- all composed using
|
||||
cloud service primitives from the [Upbound Official AWS
|
||||
Provider](https://marketplace.upbound.io/providers/upbound/provider-aws). App
|
||||
deployments can securely connect to the infrastructure they need using
|
||||
secrets distributed directly to the app namespace.
|
||||
|
||||
To learn more checkout the [GitHub
|
||||
repo](https://github.com/upbound/platform-ref-aws/) that you can copy and
|
||||
customize to meet the exact needs of your organization!
|
||||
spec:
|
||||
crossplane:
|
||||
version: ">=v1.7.0-0"
|
||||
dependsOn:
|
||||
- provider: xpkg.upbound.io/upbound/provider-aws-eks
|
||||
version: ">=v0.17.0"
|
|
@ -1,38 +0,0 @@
|
|||
# SPDX-FileCopyrightText: 2023 The Crossplane Authors <https://crossplane.io>
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
apiVersion: meta.pkg.crossplane.io/v1alpha1
|
||||
kind: Configuration
|
||||
metadata:
|
||||
name: platform-ref-aws
|
||||
annotations:
|
||||
meta.crossplane.io/maintainer: Upbound <support@upbound.io>
|
||||
meta.crossplane.io/source: github.com/upbound/platform-ref-aws
|
||||
meta.crossplane.io/license: Apache-2.0
|
||||
meta.crossplane.io/description: |
|
||||
This reference platform Configuration for Kubernetes and Data Services
|
||||
is a starting point to build, run, and operate your own internal cloud
|
||||
platform and offer a self-service console and API to your internal teams.
|
||||
|
||||
meta.crossplane.io/readme: |
|
||||
This reference platform `Configuration` for Kubernetes and Data Services
|
||||
is a starting point to build, run, and operate your own internal cloud
|
||||
platform and offer a self-service console and API to your internal teams.
|
||||
It provides platform APIs to provision fully configured EKS clusters,
|
||||
with secure networking, and stateful cloud services (RDS) designed to
|
||||
securely connect to the nodes in each EKS cluster -- all composed using
|
||||
cloud service primitives from the [Upbound Official AWS
|
||||
Provider](https://marketplace.upbound.io/providers/upbound/provider-aws). App
|
||||
deployments can securely connect to the infrastructure they need using
|
||||
secrets distributed directly to the app namespace.
|
||||
|
||||
To learn more checkout the [GitHub
|
||||
repo](https://github.com/upbound/platform-ref-aws/) that you can copy and
|
||||
customize to meet the exact needs of your organization!
|
||||
spec:
|
||||
crossplane:
|
||||
version: ">=v1.7.0-0"
|
||||
dependsOn:
|
||||
- provider: xpkg.upbound.io/upbound/provider-aws-eks
|
||||
version: ">=v0.17.0"
|
|
@ -1,10 +0,0 @@
|
|||
# SPDX-FileCopyrightText: 2023 The Crossplane Authors <https://crossplane.io>
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
apiVersion: pkg.crossplane.io/v1
|
||||
kind: Configuration
|
||||
metadata:
|
||||
name: platform-ref-aws
|
||||
spec:
|
||||
package: xpkg.upbound.io/upbound/provider-ref-aws:v0.2.0-ssop
|
|
@ -1,17 +0,0 @@
|
|||
# SPDX-FileCopyrightText: 2023 The Crossplane Authors <https://crossplane.io>
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
apiVersion: pkg.crossplane.io/v1beta1
|
||||
kind: Lock
|
||||
metadata:
|
||||
name: lock
|
||||
packages:
|
||||
- name: provider-aws
|
||||
type: Provider
|
||||
source: xpkg.upbound.io/upbound/provider-aws
|
||||
version: v0.36.0
|
||||
- name: test-provider
|
||||
type: Provider
|
||||
source: xpkg.upbound.io/upbound/test-provider
|
||||
version: vX.Y.Z
|
|
@ -1,10 +0,0 @@
|
|||
# SPDX-FileCopyrightText: 2023 The Crossplane Authors <https://crossplane.io>
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
apiVersion: pkg.crossplane.io/v1
|
||||
kind: Configuration
|
||||
metadata:
|
||||
name: platform-ref-aws
|
||||
spec:
|
||||
skipDependencyResolution: false
|
|
@ -1,108 +0,0 @@
|
|||
# SPDX-FileCopyrightText: 2023 The Crossplane Authors <https://crossplane.io>
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
spec:
|
||||
steps:
|
||||
- patch:
|
||||
type: merge
|
||||
files:
|
||||
- pause-managed/sample-vpc.vpcs.fakesourceapi.yaml
|
||||
name: pause-managed
|
||||
manualExecution:
|
||||
- "kubectl patch --type='merge' -f pause-managed/sample-vpc.vpcs.fakesourceapi.yaml --patch-file pause-managed/sample-vpc.vpcs.fakesourceapi.yaml"
|
||||
type: Patch
|
||||
|
||||
- patch:
|
||||
type: merge
|
||||
files:
|
||||
- pause-composites/my-resource-dwjgh.xmyresources.test.com.yaml
|
||||
name: pause-composites
|
||||
manualExecution:
|
||||
- "kubectl patch --type='merge' -f pause-composites/my-resource-dwjgh.xmyresources.test.com.yaml --patch-file pause-composites/my-resource-dwjgh.xmyresources.test.com.yaml"
|
||||
type: Patch
|
||||
|
||||
- apply:
|
||||
files:
|
||||
- create-new-managed/sample-vpc.vpcs.faketargetapi.yaml
|
||||
name: create-new-managed
|
||||
manualExecution:
|
||||
- "kubectl apply -f create-new-managed/sample-vpc.vpcs.faketargetapi.yaml"
|
||||
type: Apply
|
||||
|
||||
- apply:
|
||||
files:
|
||||
- new-compositions/example-migrated.compositions.apiextensions.crossplane.io.yaml
|
||||
name: new-compositions
|
||||
manualExecution:
|
||||
- "kubectl apply -f new-compositions/example-migrated.compositions.apiextensions.crossplane.io.yaml"
|
||||
type: Apply
|
||||
|
||||
- patch:
|
||||
type: merge
|
||||
files:
|
||||
- edit-composites/my-resource-dwjgh.xmyresources.test.com.yaml
|
||||
name: edit-composites
|
||||
manualExecution:
|
||||
- "kubectl patch --type='merge' -f edit-composites/my-resource-dwjgh.xmyresources.test.com.yaml --patch-file edit-composites/my-resource-dwjgh.xmyresources.test.com.yaml"
|
||||
type: Patch
|
||||
|
||||
- patch:
|
||||
type: merge
|
||||
files:
|
||||
- edit-claims/my-resource.myresources.test.com.yaml
|
||||
name: edit-claims
|
||||
manualExecution:
|
||||
- "kubectl patch --type='merge' -f edit-claims/my-resource.myresources.test.com.yaml --patch-file edit-claims/my-resource.myresources.test.com.yaml"
|
||||
type: Patch
|
||||
|
||||
- patch:
|
||||
type: merge
|
||||
files:
|
||||
- deletion-policy-orphan/sample-vpc.vpcs.fakesourceapi.yaml
|
||||
name: deletion-policy-orphan
|
||||
manualExecution:
|
||||
- "kubectl patch --type='merge' -f deletion-policy-orphan/sample-vpc.vpcs.fakesourceapi.yaml --patch-file deletion-policy-orphan/sample-vpc.vpcs.fakesourceapi.yaml"
|
||||
type: Patch
|
||||
|
||||
- patch:
|
||||
type: merge
|
||||
files:
|
||||
- remove-finalizers/sample-vpc.vpcs.fakesourceapi.yaml
|
||||
name: remove-finalizers
|
||||
manualExecution:
|
||||
- "kubectl patch --type='merge' -f remove-finalizers/sample-vpc.vpcs.fakesourceapi.yaml --patch-file remove-finalizers/sample-vpc.vpcs.fakesourceapi.yaml"
|
||||
type: Patch
|
||||
|
||||
- delete:
|
||||
options:
|
||||
finalizerPolicy: Remove
|
||||
resources:
|
||||
- group: fakesourceapi
|
||||
kind: VPC
|
||||
name: sample-vpc
|
||||
version: v1alpha1
|
||||
name: delete-old-managed
|
||||
manualExecution:
|
||||
- "kubectl delete VPC.fakesourceapi sample-vpc"
|
||||
type: Delete
|
||||
|
||||
- patch:
|
||||
type: merge
|
||||
files:
|
||||
- start-managed/sample-vpc.vpcs.faketargetapi.yaml
|
||||
name: start-managed
|
||||
manualExecution:
|
||||
- "kubectl patch --type='merge' -f start-managed/sample-vpc.vpcs.faketargetapi.yaml --patch-file start-managed/sample-vpc.vpcs.faketargetapi.yaml"
|
||||
type: Patch
|
||||
|
||||
- patch:
|
||||
type: merge
|
||||
files:
|
||||
- start-composites/my-resource-dwjgh.xmyresources.test.com.yaml
|
||||
name: start-composites
|
||||
manualExecution:
|
||||
- "kubectl patch --type='merge' -f start-composites/my-resource-dwjgh.xmyresources.test.com.yaml --patch-file start-composites/my-resource-dwjgh.xmyresources.test.com.yaml"
|
||||
type: Patch
|
||||
|
||||
version: 0.1.0
|
|
@ -1,59 +0,0 @@
|
|||
# SPDX-FileCopyrightText: 2023 The Crossplane Authors <https://crossplane.io>
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
spec:
|
||||
steps:
|
||||
- apply:
|
||||
files:
|
||||
- create-new-managed/sample-vpc.vpcs.faketargetapi.yaml
|
||||
name: create-new-managed
|
||||
manualExecution:
|
||||
- "kubectl apply -f create-new-managed/sample-vpc.vpcs.faketargetapi.yaml"
|
||||
type: Apply
|
||||
|
||||
- apply:
|
||||
files:
|
||||
- new-compositions/example-migrated.compositions.apiextensions.crossplane.io.yaml
|
||||
name: new-compositions
|
||||
manualExecution:
|
||||
- "kubectl apply -f new-compositions/example-migrated.compositions.apiextensions.crossplane.io.yaml"
|
||||
type: Apply
|
||||
|
||||
- patch:
|
||||
type: merge
|
||||
files:
|
||||
- edit-composites/my-resource-dwjgh.xmyresources.test.com.yaml
|
||||
name: edit-composites
|
||||
manualExecution:
|
||||
- "kubectl patch --type='merge' -f edit-composites/my-resource-dwjgh.xmyresources.test.com.yaml --patch-file edit-composites/my-resource-dwjgh.xmyresources.test.com.yaml"
|
||||
type: Patch
|
||||
|
||||
- patch:
|
||||
type: merge
|
||||
files:
|
||||
- edit-claims/my-resource.myresources.test.com.yaml
|
||||
name: edit-claims
|
||||
manualExecution:
|
||||
- "kubectl patch --type='merge' -f edit-claims/my-resource.myresources.test.com.yaml --patch-file edit-claims/my-resource.myresources.test.com.yaml"
|
||||
type: Patch
|
||||
|
||||
- patch:
|
||||
type: merge
|
||||
files:
|
||||
- start-managed/sample-vpc.vpcs.faketargetapi.yaml
|
||||
name: start-managed
|
||||
manualExecution:
|
||||
- "kubectl patch --type='merge' -f start-managed/sample-vpc.vpcs.faketargetapi.yaml --patch-file start-managed/sample-vpc.vpcs.faketargetapi.yaml"
|
||||
type: Patch
|
||||
|
||||
- patch:
|
||||
type: merge
|
||||
files:
|
||||
- start-composites/my-resource-dwjgh.xmyresources.test.com.yaml
|
||||
name: start-composites
|
||||
manualExecution:
|
||||
- "kubectl patch --type='merge' -f start-composites/my-resource-dwjgh.xmyresources.test.com.yaml --patch-file start-composites/my-resource-dwjgh.xmyresources.test.com.yaml"
|
||||
type: Patch
|
||||
|
||||
version: 0.1.0
|
|
@ -1,78 +0,0 @@
|
|||
# SPDX-FileCopyrightText: 2023 The Crossplane Authors <https://crossplane.io>
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
apiVersion: apiextensions.crossplane.io/v1
|
||||
kind: Composition
|
||||
metadata:
|
||||
labels:
|
||||
purpose: example
|
||||
name: example-migrated
|
||||
spec:
|
||||
compositeTypeRef:
|
||||
apiVersion: test.com/v1alpha1
|
||||
kind: XMyResource
|
||||
patchSets:
|
||||
- name: not-referenced
|
||||
patches:
|
||||
- fromFieldPath: "spec.parameters.tagValue"
|
||||
toFieldPath: spec.forProvider.myTag
|
||||
- name: ps1
|
||||
patches:
|
||||
- fromFieldPath: "spec.parameters.tagValue"
|
||||
toFieldPath: spec.forProvider.tags["key3"]
|
||||
- name: ps2
|
||||
patches:
|
||||
- fromFieldPath: "spec.parameters.region"
|
||||
toFieldPath: spec.forProvider.region
|
||||
- name: ps3
|
||||
patches:
|
||||
- fromFieldPath: "spec.parameters.tagValue"
|
||||
toFieldPath: metadata.labels[a.b.c.d/tag-value]
|
||||
- name: ps4
|
||||
patches:
|
||||
- fromFieldPath: "spec.parameters.tagValue"
|
||||
toFieldPath: metadata.labels['a.b.c.d.e/tag-value']
|
||||
- name: ps5
|
||||
patches:
|
||||
- fromFieldPath: "spec.parameters.tagValue"
|
||||
toFieldPath: metadata.labels["a.b.c.d.e.f/tag-value"]
|
||||
- name: ps6
|
||||
patches:
|
||||
- fromFieldPath: "spec.parameters.tagValue"
|
||||
toFieldPath: spec.forProvider.tags["key4"]
|
||||
resources:
|
||||
- base:
|
||||
apiVersion: faketargetapi/v1alpha1
|
||||
kind: VPC
|
||||
mockManaged:
|
||||
ctrl: null
|
||||
recorder: null
|
||||
spec:
|
||||
forProvider:
|
||||
cidrBlock: 192.168.0.0/16
|
||||
region: us-west-1
|
||||
tags:
|
||||
key1: val1
|
||||
key2: val2
|
||||
key3: val3
|
||||
name: vpc
|
||||
patches:
|
||||
- fromFieldPath: spec.parameters.tagValue
|
||||
toFieldPath: spec.forProvider.tags["key1"]
|
||||
- fromFieldPath: spec.parameters.tagValue
|
||||
toFieldPath: spec.forProvider.tags["key2"]
|
||||
- type: PatchSet
|
||||
patchSetName: ps1
|
||||
- type: PatchSet
|
||||
patchSetName: ps2
|
||||
- type: PatchSet
|
||||
patchSetName: ps3
|
||||
- type: PatchSet
|
||||
patchSetName: ps4
|
||||
- type: PatchSet
|
||||
patchSetName: ps5
|
||||
- type: PatchSet
|
||||
patchSetName: ps6
|
||||
- fromFieldPath: "spec.parameters.tagValue"
|
||||
toFieldPath: spec.forProvider.param
|
|
@ -1,11 +0,0 @@
|
|||
# SPDX-FileCopyrightText: 2023 The Crossplane Authors <https://crossplane.io>
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
apiVersion: pkg.crossplane.io/v1
|
||||
kind: Provider
|
||||
metadata:
|
||||
name: provider-aws-ec2
|
||||
spec:
|
||||
package: xpkg.upbound.io/upbound/provider-aws-ec2:v0.37.0
|
||||
revisionActivationPolicy: Manual
|
|
@ -1,11 +0,0 @@
|
|||
# SPDX-FileCopyrightText: 2023 The Crossplane Authors <https://crossplane.io>
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
apiVersion: pkg.crossplane.io/v1
|
||||
kind: Provider
|
||||
metadata:
|
||||
name: provider-aws-eks
|
||||
spec:
|
||||
package: xpkg.upbound.io/upbound/provider-aws-eks:v0.37.0
|
||||
revisionActivationPolicy: Manual
|
|
@ -1,11 +0,0 @@
|
|||
# SPDX-FileCopyrightText: 2023 The Crossplane Authors <https://crossplane.io>
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
apiVersion: pkg.crossplane.io/v1
|
||||
kind: Provider
|
||||
metadata:
|
||||
name: provider-family-aws
|
||||
spec:
|
||||
package: xpkg.upbound.io/upbound/provider-family-aws:v0.37.0
|
||||
revisionActivationPolicy: Manual
|
|
@ -1,10 +0,0 @@
|
|||
# SPDX-FileCopyrightText: 2023 The Crossplane Authors <https://crossplane.io>
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
apiVersion: test.com/v1alpha1
|
||||
kind: XMyResource
|
||||
metadata:
|
||||
annotations:
|
||||
crossplane.io/paused: "true"
|
||||
name: my-resource-dwjgh
|
|
@ -1,10 +0,0 @@
|
|||
# SPDX-FileCopyrightText: 2023 The Crossplane Authors <https://crossplane.io>
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
apiVersion: fakesourceapi/v1alpha1
|
||||
kind: VPC
|
||||
metadata:
|
||||
annotations:
|
||||
crossplane.io/paused: "true"
|
||||
name: sample-vpc
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue