From d1140d54e8dc1284ddde5d3d8483ce4b4e50f42d Mon Sep 17 00:00:00 2001 From: Daniel Fan Date: Sun, 12 Mar 2023 23:43:53 -0400 Subject: [PATCH 001/179] tolerate multi entries for same subscription (#907) * tolerate multi entries for same subscription in one OperandRequest Signed-off-by: Daniel Fan * bump to go 1.20 Signed-off-by: Daniel Fan --------- Signed-off-by: Daniel Fan --- common/config/.golangci.yml | 2 +- .../operandrequest_controller.go | 4 ++-- .../operandrequest/reconcile_operand.go | 4 ++-- .../operandrequest/reconcile_operator.go | 14 +++++------ go.mod | 13 +++++------ go.sum | 23 ++++++++++--------- 6 files changed, 30 insertions(+), 30 deletions(-) diff --git a/common/config/.golangci.yml b/common/config/.golangci.yml index 342f8f8c..27973311 100644 --- a/common/config/.golangci.yml +++ b/common/config/.golangci.yml @@ -1,6 +1,6 @@ service: # When updating this, also update the version stored in docker/build-tools/Dockerfile in the multicloudlab/tools repo. - golangci-lint-version: 1.18.x # use the fixed version to not introduce new linters unexpectedly + golangci-lint-version: 1.51.x # use the fixed version to not introduce new linters unexpectedly run: # timeout for analysis, e.g. 30s, 5m, default is 1m deadline: 20m diff --git a/controllers/operandrequest/operandrequest_controller.go b/controllers/operandrequest/operandrequest_controller.go index 88da6493..c25089d4 100644 --- a/controllers/operandrequest/operandrequest_controller.go +++ b/controllers/operandrequest/operandrequest_controller.go @@ -245,14 +245,14 @@ func (r *Reconciler) getRegistryToRequestMapper() handler.MapFunc { func (r *Reconciler) getSubToRequestMapper() handler.MapFunc { return func(object client.Object) []ctrl.Request { - reg, _ := regexp.Compile(`^(.*)\.(.*)\/request`) + reg, _ := regexp.Compile(`^(.*)\.(.*)\.(.*)\/request`) annotations := object.GetAnnotations() var reqName, reqNamespace string for annotation := range annotations { if reg.MatchString(annotation) { annotationSlices := strings.Split(annotation, ".") reqNamespace = annotationSlices[0] - reqName = strings.Split(annotationSlices[1], "/")[0] + reqName = annotationSlices[1] } } if reqNamespace == "" || reqName == "" { diff --git a/controllers/operandrequest/reconcile_operand.go b/controllers/operandrequest/reconcile_operand.go index ab0559c0..50876ced 100644 --- a/controllers/operandrequest/reconcile_operand.go +++ b/controllers/operandrequest/reconcile_operand.go @@ -160,14 +160,14 @@ func (r *Reconciler) reconcileOperand(ctx context.Context, requestInstance *oper // find the OperandRequest which has the same operator's channel version as existing subscription. // ODLM will only reconcile Operand based on OperandConfig for this OperandRequest var requestList []string - reg, _ := regexp.Compile(`^(.*)\.(.*)\/request`) + reg, _ := regexp.Compile(`^(.*)\.(.*)\.(.*)\/request`) for anno, version := range sub.Annotations { if reg.MatchString(anno) && version == sub.Spec.Channel { requestList = append(requestList, anno) } } - if len(requestList) == 0 || !util.Contains(requestList, requestInstance.Namespace+"."+requestInstance.Name+"/request") { + if len(requestList) == 0 || !util.Contains(requestList, requestInstance.Namespace+"."+requestInstance.Name+"."+operand.Name+"/request") { klog.V(2).Infof("Subscription %s in the namespace %s is NOT managed by %s/%s, Skip reconciling Operands", sub.Name, sub.Namespace, requestInstance.Namespace, requestInstance.Name) requestInstance.SetMemberStatus(operand.Name, "", operatorv1alpha1.ServiceRunning, &r.Mutex) continue diff --git a/controllers/operandrequest/reconcile_operator.go b/controllers/operandrequest/reconcile_operator.go index 6ed964db..812c476f 100644 --- a/controllers/operandrequest/reconcile_operator.go +++ b/controllers/operandrequest/reconcile_operator.go @@ -194,7 +194,7 @@ func (r *Reconciler) reconcileSubscription(ctx context.Context, requestInstance } sub.Annotations[registryKey.Namespace+"."+registryKey.Name+"/registry"] = "true" sub.Annotations[registryKey.Namespace+"."+registryKey.Name+"/config"] = "true" - sub.Annotations[requestInstance.Namespace+"."+requestInstance.Name+"/request"] = opt.Channel + sub.Annotations[requestInstance.Namespace+"."+requestInstance.Name+"."+operand.Name+"/request"] = opt.Channel sub.Spec.CatalogSource = opt.SourceName sub.Spec.CatalogSourceNamespace = opt.SourceNamespace @@ -202,7 +202,7 @@ func (r *Reconciler) reconcileSubscription(ctx context.Context, requestInstance // check request annotation in subscription, get all available channels var semverlList []string - reg, _ := regexp.Compile(`^(.*)\.(.*)\/request`) + reg, _ := regexp.Compile(`^(.*)\.(.*)\.(.*)\/request`) for anno, channel := range sub.Annotations { if reg.MatchString(anno) && semver.IsValid(channel) { semverlList = append(semverlList, channel) @@ -331,11 +331,11 @@ func (r *Reconciler) deleteSubscription(ctx context.Context, operandName string, // remove request in annotation of subscription reqName := requestInstance.ObjectMeta.Name reqNs := requestInstance.ObjectMeta.Namespace - delete(sub.Annotations, reqNs+"."+reqName+"/request") + delete(sub.Annotations, reqNs+"."+reqName+"."+op.Name+"/request") var semverlList []string var annoSlice []string - reg, _ := regexp.Compile(`^(.*)\.(.*)\/request`) + reg, _ := regexp.Compile(`^(.*)\.(.*)\.(.*)\/request`) for anno, channel := range sub.Annotations { if reg.MatchString(anno) { annoSlice = append(annoSlice, anno) @@ -483,9 +483,9 @@ func (r *Reconciler) generateClusterObjects(o *operatorv1alpha1.Operator, regist constant.OpreqLabel: "true", } annotations := map[string]string{ - registryKey.Namespace + "." + registryKey.Name + "/registry": "true", - registryKey.Namespace + "." + registryKey.Name + "/config": "true", - requestKey.Namespace + "." + requestKey.Name + "/request": o.Channel, + registryKey.Namespace + "." + registryKey.Name + "/registry": "true", + registryKey.Namespace + "." + registryKey.Name + "/config": "true", + requestKey.Namespace + "." + requestKey.Name + "." + o.Name + "/request": o.Channel, } klog.V(3).Info("Generating Namespace: ", o.Namespace) diff --git a/go.mod b/go.mod index 19cf2190..0da0e392 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/IBM/operand-deployment-lifecycle-manager -go 1.17 +go 1.20 require ( github.com/IBM/controller-filtered-cache v0.3.2 @@ -15,7 +15,7 @@ require ( github.com/pkg/errors v0.9.1 golang.org/x/mod v0.7.0 k8s.io/api v0.21.3 - k8s.io/apimachinery v0.21.3 + k8s.io/apimachinery v0.21.14 k8s.io/client-go v0.21.3 k8s.io/klog v1.0.0 sigs.k8s.io/controller-runtime v0.9.6 @@ -27,7 +27,6 @@ require ( github.com/beorn7/perks v1.0.1 // indirect github.com/blang/semver v3.5.1+incompatible // indirect github.com/blang/semver/v4 v4.0.0 // indirect - github.com/buger/jsonparser v1.1.1 // indirect github.com/cespare/xxhash/v2 v2.1.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/evanphx/json-patch v4.11.0+incompatible // indirect @@ -59,7 +58,7 @@ require ( go.uber.org/atomic v1.7.0 // indirect go.uber.org/multierr v1.6.0 // indirect go.uber.org/zap v1.18.1 // indirect - golang.org/x/net v0.0.0-20210428140749-89ef3d95e781 // indirect + golang.org/x/net v0.0.0-20211209124913-491a49abca63 // indirect golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d // indirect golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c // indirect golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d // indirect @@ -76,10 +75,10 @@ require ( gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect k8s.io/apiextensions-apiserver v0.21.3 // indirect k8s.io/component-base v0.21.3 // indirect - k8s.io/klog/v2 v2.8.0 // indirect - k8s.io/kube-openapi v0.0.0-20210305001622-591a79e4bda7 // indirect + k8s.io/klog/v2 v2.9.0 // indirect + k8s.io/kube-openapi v0.0.0-20211110012726-3cc51fd1e909 // indirect k8s.io/utils v0.0.0-20210722164352-7f3ee0f31471 // indirect - sigs.k8s.io/structured-merge-diff/v4 v4.1.2 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.2.1 // indirect sigs.k8s.io/yaml v1.2.0 // indirect ) diff --git a/go.sum b/go.sum index 39228614..b383852c 100644 --- a/go.sum +++ b/go.sum @@ -115,8 +115,6 @@ github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2y github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= github.com/bshuster-repo/logrus-logstash-hook v0.4.1 h1:pgAtgj+A31JBVtEHu2uHuEx0n+2ukqUJnS2vVe5pQNA= github.com/bshuster-repo/logrus-logstash-hook v0.4.1/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk= -github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs= -github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8= github.com/bugsnag/bugsnag-go v1.5.3 h1:yeRUT3mUE13jL1tGwvoQsKdVbAsQx9AJ+fqahKveP04= github.com/bugsnag/bugsnag-go v1.5.3/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8= @@ -125,7 +123,6 @@ github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3k github.com/bugsnag/panicwrap v1.2.0 h1:OzrKrRvXis8qEvOkfcxNcYbOd2O7xXS2nnKMEMABFQA= github.com/bugsnag/panicwrap v1.2.0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.0/go.mod h1:dgIUBU3pDso/gPgZ1osOZ0iQf77oPR28Tjxl5dIMyVM= github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= @@ -903,7 +900,6 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= 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.3.1-0.20200828183125-ce943fd02449 h1:xUIPaMhvROX9dhPvRCenIJtU78+lbEenGbgqB5hfHCQ= golang.org/x/mod v0.3.1-0.20200828183125-ce943fd02449/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.7.0 h1:LapD9S96VoQRhi/GrNTqeBJFrUjs5UHCAtTlgwA5oZA= golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= @@ -950,8 +946,9 @@ golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81R golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210224082022-3d97a244fca7/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210428140749-89ef3d95e781 h1:DzZ89McO9/gWPsQXS/FVKAlG02ZjaQ6AlZRBimEYOd0= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= +golang.org/x/net v0.0.0-20211209124913-491a49abca63 h1:iocB37TsdFuN6IBRZ+ry36wrkoV51/tl5vOWqkcPGvY= +golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1035,6 +1032,7 @@ golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= @@ -1113,8 +1111,8 @@ golang.org/x/tools v0.0.0-20200616195046-dc31b401abb5/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.0 h1:po9/4sTYwZU9lPhi1tOrb4hCv3qrhiQ77LZfGa2OjwY= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1281,8 +1279,9 @@ k8s.io/apimachinery v0.18.6/go.mod h1:OaXp26zu/5J7p0f92ASynJa1pZo06YlV9fG7BoWbCk k8s.io/apimachinery v0.18.9/go.mod h1:PF5taHbXgTEJLU+xMypMmYTXTWPJ5LaW8bfsisxnEXk= k8s.io/apimachinery v0.20.1/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= k8s.io/apimachinery v0.20.5/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= -k8s.io/apimachinery v0.21.3 h1:3Ju4nvjCngxxMYby0BimUk+pQHPOQp3eCGChk5kfVII= k8s.io/apimachinery v0.21.3/go.mod h1:H/IM+5vH9kZRNJ4l3x/fXP/5bOPJaVP/guptnZPeCFI= +k8s.io/apimachinery v0.21.14 h1:tC5klgLnEkSqcS4qJdKP+Cmm8gVdaY9Hu31+ozRgv6E= +k8s.io/apimachinery v0.21.14/go.mod h1:NI5S3z6+ZZ6Da3whzPF+MnJCjU1NyLuTq9WnKIj5I20= k8s.io/apiserver v0.17.2/go.mod h1:lBmw/TtQdtxvrTk0e2cgtOxHizXI+d0mmGQURIHQZlo= k8s.io/apiserver v0.18.2/go.mod h1:Xbh066NqrZO8cbsoenCwyDJ1OSi8Ag8I2lezeHxzwzw= k8s.io/apiserver v0.18.6/go.mod h1:Zt2XvTHuaZjBz6EFYzpp+X4hTmgWGy8AthNVnTdm3Wg= @@ -1328,15 +1327,17 @@ k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= k8s.io/klog/v2 v2.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= -k8s.io/klog/v2 v2.8.0 h1:Q3gmuM9hKEjefWFFYF0Mat+YyFJvsUyYuwyNNJ5C9Ts= k8s.io/klog/v2 v2.8.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= +k8s.io/klog/v2 v2.9.0 h1:D7HV+n1V57XeZ0m6tdRkfknthUaM06VFbWldOFh8kzM= +k8s.io/klog/v2 v2.9.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= k8s.io/kube-aggregator v0.18.9/go.mod h1:ik5Mf6JaP2M9XbWZR/AYgXx2Nj4EDBrHyakUx7C8cdw= k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E= k8s.io/kube-openapi v0.0.0-20200121204235-bf4fb3bd569c/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E= k8s.io/kube-openapi v0.0.0-20200410145947-61e04a5be9a6/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E= k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd/go.mod h1:WOJ3KddDSol4tAGcJo0Tvi+dK12EcqSLqcWsryKMpfM= -k8s.io/kube-openapi v0.0.0-20210305001622-591a79e4bda7 h1:vEx13qjvaZ4yfObSSXW7BrMc/KQBBT/Jyee8XtLf4x0= k8s.io/kube-openapi v0.0.0-20210305001622-591a79e4bda7/go.mod h1:wXW5VT87nVfh/iLV8FpR2uDvrFyomxbtb1KivDbvPTE= +k8s.io/kube-openapi v0.0.0-20211110012726-3cc51fd1e909 h1:s77MRc/+/eQjsF89MB12JssAlsoi9mnNoaacRqibeAU= +k8s.io/kube-openapi v0.0.0-20211110012726-3cc51fd1e909/go.mod h1:wXW5VT87nVfh/iLV8FpR2uDvrFyomxbtb1KivDbvPTE= k8s.io/kubectl v0.17.2/go.mod h1:y4rfLV0n6aPmvbRCqZQjvOp3ezxsFgpqL+zF5jH/lxk= k8s.io/kubectl v0.18.0/go.mod h1:LOkWx9Z5DXMEg5KtOjHhRiC1fqJPLyCr3KtQgEolCkU= k8s.io/kubernetes v1.13.0/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk= @@ -1373,13 +1374,13 @@ sigs.k8s.io/kubebuilder v1.0.9-0.20200805184228-f7a3b65dd250 h1:1D9gplyencP89oP5 sigs.k8s.io/kubebuilder v1.0.9-0.20200805184228-f7a3b65dd250/go.mod h1:lkExAOdnNf9BGrvi4lWHCMo1fa6xtENt/QVwDhWpK+c= sigs.k8s.io/kustomize v2.0.3+incompatible/go.mod h1:MkjgH3RdOWrievjo6c9T245dYlB5QeXV4WCbnt/PEpU= sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= -sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06 h1:zD2IemQ4LmOcAumeiyDWXKUI2SO0NYDe3H6QGvPOVgU= sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06/go.mod h1:/ULNhyfzRopfcjskuui0cTITekDduZ7ycKN3oUT9R18= sigs.k8s.io/structured-merge-diff/v3 v3.0.0-20200116222232-67a7b8c61874/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= sigs.k8s.io/structured-merge-diff/v3 v3.0.0/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= -sigs.k8s.io/structured-merge-diff/v4 v4.1.2 h1:Hr/htKFmJEbtMgS/UD0N+gtgctAqz81t3nu+sPzynno= sigs.k8s.io/structured-merge-diff/v4 v4.1.2/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= +sigs.k8s.io/structured-merge-diff/v4 v4.2.1 h1:bKCqE9GvQ5tiVHn5rfn1r+yao3aLQEaLzkkmAkf+A6Y= +sigs.k8s.io/structured-merge-diff/v4 v4.2.1/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= From fc2994cc2d7e9d7aa7193fb9679d69e968d94de0 Mon Sep 17 00:00:00 2001 From: Travis CI User Date: Mon, 13 Mar 2023 15:16:45 +0000 Subject: [PATCH 002/179] Trigger build with new base image --- base_images.json | 128 +++++++++++++++++++++++++++-------------------- 1 file changed, 73 insertions(+), 55 deletions(-) diff --git a/base_images.json b/base_images.json index 4006b59d..979d780f 100644 --- a/base_images.json +++ b/base_images.json @@ -1,57 +1,75 @@ [ - { - "imageType": "external", - "sourceRepo": "registry.access.redhat.com", - "sourceNamespace": "ubi8", - "sourceImage": "ubi", - "destStage": "edge", - "destNamespace": "build-images", - "destImage": "ubi8", - "tag": "8.6-990", - "updatePackages": [] - }, - { - "imageType": "external", - "sourceRepo": "registry.access.redhat.com", - "sourceNamespace": "ubi8", - "sourceImage": "ubi-minimal", - "destStage": "edge", - "destNamespace": "build-images", - "destImage": "ubi8-minimal", - "tag": "8.6-994", - "updatePackages": [] - }, - { - "imageType": "external", - "sourceRepo": "quay.io", - "sourceNamespace": "operator-framework", - "sourceImage": "helm-operator", - "destStage": "edge", - "destNamespace": "build-images", - "destImage": "helm-operator", - "tag": "v1.25.1", - "updatePackages": [] - }, - { - "imageType": "node", - "sourceImage": "ubi8-minimal", - "sourceTag": "8.6-994", - "destImage": "node-fermium-ubi8-minimal", - "nodeVersion": "14.21.1" - }, - { - "imageType": "node", - "sourceImage": "ubi8-minimal", - "sourceTag": "8.6-994", - "destImage": "node-fermium-npm8-ubi8-minimal", - "nodeVersion": "14.21.1", - "npmVersion": "8" - }, - { - "imageType": "node", - "sourceImage": "ubi8-minimal", - "sourceTag": "8.6-994", - "destImage": "node-v16-ubi8-minimal", - "nodeVersion": "16.18.1" - } + { + "imageType": "external", + "sourceRepo": "registry.access.redhat.com", + "sourceNamespace": "ubi8", + "sourceImage": "ubi", + "destStage": "edge", + "destNamespace": "build-images", + "destImage": "ubi8", + "tag": "8.7-1090", + "updatePackages": [] + }, + { + "imageType": "external", + "sourceRepo": "registry.access.redhat.com", + "sourceNamespace": "ubi8", + "sourceImage": "ubi-minimal", + "destStage": "edge", + "destNamespace": "build-images", + "destImage": "ubi8-minimal", + "tag": "8.7-1085", + "updatePackages": [] + }, + { + "imageType": "external", + "sourceRepo": "registry.access.redhat.com", + "sourceNamespace": "ubi9", + "sourceImage": "ubi-micro", + "destStage": "edge", + "destNamespace": "build-images", + "destImage": "ubi9-micro", + "tag": "9.1.0-15", + "updatePackages": [] + }, + { + "imageType": "external", + "sourceRepo": "quay.io", + "sourceNamespace": "operator-framework", + "sourceImage": "helm-operator", + "destStage": "edge", + "destNamespace": "build-images", + "destImage": "helm-operator", + "tag": "v1.27.0", + "updatePackages": [] + }, + { + "imageType": "node", + "sourceImage": "ubi8-minimal", + "sourceTag": "8.7-1085", + "destImage": "node-fermium-ubi8-minimal", + "nodeVersion": "14.21.3" + }, + { + "imageType": "node", + "sourceImage": "ubi8-minimal", + "sourceTag": "8.7-1085", + "destImage": "node-fermium-npm8-ubi8-minimal", + "nodeVersion": "14.21.3", + "npmVersion": "8" + }, + { + "imageType": "node", + "sourceImage": "ubi8-minimal", + "sourceTag": "8.7-1085", + "destImage": "node-v16-ubi8-minimal", + "nodeVersion": "16.19.1" + }, + { + "imageType": "node", + "sourceImage": "ubi8-minimal", + "sourceTag": "8.7-1085", + "destImage": "node-v18-ubi8-minimal", + "nodeVersion": "18.15.0" + } ] From 52c402063c9a40b46fdffa17706c62a8dfb15fcb Mon Sep 17 00:00:00 2001 From: YuChen Shen <59578388+YCShen1010@users.noreply.github.com> Date: Tue, 14 Mar 2023 00:04:53 -0400 Subject: [PATCH 003/179] add new value no-op in installmode replace supportStatus (#909) * add new value no-op in installmode Signed-off-by: YuChen * add preserve unknown field Signed-off-by: YuChen * move preserve unknown field position Signed-off-by: YuChen * update golangci-lint-version Signed-off-by: YuChen --------- Signed-off-by: YuChen --- api/v1alpha1/operandregistry_types.go | 17 ++++------------- .../operator.ibm.com_operandregistries.yaml | 17 ++++++----------- .../operator.ibm.com_operandregistries.yaml | 17 ++++++----------- .../operandrequest/reconcile_operator.go | 2 +- controllers/operator/manager.go | 3 --- .../operand-deployment-lifecycle-manager.md | 4 +--- 6 files changed, 18 insertions(+), 42 deletions(-) diff --git a/api/v1alpha1/operandregistry_types.go b/api/v1alpha1/operandregistry_types.go index 6daf785b..3eef90cc 100644 --- a/api/v1alpha1/operandregistry_types.go +++ b/api/v1alpha1/operandregistry_types.go @@ -27,6 +27,7 @@ import ( // NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. // Operator defines the desired state of Operators. +// +kubebuilder:pruning:PreserveUnknownFields type Operator struct { // A unique name for the operator whose operand may be deployed. Name string `json:"name"` @@ -40,6 +41,7 @@ type Operator struct { // Valid values are: // - "namespace" (default): operator is deployed in namespace of OperandRegistry; // - "cluster": operator is deployed in "openshift-operators" namespace; + // - "no-op": operator is not supported to be fresh deployed; // +optional InstallMode string `json:"installMode,omitempty"` // The namespace in which operator should be deployed when InstallMode is empty or set to "namespace". @@ -71,12 +73,6 @@ type Operator struct { // SubscriptionConfig is used to override operator configuration. // +optional SubscriptionConfig *olmv1alpha1.SubscriptionConfig `json:"subscriptionConfig,omitempty"` - // SupportStatus is used to indicate the support status for services. - // Valid values are: - // - "continuous" (default): operator is supported to be fresh deployed via OperandRequest from scratch - // - "maintained" operator is not supported to be fresh deployed via OperandRequest, only upgrade and deletion are allowed - // +optional - SupportStatus string `json:"supportStatus,omitempty"` } // +kubebuilder:validation:Enum=public;private @@ -96,13 +92,8 @@ const ( InstallModeCluster string = "cluster" // InstallModeNamespace means install the operator in one namespace mode. InstallModeNamespace string = "namespace" -) - -const ( - // MaintainedSupportStatus means NOT supporting fresh deployment for the operator - MaintainedSupportStatus string = "maintained" - // ContinuousSupportStatus means supporting fresh deployment for the operator - ContinuousSupportStatus string = "continuous" + // InstallModeNoop means not create the subscription for the operator + InstallModeNoop string = "no-op" ) // OperandRegistrySpec defines the desired state of OperandRegistry. diff --git a/bundle/manifests/operator.ibm.com_operandregistries.yaml b/bundle/manifests/operator.ibm.com_operandregistries.yaml index e1dd4e1b..4849798a 100644 --- a/bundle/manifests/operator.ibm.com_operandregistries.yaml +++ b/bundle/manifests/operator.ibm.com_operandregistries.yaml @@ -63,10 +63,12 @@ spec: description: Description of a common service. type: string installMode: - description: 'The install mode of an operator, either namespace - or cluster. Valid values are: - "namespace" (default): operator + description: 'The install mode of an operator, could be namespace, + cluster or no-op. Valid values are: - "namespace" (default): operator is deployed in namespace of OperandRegistry; - "cluster": - operator is deployed in "openshift-operators" namespace;' + operator is deployed in "openshift-operators" namespace; - "no-op": + operator is not supported to be fresh deployed via OperandRequest, + only upgrade and deletion are allowed;' type: string installPlanApproval: description: 'Approval mode for emitted InstallPlans. Valid @@ -2026,14 +2028,6 @@ spec: type: object type: array type: object - supportStatus: - description: 'SupportStatus is used to indicate the support - status for services. Valid values are: - "continuous" (default): - operator is supported to be fresh deployed via OperandRequest - from scratch - "maintained" operator is not supported to be - fresh deployed via OperandRequest, only upgrade and deletion - are allowed' - type: string targetNamespaces: description: The target namespace of the OperatorGroups. items: @@ -2044,6 +2038,7 @@ spec: - name - packageName type: object + x-kubernetes-preserve-unknown-fields: true type: array type: object x-kubernetes-preserve-unknown-fields: true diff --git a/config/crd/bases/operator.ibm.com_operandregistries.yaml b/config/crd/bases/operator.ibm.com_operandregistries.yaml index 592016e4..22ebc07d 100644 --- a/config/crd/bases/operator.ibm.com_operandregistries.yaml +++ b/config/crd/bases/operator.ibm.com_operandregistries.yaml @@ -61,10 +61,12 @@ spec: description: Description of a common service. type: string installMode: - description: 'The install mode of an operator, either namespace - or cluster. Valid values are: - "namespace" (default): operator + description: 'The install mode of an operator, could be namespace + cluster, or no-op. Valid values are: - "namespace" (default): operator is deployed in namespace of OperandRegistry; - "cluster": - operator is deployed in "openshift-operators" namespace;' + operator is deployed in "openshift-operators" namespace; - "no-op": + operator is not supported to be fresh deployed via OperandRequest, + only upgrade and deletion are allowed;' type: string installPlanApproval: description: 'Approval mode for emitted InstallPlans. Valid @@ -2024,14 +2026,6 @@ spec: type: object type: array type: object - supportStatus: - description: 'SupportStatus is used to indicate the support - status for services. Valid values are: - "continuous" (default): - operator is supported to be fresh deployed via OperandRequest - from scratch - "maintained" operator is not supported to be - fresh deployed via OperandRequest, only upgrade and deletion - are allowed' - type: string targetNamespaces: description: The target namespace of the OperatorGroups. items: @@ -2042,6 +2036,7 @@ spec: - name - packageName type: object + x-kubernetes-preserve-unknown-fields: true type: array type: object x-kubernetes-preserve-unknown-fields: true diff --git a/controllers/operandrequest/reconcile_operator.go b/controllers/operandrequest/reconcile_operator.go index 812c476f..b54989e6 100644 --- a/controllers/operandrequest/reconcile_operator.go +++ b/controllers/operandrequest/reconcile_operator.go @@ -168,7 +168,7 @@ func (r *Reconciler) reconcileSubscription(ctx context.Context, requestInstance if err != nil { if apierrors.IsNotFound(err) { - if opt.SupportStatus == operatorv1alpha1.MaintainedSupportStatus { + if opt.InstallMode == operatorv1alpha1.InstallModeNoop { requestInstance.SetNoSuitableRegistryCondition(registryKey.String(), opt.Name+" is in maintenance status", operatorv1alpha1.ResourceTypeOperandRegistry, corev1.ConditionTrue, &r.Mutex) requestInstance.SetMemberStatus(operand.Name, operatorv1alpha1.OperatorRunning, operatorv1alpha1.ServiceRunning, mu) } else { diff --git a/controllers/operator/manager.go b/controllers/operator/manager.go index 91f7283f..e1c81603 100644 --- a/controllers/operator/manager.go +++ b/controllers/operator/manager.go @@ -86,9 +86,6 @@ func (m *ODLMOperator) GetOperandRegistry(ctx context.Context, key types.Namespa if o.Namespace == "" { reg.Spec.Operators[i].Namespace = key.Namespace } - if o.SupportStatus == "" { - reg.Spec.Operators[i].SupportStatus = apiv1alpha1.ContinuousSupportStatus - } if o.SourceName == "" || o.SourceNamespace == "" { catalogSourceName, catalogSourceNs, err := m.GetCatalogSourceFromPackage(ctx, o.PackageName, o.Namespace, o.Channel, key.Namespace, excludedCatalogSources) if err != nil { diff --git a/docs/design/operand-deployment-lifecycle-manager.md b/docs/design/operand-deployment-lifecycle-manager.md index bef60831..dac88306 100644 --- a/docs/design/operand-deployment-lifecycle-manager.md +++ b/docs/design/operand-deployment-lifecycle-manager.md @@ -73,7 +73,6 @@ spec: sourceNamespace: openshift-marketplace [9] installMode: cluster [10] installPlanApproval: Manual [11] - supportStatus: continuous [12] ``` The OperandRegistry Custom Resource (CR) lists OLM Operator information for operands that may be requested for installation and/or access by an application that runs in a namespace. The registry CR specifies: @@ -87,9 +86,8 @@ The OperandRegistry Custom Resource (CR) lists OLM Operator information for oper 7. (optional) `scope` is an indicator, either public or private, that dictates whether deployment can be requested from other namespaces (public) or only from the namespace of this OperandRegistry (private). The default value is private. 8. `sourceName` is the name of the CatalogSource. 9. `sourceNamespace` is the namespace of the CatalogSource. -10. (optional) `installMode` is the install mode of the operator, can be either `namespace` (OLM one namespace) or `cluster` (OLM all namespaces). The default value is `namespace`. Operator is deployed in `openshift-operators` namespace when InstallMode is set to `cluster`. +10. (optional) `installMode` is the install mode of the operator, can be `namespace` (OLM one namespace), `cluster` (OLM all namespaces) or `no-op` (discontinued service). The default value is `namespace`. Operator is deployed in `openshift-operators` namespace when InstallMode is set to `cluster`. 11. (optional) `installPlanApproval` is the approval mode for emitted installplan. The default value is `Automatic`. -12. (optional) `supportStatus` is the support status for services. (1) When SupportStatus is `continous`, operator is supported to be fresh deployed via OperandRequest from scratch. (2) When SupportStatus is `maintained`, operator is not supported to be fresh deployed via OperandRequest, only upgrade and deletion are allowed. The default value is `continous` ## OperandConfig Spec From c8b40718b5e9a727b899bb68d311f171b434a6ed Mon Sep 17 00:00:00 2001 From: YuChen Shen <59578388+YCShen1010@users.noreply.github.com> Date: Thu, 16 Mar 2023 18:15:54 -0400 Subject: [PATCH 004/179] skip sub updating for discontinued services (#910) * skip sub updating for discontinued services Signed-off-by: YuChen * update annotations only Signed-off-by: YuChen * typo Signed-off-by: YuChen * update opreq annotation Signed-off-by: YuChen * update annotation channel Signed-off-by: YuChen * fix go fmt Signed-off-by: YuChen * set annotation when installmode is no-op Signed-off-by: YuChen --------- Signed-off-by: YuChen --- .../operandrequest/reconcile_operator.go | 57 +++++++++++-------- 1 file changed, 33 insertions(+), 24 deletions(-) diff --git a/controllers/operandrequest/reconcile_operator.go b/controllers/operandrequest/reconcile_operator.go index b54989e6..029b4283 100644 --- a/controllers/operandrequest/reconcile_operator.go +++ b/controllers/operandrequest/reconcile_operator.go @@ -196,32 +196,41 @@ func (r *Reconciler) reconcileSubscription(ctx context.Context, requestInstance sub.Annotations[registryKey.Namespace+"."+registryKey.Name+"/config"] = "true" sub.Annotations[requestInstance.Namespace+"."+requestInstance.Name+"."+operand.Name+"/request"] = opt.Channel - sub.Spec.CatalogSource = opt.SourceName - sub.Spec.CatalogSourceNamespace = opt.SourceNamespace - sub.Spec.Package = opt.PackageName - - // check request annotation in subscription, get all available channels - var semverlList []string - reg, _ := regexp.Compile(`^(.*)\.(.*)\.(.*)\/request`) - for anno, channel := range sub.Annotations { - if reg.MatchString(anno) && semver.IsValid(channel) { - semverlList = append(semverlList, channel) + if opt.InstallMode == operatorv1alpha1.InstallModeNoop { + requestInstance.SetNoSuitableRegistryCondition(registryKey.String(), opt.Name+" is in maintenance status", operatorv1alpha1.ResourceTypeOperandRegistry, corev1.ConditionTrue, &r.Mutex) + requestInstance.SetMemberStatus(operand.Name, operatorv1alpha1.OperatorRunning, operatorv1alpha1.ServiceRunning, mu) + + //set operator channel back to previous one if it is tombstone service + sub.Annotations[requestInstance.Namespace+"."+requestInstance.Name+"."+operand.Name+"/request"] = sub.Spec.Channel + } else { + + sub.Spec.CatalogSource = opt.SourceName + sub.Spec.CatalogSourceNamespace = opt.SourceNamespace + sub.Spec.Package = opt.PackageName + + // check request annotation in subscription, get all available channels + var semverlList []string + reg, _ := regexp.Compile(`^(.*)\.(.*)\.(.*)\/request`) + for anno, channel := range sub.Annotations { + if reg.MatchString(anno) && semver.IsValid(channel) { + semverlList = append(semverlList, channel) + } + } + if len(semverlList) == 0 { + // channel is not valid semantic version + sub.Spec.Channel = opt.Channel + } else if !util.Contains(semverlList, sub.Spec.Channel) { + // upgrade channel to minimal version existing in annotation + sort.Sort(semver.ByVersion(semverlList)) + sub.Spec.Channel = semverlList[0] } - } - if len(semverlList) == 0 { - // channel is not valid semantic version - sub.Spec.Channel = opt.Channel - } else if !util.Contains(semverlList, sub.Spec.Channel) { - // upgrade channel to minimal version existing in annotation - sort.Sort(semver.ByVersion(semverlList)) - sub.Spec.Channel = semverlList[0] - } - if opt.InstallPlanApproval != "" && sub.Spec.InstallPlanApproval != opt.InstallPlanApproval { - sub.Spec.InstallPlanApproval = opt.InstallPlanApproval - } - if opt.SubscriptionConfig != nil { - sub.Spec.Config = opt.SubscriptionConfig + if opt.InstallPlanApproval != "" && sub.Spec.InstallPlanApproval != opt.InstallPlanApproval { + sub.Spec.InstallPlanApproval = opt.InstallPlanApproval + } + if opt.SubscriptionConfig != nil { + sub.Spec.Config = opt.SubscriptionConfig + } } if compareSub(sub, originalSub) { if err = r.updateSubscription(ctx, requestInstance, sub); err != nil { From bf3930088cd3843e48ec6c3bf5ce9c796ccf62b1 Mon Sep 17 00:00:00 2001 From: Travis CI User Date: Mon, 27 Mar 2023 16:56:14 +0000 Subject: [PATCH 005/179] Trigger build with new base image --- base_images.json | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/base_images.json b/base_images.json index 979d780f..d54786f5 100644 --- a/base_images.json +++ b/base_images.json @@ -7,7 +7,7 @@ "destStage": "edge", "destNamespace": "build-images", "destImage": "ubi8", - "tag": "8.7-1090", + "tag": "8.7-1090.1679482075", "updatePackages": [] }, { @@ -18,7 +18,7 @@ "destStage": "edge", "destNamespace": "build-images", "destImage": "ubi8-minimal", - "tag": "8.7-1085", + "tag": "8.7-1085.1679482090", "updatePackages": [] }, { @@ -40,20 +40,20 @@ "destStage": "edge", "destNamespace": "build-images", "destImage": "helm-operator", - "tag": "v1.27.0", + "tag": "v1.28.0", "updatePackages": [] }, { "imageType": "node", "sourceImage": "ubi8-minimal", - "sourceTag": "8.7-1085", + "sourceTag": "8.7-1085.1679482090", "destImage": "node-fermium-ubi8-minimal", "nodeVersion": "14.21.3" }, { "imageType": "node", "sourceImage": "ubi8-minimal", - "sourceTag": "8.7-1085", + "sourceTag": "8.7-1085.1679482090", "destImage": "node-fermium-npm8-ubi8-minimal", "nodeVersion": "14.21.3", "npmVersion": "8" @@ -61,14 +61,14 @@ { "imageType": "node", "sourceImage": "ubi8-minimal", - "sourceTag": "8.7-1085", + "sourceTag": "8.7-1085.1679482090", "destImage": "node-v16-ubi8-minimal", "nodeVersion": "16.19.1" }, { "imageType": "node", "sourceImage": "ubi8-minimal", - "sourceTag": "8.7-1085", + "sourceTag": "8.7-1085.1679482090", "destImage": "node-v18-ubi8-minimal", "nodeVersion": "18.15.0" } From c3cf88e8a1725056f906973de048f376257eb38f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 28 Mar 2023 11:18:58 +0800 Subject: [PATCH 006/179] build(deps): bump github.com/prometheus/client_golang (#895) Bumps [github.com/prometheus/client_golang](https://github.com/prometheus/client_golang) from 1.11.0 to 1.11.1. - [Release notes](https://github.com/prometheus/client_golang/releases) - [Changelog](https://github.com/prometheus/client_golang/blob/main/CHANGELOG.md) - [Commits](https://github.com/prometheus/client_golang/compare/v1.11.0...v1.11.1) --- updated-dependencies: - dependency-name: github.com/prometheus/client_golang dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index 0da0e392..75295cc7 100644 --- a/go.mod +++ b/go.mod @@ -49,7 +49,7 @@ require ( github.com/modern-go/reflect2 v1.0.1 // indirect github.com/nxadm/tail v1.4.8 // indirect github.com/operator-framework/operator-registry v1.13.6 // indirect - github.com/prometheus/client_golang v1.11.0 // indirect + github.com/prometheus/client_golang v1.11.1 // indirect github.com/prometheus/client_model v0.2.0 // indirect github.com/prometheus/common v0.26.0 // indirect github.com/prometheus/procfs v0.6.0 // indirect diff --git a/go.sum b/go.sum index b383852c..f0f0ef53 100644 --- a/go.sum +++ b/go.sum @@ -686,8 +686,9 @@ github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5Fsn github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= github.com/prometheus/client_golang v1.2.1/go.mod h1:XMU6Z2MjaRKVu/dC1qupJI9SiNkDYzz3xecMgSW/F+U= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= -github.com/prometheus/client_golang v1.11.0 h1:HNkLOAEQMIDv/K+04rukrLx6ch7msSRwf3/SASFAGtQ= github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= +github.com/prometheus/client_golang v1.11.1 h1:+4eQaD7vAZ6DsfsxB15hbE0odUjGI5ARs9yskGu1v4s= +github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= From c927bf9661cac7f83374c636847a4778f4c3d8b8 Mon Sep 17 00:00:00 2001 From: YuChen Shen <59578388+YCShen1010@users.noreply.github.com> Date: Tue, 28 Mar 2023 18:59:58 -0400 Subject: [PATCH 007/179] tolerate multi catalogsource for same service (#914) Signed-off-by: YuChen --- .../operandrequest/reconcile_operator.go | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/controllers/operandrequest/reconcile_operator.go b/controllers/operandrequest/reconcile_operator.go index 029b4283..a7b652b5 100644 --- a/controllers/operandrequest/reconcile_operator.go +++ b/controllers/operandrequest/reconcile_operator.go @@ -204,10 +204,6 @@ func (r *Reconciler) reconcileSubscription(ctx context.Context, requestInstance sub.Annotations[requestInstance.Namespace+"."+requestInstance.Name+"."+operand.Name+"/request"] = sub.Spec.Channel } else { - sub.Spec.CatalogSource = opt.SourceName - sub.Spec.CatalogSourceNamespace = opt.SourceNamespace - sub.Spec.Package = opt.PackageName - // check request annotation in subscription, get all available channels var semverlList []string reg, _ := regexp.Compile(`^(.*)\.(.*)\.(.*)\/request`) @@ -225,12 +221,20 @@ func (r *Reconciler) reconcileSubscription(ctx context.Context, requestInstance sub.Spec.Channel = semverlList[0] } - if opt.InstallPlanApproval != "" && sub.Spec.InstallPlanApproval != opt.InstallPlanApproval { - sub.Spec.InstallPlanApproval = opt.InstallPlanApproval - } - if opt.SubscriptionConfig != nil { - sub.Spec.Config = opt.SubscriptionConfig + // update the spec iff channel in sub matches channel in opreg + if sub.Spec.Channel == opt.Channel { + sub.Spec.CatalogSource = opt.SourceName + sub.Spec.CatalogSourceNamespace = opt.SourceNamespace + sub.Spec.Package = opt.PackageName + + if opt.InstallPlanApproval != "" && sub.Spec.InstallPlanApproval != opt.InstallPlanApproval { + sub.Spec.InstallPlanApproval = opt.InstallPlanApproval + } + if opt.SubscriptionConfig != nil { + sub.Spec.Config = opt.SubscriptionConfig + } } + } if compareSub(sub, originalSub) { if err = r.updateSubscription(ctx, requestInstance, sub); err != nil { From 1cfed4aacc8d5af14684949b15c7ed400e0130cf Mon Sep 17 00:00:00 2001 From: Daniel Fan Date: Thu, 30 Mar 2023 12:12:59 -0400 Subject: [PATCH 008/179] Remove annotation patch to avoid status lost (#915) Signed-off-by: Daniel Fan --- api/v1alpha1/operandrequest_types.go | 4 +- .../operandrequest_controller.go | 7 ++- .../operandrequest/reconcile_operator.go | 46 ++++--------------- 3 files changed, 15 insertions(+), 42 deletions(-) diff --git a/api/v1alpha1/operandrequest_types.go b/api/v1alpha1/operandrequest_types.go index 19956199..e2ad35b0 100644 --- a/api/v1alpha1/operandrequest_types.go +++ b/api/v1alpha1/operandrequest_types.go @@ -474,10 +474,10 @@ func (r *OperandRequest) setOperandReadyCondition(operandPhase ServicePhase, nam } // FreshMemberStatus cleanup Member status from the Member status list. -func (r *OperandRequest) FreshMemberStatus(failedDeletedOperands *gset.Set) { +func (r *OperandRequest) FreshMemberStatus(remainingOp *gset.Set) { newMembers := []MemberStatus{} for index, m := range r.Status.Members { - if foundOperand(r.Spec.Requests, m.Name) || (*failedDeletedOperands).Contains(m.Name) { + if foundOperand(r.Spec.Requests, m.Name) || (*remainingOp).Contains(m.Name) { newMembers = append(newMembers, r.Status.Members[index]) } } diff --git a/controllers/operandrequest/operandrequest_controller.go b/controllers/operandrequest/operandrequest_controller.go index c25089d4..7babfbd0 100644 --- a/controllers/operandrequest/operandrequest_controller.go +++ b/controllers/operandrequest/operandrequest_controller.go @@ -208,7 +208,10 @@ func (r *Reconciler) addFinalizer(ctx context.Context, cr *operatorv1alpha1.Oper func (r *Reconciler) checkFinalizer(ctx context.Context, requestInstance *operatorv1alpha1.OperandRequest) error { klog.V(1).Infof("Deleting OperandRequest %s in the namespace %s", requestInstance.Name, requestInstance.Namespace) - failedDeletedOperands := gset.NewSet() + remainingOperands := gset.NewSet() + for _, m := range requestInstance.Status.Members { + remainingOperands.Add(m.Name) + } existingSub := &olmv1alpha1.SubscriptionList{} opts := []client.ListOption{ @@ -222,7 +225,7 @@ func (r *Reconciler) checkFinalizer(ctx context.Context, requestInstance *operat return nil } // Delete all the subscriptions that created by current request - if err := r.absentOperatorsAndOperands(ctx, requestInstance, &failedDeletedOperands); err != nil { + if err := r.absentOperatorsAndOperands(ctx, requestInstance, &remainingOperands); err != nil { return err } return nil diff --git a/controllers/operandrequest/reconcile_operator.go b/controllers/operandrequest/reconcile_operator.go index a7b652b5..4a1906bd 100644 --- a/controllers/operandrequest/reconcile_operator.go +++ b/controllers/operandrequest/reconcile_operator.go @@ -18,13 +18,11 @@ package operandrequest import ( "context" - "encoding/json" "fmt" "regexp" "sort" "strings" "sync" - "time" gset "github.com/deckarep/golang-set" olmv1 "github.com/operator-framework/api/pkg/operators/v1" @@ -37,7 +35,6 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/types" - utilerrors "k8s.io/apimachinery/pkg/util/errors" "k8s.io/klog" "sigs.k8s.io/controller-runtime/pkg/client" @@ -50,10 +47,13 @@ func (r *Reconciler) reconcileOperator(ctx context.Context, requestInstance *ope klog.V(1).Infof("Reconciling Operators for OperandRequest: %s/%s", requestInstance.GetNamespace(), requestInstance.GetName()) // It is important to NOT pass the set directly into defer functions. // The arguments to the deferred function are evaluated when the defer executes - failedDeletedOperands := gset.NewSet() + remainingOperands := gset.NewSet() + for _, m := range requestInstance.Status.Members { + remainingOperands.Add(m.Name) + } // Update request status defer func() { - requestInstance.FreshMemberStatus(&failedDeletedOperands) + requestInstance.FreshMemberStatus(&remainingOperands) requestInstance.UpdateClusterPhase() }() @@ -68,20 +68,6 @@ func (r *Reconciler) reconcileOperator(ctx context.Context, requestInstance *ope requestInstance.SetNoSuitableRegistryCondition(registryKey.String(), err.Error(), operatorv1alpha1.ResourceTypeOperandRegistry, corev1.ConditionTrue, &r.Mutex) } klog.Errorf("Failed to get suitable OperandRegistry %s: %v", registryKey.String(), err) - t := time.Now() - formatted := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02d", - t.Year(), t.Month(), t.Day(), - t.Hour(), t.Minute(), t.Second()) - mergePatch, _ := json.Marshal(map[string]interface{}{ - "metadata": map[string]interface{}{ - "annotations": map[string]interface{}{ - constant.FindOperandRegistry: formatted, - }, - }, - }) - if patchErr := r.Patch(ctx, requestInstance, client.RawPatch(types.MergePatchType, mergePatch)); patchErr != nil { - return utilerrors.NewAggregate([]error{err, patchErr}) - } return err } merr := &util.MultiErr{} @@ -122,24 +108,8 @@ func (r *Reconciler) reconcileOperator(ctx context.Context, requestInstance *ope } } - // TODO: update OperandRequest status before patching. Otherwise, the status will be lost. - // It is really corner case which would not cause any issue so far since the Status will finally be Running. - // Need to consider a more elegant way to preserve status instead of calling Client API like below - // requestInstance.FreshMemberStatus(&failedDeletedOperands) - - mergePatch, _ := json.Marshal(map[string]interface{}{ - "metadata": map[string]interface{}{ - "annotations": map[string]interface{}{ - constant.FindOperandRegistry: "false", - }, - }, - }) - if err := r.Patch(ctx, requestInstance, client.RawPatch(types.MergePatchType, mergePatch)); err != nil { - return err - } - // Delete specific operators - if err := r.absentOperatorsAndOperands(ctx, requestInstance, &failedDeletedOperands); err != nil { + if err := r.absentOperatorsAndOperands(ctx, requestInstance, &remainingOperands); err != nil { return err } klog.V(1).Infof("Finished reconciling Operators for OperandRequest: %s/%s", requestInstance.GetNamespace(), requestInstance.GetName()) @@ -418,7 +388,7 @@ func (r *Reconciler) deleteSubscription(ctx context.Context, operandName string, return nil } -func (r *Reconciler) absentOperatorsAndOperands(ctx context.Context, requestInstance *operatorv1alpha1.OperandRequest, failedDeletedOperands *gset.Set) error { +func (r *Reconciler) absentOperatorsAndOperands(ctx context.Context, requestInstance *operatorv1alpha1.OperandRequest, remainingOperands *gset.Set) error { needDeletedOperands := r.getNeedDeletedOperands(requestInstance) var ( @@ -452,8 +422,8 @@ func (r *Reconciler) absentOperatorsAndOperands(ctx context.Context, requestInst r.Mutex.Lock() defer r.Mutex.Unlock() merr.Add(err) - (*failedDeletedOperands).Add(o) } + (*remainingOperands).Remove(o) remainingOp.Remove(o) }() } From e9839ec3ee03b0537456abd0bcaaab662e39409b Mon Sep 17 00:00:00 2001 From: Travis CI User Date: Tue, 18 Apr 2023 14:37:54 +0000 Subject: [PATCH 009/179] Trigger build with new base image --- base_images.json | 37 +++++++++++-------------------------- 1 file changed, 11 insertions(+), 26 deletions(-) diff --git a/base_images.json b/base_images.json index d54786f5..49d22c4e 100644 --- a/base_images.json +++ b/base_images.json @@ -7,7 +7,7 @@ "destStage": "edge", "destNamespace": "build-images", "destImage": "ubi8", - "tag": "8.7-1090.1679482075", + "tag": "8.7-1112", "updatePackages": [] }, { @@ -18,7 +18,7 @@ "destStage": "edge", "destNamespace": "build-images", "destImage": "ubi8-minimal", - "tag": "8.7-1085.1679482090", + "tag": "8.7-1107", "updatePackages": [] }, { @@ -29,7 +29,7 @@ "destStage": "edge", "destNamespace": "build-images", "destImage": "ubi9-micro", - "tag": "9.1.0-15", + "tag": "9.1.0-17", "updatePackages": [] }, { @@ -46,30 +46,15 @@ { "imageType": "node", "sourceImage": "ubi8-minimal", - "sourceTag": "8.7-1085.1679482090", - "destImage": "node-fermium-ubi8-minimal", - "nodeVersion": "14.21.3" - }, - { - "imageType": "node", - "sourceImage": "ubi8-minimal", - "sourceTag": "8.7-1085.1679482090", - "destImage": "node-fermium-npm8-ubi8-minimal", - "nodeVersion": "14.21.3", - "npmVersion": "8" - }, - { - "imageType": "node", - "sourceImage": "ubi8-minimal", - "sourceTag": "8.7-1085.1679482090", - "destImage": "node-v16-ubi8-minimal", - "nodeVersion": "16.19.1" + "sourceTag": "8.7-1107", + "destImage": "node-v18-ubi8-minimal", + "nodeVersion": "18.16.0" }, { - "imageType": "node", - "sourceImage": "ubi8-minimal", - "sourceTag": "8.7-1085.1679482090", - "destImage": "node-v18-ubi8-minimal", - "nodeVersion": "18.15.0" + "imageType": "liberty", + "sourceImage": "node-v18-ubi8-minimal", + "sourceTag": "18.16.0_8.7-1107", + "destImage": "liberty11-ubi8-minimal", + "libertyVersion": "23.0.0.3" } ] From 6999157ae8040f5c59d5ea05da968a59e8273f20 Mon Sep 17 00:00:00 2001 From: Ben Luzarraga <31223504+bluzarraga@users.noreply.github.com> Date: Wed, 19 Apr 2023 11:31:17 -0500 Subject: [PATCH 010/179] check for status.services, im service status (#916) * check for status.services, im service status Signed-off-by: Ben Luzarraga * alter check for im operator status Signed-off-by: Ben Luzarraga * export function Signed-off-by: Ben Luzarraga * account for opreq that do not request im Signed-off-by: Ben Luzarraga * typo Signed-off-by: Ben Luzarraga * clean up implementation Signed-off-by: Ben Luzarraga * linter changes Signed-off-by: Ben Luzarraga * service.operatorName value from managedBy to requested name Signed-off-by: Ben Luzarraga * change common ui operator name to look for Signed-off-by: Ben Luzarraga --------- Signed-off-by: Ben Luzarraga Co-authored-by: Ben Luzarraga --- api/v1alpha1/operandrequest_types.go | 53 +++++++++++++++++++ .../operandrequest_controller.go | 5 ++ .../operandrequest/reconcile_operand.go | 48 ++--------------- 3 files changed, 62 insertions(+), 44 deletions(-) diff --git a/api/v1alpha1/operandrequest_types.go b/api/v1alpha1/operandrequest_types.go index e2ad35b0..d92e6bf4 100644 --- a/api/v1alpha1/operandrequest_types.go +++ b/api/v1alpha1/operandrequest_types.go @@ -29,6 +29,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" + "k8s.io/klog" "sigs.k8s.io/controller-runtime/pkg/reconcile" ) @@ -650,6 +651,58 @@ func (r *OperandRequest) UpdateLabels() bool { return isUpdated } +func (r *OperandRequest) CheckServiceStatus() bool { + requeue := false + monitoredServices := []string{"ibm-iam-operator", "ibm-idp-config-ui-operator", "ibm-mongodb-operator", "ibm-im-operator"} + servicesRequested := false + for _, serviceName := range monitoredServices { + if foundOperand(r.Spec.Requests, serviceName) { + servicesRequested = true + break + } + } + if servicesRequested { + if len(r.Status.Services) == 0 { + klog.Info("Waiting for status.services to be instantiated ...") + requeue = true + return requeue + } + // var IMOrIAM string + exists := false + if foundOperand(r.Spec.Requests, "ibm-iam-operator") { + // IMOrIAM = "ibm-iam-operator" + exists = true + } else if foundOperand(r.Spec.Requests, "ibm-im-operator") { + // IMOrIAM = "ibm-im-operator" + exists = true + } + + if exists { + var imIndex int + found := false + for i, s := range r.Status.Services { + if "ibm-iam-operator" == s.OperatorName { //eventually this should be changed to the variable but the operator name is still listed as iam in practice even when im is requested + found = true + imIndex = i + break + } + } + if found { + if r.Status.Services[imIndex].Status != "Ready" { + klog.Info("Waiting for IM service to be Ready ...") + requeue = true + return requeue + } + } else { + klog.Info("Waiting for IM service status ...") + requeue = true + return requeue + } + } + } + return requeue +} + // GetAllRegistryReconcileRequest gets all the Registry ReconcileRequest. func (r *OperandRequest) GetAllRegistryReconcileRequest() []reconcile.Request { rrs := []reconcile.Request{} diff --git a/controllers/operandrequest/operandrequest_controller.go b/controllers/operandrequest/operandrequest_controller.go index 7babfbd0..8e4284b2 100644 --- a/controllers/operandrequest/operandrequest_controller.go +++ b/controllers/operandrequest/operandrequest_controller.go @@ -153,6 +153,11 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctrl.Re return ctrl.Result{RequeueAfter: constant.DefaultRequeueDuration}, nil } + //check if status.services is present (if a relevant service was requested), requeue again is im/iam is not ready yet + if requestInstance.CheckServiceStatus() { + return ctrl.Result{RequeueAfter: constant.DefaultRequeueDuration}, nil + } + klog.V(1).Infof("Finished reconciling OperandRequest: %s", req.NamespacedName) return ctrl.Result{RequeueAfter: constant.DefaultSyncPeriod}, nil } diff --git a/controllers/operandrequest/reconcile_operand.go b/controllers/operandrequest/reconcile_operand.go index 50876ced..240ada10 100644 --- a/controllers/operandrequest/reconcile_operand.go +++ b/controllers/operandrequest/reconcile_operand.go @@ -183,7 +183,7 @@ func (r *Reconciler) reconcileOperand(ctx context.Context, requestInstance *oper klog.V(2).Infof("There is no service: %s from the OperandConfig instance: %s/%s, Skip reconciling Operands", operand.Name, registryKey.Namespace, req.Registry) continue } - err = r.reconcileCRwithConfig(ctx, opdConfig, configInstance.Namespace, csv, requestInstance, sub.Namespace, &r.Mutex) + err = r.reconcileCRwithConfig(ctx, opdConfig, configInstance.Namespace, csv, requestInstance, operand.Name, sub.Namespace, &r.Mutex) if err != nil { merr.Add(err) requestInstance.SetMemberStatus(operand.Name, "", operatorv1alpha1.ServiceFailed, &r.Mutex) @@ -215,7 +215,7 @@ func (r *Reconciler) reconcileOperand(ctx context.Context, requestInstance *oper } // reconcileCRwithConfig merge and create custom resource base on OperandConfig and CSV alm-examples -func (r *Reconciler) reconcileCRwithConfig(ctx context.Context, service *operatorv1alpha1.ConfigService, namespace string, csv *olmv1alpha1.ClusterServiceVersion, requestInstance *operatorv1alpha1.OperandRequest, operatorNamespace string, mu sync.Locker) error { +func (r *Reconciler) reconcileCRwithConfig(ctx context.Context, service *operatorv1alpha1.ConfigService, namespace string, csv *olmv1alpha1.ClusterServiceVersion, requestInstance *operatorv1alpha1.OperandRequest, operandName string, operatorNamespace string, mu sync.Locker) error { merr := &util.MultiErr{} // Create k8s resources required by service @@ -337,10 +337,6 @@ func (r *Reconciler) reconcileCRwithConfig(ctx context.Context, service *operato merr.Add(err) continue } - managedBy, err := r.getManagedBy(crFromALM) - if err != nil { - return err - } statusSpec, err := r.getOperandStatus(crFromALM) if err != nil { return err @@ -349,7 +345,7 @@ func (r *Reconciler) reconcileCRwithConfig(ctx context.Context, service *operato if serviceKind != "OperandRequest" && statusSpec.ObjectName != "" { var resources []operatorv1alpha1.OperandStatus resources = append(resources, statusSpec) - serviceSpec := newServiceStatus(managedBy, operatorNamespace, resources) + serviceSpec := newServiceStatus(operandName, operatorNamespace, resources) seterr := requestInstance.SetServiceStatus(ctx, serviceSpec, r.Client, mu) if seterr != nil { return seterr @@ -421,10 +417,6 @@ func (r *Reconciler) reconcileCRwithRequest(ctx context.Context, requestInstance if err := r.updateCustomResource(ctx, crFromRequest, requestKey.Namespace, operand.Kind, operand.Spec.Raw, map[string]interface{}{}); err != nil { return err } - managedBy, err := r.getManagedBy(crFromRequest) - if err != nil { - return err - } statusSpec, err := r.getOperandStatus(crFromRequest) if err != nil { return err @@ -432,7 +424,7 @@ func (r *Reconciler) reconcileCRwithRequest(ctx context.Context, requestInstance if operand.Kind != "OperandRequest" && statusSpec.ObjectName != "" { var resources []operatorv1alpha1.OperandStatus resources = append(resources, statusSpec) - serviceSpec := newServiceStatus(managedBy, operatorNamespace, resources) + serviceSpec := newServiceStatus(operand.Name, operatorNamespace, resources) seterr := requestInstance.SetServiceStatus(ctx, serviceSpec, r.Client, mu) if seterr != nil { return seterr @@ -449,38 +441,6 @@ func (r *Reconciler) reconcileCRwithRequest(ctx context.Context, requestInstance return nil } -func (r *Reconciler) getManagedBy(existingCR unstructured.Unstructured) (string, error) { - byteMetadata, err := json.Marshal(existingCR.Object["metadata"]) - if err != nil { - klog.Error(err) - return "", err - } - var rawMetadata map[string]interface{} - err = json.Unmarshal(byteMetadata, &rawMetadata) - if err != nil { - klog.Error(err) - return "", err - } - byteLabels, err := json.Marshal(rawMetadata["labels"]) - if err != nil { - klog.Error(err) - return "", err - } - var parsedLabels map[string]string - err = json.Unmarshal(byteLabels, &parsedLabels) - if err != nil { - klog.Error(err) - return "", err - } - var managedBy string - for key, value := range parsedLabels { - if key == "app.kubernetes.io/managed-by" { - managedBy = value - } - } - return managedBy, nil -} - func (r *Reconciler) getOperandStatus(existingCR unstructured.Unstructured) (operatorv1alpha1.OperandStatus, error) { var emptyStatus operatorv1alpha1.OperandStatus byteStatus, err := json.Marshal(existingCR.Object["status"]) From 89602541fe31ab8d7665fe4fac02f98d60796b3b Mon Sep 17 00:00:00 2001 From: Allen Li <46284272+qpdpQ@users.noreply.github.com> Date: Wed, 19 Apr 2023 16:20:18 -0400 Subject: [PATCH 011/179] cp3 migrate to aws (#920) Signed-off-by: Allen Li --- common/Makefile.common.mk | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/common/Makefile.common.mk b/common/Makefile.common.mk index e0e3d760..4b896678 100644 --- a/common/Makefile.common.mk +++ b/common/Makefile.common.mk @@ -26,11 +26,15 @@ OLM_API_VERSION = 0.3.8 activate-serviceaccount: ifdef GOOGLE_APPLICATION_CREDENTIALS - gcloud auth activate-service-account --key-file="$(GOOGLE_APPLICATION_CREDENTIALS)" + gcloud auth activate-service-account --key-file="$(GOOGLE_APPLICATION_CREDENTIALS)" || true endif get-cluster-credentials: activate-serviceaccount - gcloud container clusters get-credentials "$(CLUSTER)" --project="$(PROJECT)" --zone="$(ZONE)" + mkdir -p ~/.kube; cp -v /etc/kubeconfig/config ~/.kube; kubectl config use-context default; kubectl get nodes; echo going forward retiring google cloud + +ifdef GOOGLE_APPLICATION_CREDENTIALS + gcloud container clusters get-credentials "$(CLUSTER)" --project="$(PROJECT)" --zone="$(ZONE)" || true +endif config-docker: get-cluster-credentials @common/scripts/artifactory_config_docker.sh From 04b32e086f7ca82b6c9bd5cfecf51f5c1ef50f70 Mon Sep 17 00:00:00 2001 From: Ben Luzarraga <31223504+bluzarraga@users.noreply.github.com> Date: Mon, 24 Apr 2023 09:43:19 -0500 Subject: [PATCH 012/179] Remove the status.services entry for an operator if it is removed from an operandrequest (#922) * remove status when operator removed from opreq Signed-off-by: Ben Luzarraga * remove status.services entry when operator removed from request Signed-off-by: Ben Luzarraga * run make code-dev Signed-off-by: Ben Luzarraga --------- Signed-off-by: Ben Luzarraga Co-authored-by: Ben Luzarraga --- api/v1alpha1/operandrequest_types.go | 17 +++++++++++++---- .../operandrequest/reconcile_operator.go | 1 + 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/api/v1alpha1/operandrequest_types.go b/api/v1alpha1/operandrequest_types.go index d92e6bf4..e4fd21dc 100644 --- a/api/v1alpha1/operandrequest_types.go +++ b/api/v1alpha1/operandrequest_types.go @@ -410,6 +410,15 @@ func (r *OperandRequest) RemoveMemberCRStatus(name, CRName, CRKind string, mu sy } } +func (r *OperandRequest) RemoveServiceStatus(operatorName string, mu sync.Locker) { + mu.Lock() + defer mu.Unlock() + pos, s := getServiceStatus(&r.Status, operatorName) + if s != nil { + r.Status.Services = append(r.Status.Services[:pos], r.Status.Services[pos+1:]...) + } +} + func (r *OperandRequest) SetServiceStatus(ctx context.Context, service ServiceStatus, updater client.StatusClient, mu sync.Locker) error { mu.Lock() defer mu.Unlock() @@ -667,13 +676,13 @@ func (r *OperandRequest) CheckServiceStatus() bool { requeue = true return requeue } - // var IMOrIAM string + var IMOrIAM string exists := false if foundOperand(r.Spec.Requests, "ibm-iam-operator") { - // IMOrIAM = "ibm-iam-operator" + IMOrIAM = "ibm-iam-operator" exists = true } else if foundOperand(r.Spec.Requests, "ibm-im-operator") { - // IMOrIAM = "ibm-im-operator" + IMOrIAM = "ibm-im-operator" exists = true } @@ -681,7 +690,7 @@ func (r *OperandRequest) CheckServiceStatus() bool { var imIndex int found := false for i, s := range r.Status.Services { - if "ibm-iam-operator" == s.OperatorName { //eventually this should be changed to the variable but the operator name is still listed as iam in practice even when im is requested + if IMOrIAM == s.OperatorName { //eventually this should be changed to the variable but the operator name is still listed as iam in practice even when im is requested found = true imIndex = i break diff --git a/controllers/operandrequest/reconcile_operator.go b/controllers/operandrequest/reconcile_operator.go index 4a1906bd..08ec0810 100644 --- a/controllers/operandrequest/reconcile_operator.go +++ b/controllers/operandrequest/reconcile_operator.go @@ -423,6 +423,7 @@ func (r *Reconciler) absentOperatorsAndOperands(ctx context.Context, requestInst defer r.Mutex.Unlock() merr.Add(err) } + requestInstance.RemoveServiceStatus(fmt.Sprintf("%v", o), &r.Mutex) (*remainingOperands).Remove(o) remainingOp.Remove(o) }() From ce01d9de8dc9514304a7cd7bfc3c1b8605fb93f4 Mon Sep 17 00:00:00 2001 From: Daniel Fan Date: Mon, 24 Apr 2023 18:20:18 -0400 Subject: [PATCH 013/179] Indicate multi requested service version conflict (#921) * Indicate multi requested service version conflict Signed-off-by: Daniel Fan * fix lint issue Signed-off-by: Daniel Fan --------- Signed-off-by: Daniel Fan --- api/v1alpha1/operandrequest_types.go | 9 +++ .../operandrequest/reconcile_operand.go | 24 ++------ .../operandrequest/reconcile_operator.go | 56 +++++++++++++------ controllers/operator/manager.go | 2 +- 4 files changed, 54 insertions(+), 37 deletions(-) diff --git a/api/v1alpha1/operandrequest_types.go b/api/v1alpha1/operandrequest_types.go index e4fd21dc..c0248f32 100644 --- a/api/v1alpha1/operandrequest_types.go +++ b/api/v1alpha1/operandrequest_types.go @@ -107,6 +107,7 @@ const ( ConditionNotFound ConditionType = "NotFound" ConditionOutofScope ConditionType = "OutofScope" ConditionReady ConditionType = "Ready" + ConditionNoConflict ConditionType = "NoConflict" OperatorReady OperatorPhase = "Ready for Deployment" OperatorRunning OperatorPhase = "Running" @@ -319,6 +320,14 @@ func (r *OperandRequest) SetNotFoundOperandRegistryCondition(name string, rt Res r.setCondition(*c) } +// SetNoConflictOperatorCondition creates a NoConflictCondition when an operator channel does not conflict with others. +func (r *OperandRequest) SetNoConflictOperatorCondition(name string, rt ResourceType, cs corev1.ConditionStatus, mu sync.Locker) { + mu.Lock() + defer mu.Unlock() + c := newCondition(ConditionNoConflict, cs, "No channel conflict on "+string(rt), "No channel conflict on "+string(rt)+" "+name+" in the scope") + r.setCondition(*c) +} + // setReadyCondition creates a Condition to claim Ready. func (r *OperandRequest) setReadyCondition(name string, rt ResourceType, cs corev1.ConditionStatus) { c := &Condition{} diff --git a/controllers/operandrequest/reconcile_operand.go b/controllers/operandrequest/reconcile_operand.go index 240ada10..5808722b 100644 --- a/controllers/operandrequest/reconcile_operand.go +++ b/controllers/operandrequest/reconcile_operand.go @@ -98,22 +98,6 @@ func (r *Reconciler) reconcileOperand(ctx context.Context, requestInstance *oper klog.Warningf("Subscription %s in the namespace %s isn't created by ODLM", sub.Name, sub.Namespace) } - // For singleton services, identify latest OperandRegistry/Config version has the priority to reconcile - if CheckSingletonServices(operatorName) { - // v1IsLarger is true if subscription has larger channel version than the version in OperandRegistry - // Skip this operator CR creation because it does not have the latest version in OperandRegistry - v1IsLarger, convertErr := util.CompareChannelVersion(sub.Spec.Channel, opdRegistry.Channel) - if convertErr != nil { - merr.Add(errors.Wrapf(err, "failed to compare channel version for the Subscription %s in the namespace %s", operatorName, namespace)) - return merr - } - if v1IsLarger { - klog.V(2).Infof("Subscription %s in the namespace %s is managed by other OperandRequest with newer version %s", sub.Name, sub.Namespace, sub.Spec.Channel) - requestInstance.SetMemberStatus(operand.Name, operatorv1alpha1.OperatorRunning, "", &r.Mutex) - continue - } - } - // It the installplan is not created yet, ODLM will try later if sub.Status.Install == nil || sub.Status.InstallPlanRef.Name == "" { klog.Warningf("The Installplan for Subscription %s is not ready. Will check it again", sub.Name) @@ -154,9 +138,6 @@ func (r *Reconciler) reconcileOperand(ctx context.Context, requestInstance *oper continue } - klog.V(3).Info("Generating customresource base on ClusterServiceVersion: ", csv.GetName()) - requestInstance.SetMemberStatus(operand.Name, operatorv1alpha1.OperatorRunning, "", &r.Mutex) - // find the OperandRequest which has the same operator's channel version as existing subscription. // ODLM will only reconcile Operand based on OperandConfig for this OperandRequest var requestList []string @@ -169,10 +150,13 @@ func (r *Reconciler) reconcileOperand(ctx context.Context, requestInstance *oper if len(requestList) == 0 || !util.Contains(requestList, requestInstance.Namespace+"."+requestInstance.Name+"."+operand.Name+"/request") { klog.V(2).Infof("Subscription %s in the namespace %s is NOT managed by %s/%s, Skip reconciling Operands", sub.Name, sub.Namespace, requestInstance.Namespace, requestInstance.Name) - requestInstance.SetMemberStatus(operand.Name, "", operatorv1alpha1.ServiceRunning, &r.Mutex) + requestInstance.SetMemberStatus(operand.Name, "", operatorv1alpha1.ServiceFailed, &r.Mutex) continue } + klog.V(3).Info("Generating customresource base on ClusterServiceVersion: ", csv.GetName()) + requestInstance.SetMemberStatus(operand.Name, operatorv1alpha1.OperatorRunning, "", &r.Mutex) + // Merge and Generate CR if operand.Kind == "" { configInstance, err := r.GetOperandConfig(ctx, registryKey) diff --git a/controllers/operandrequest/reconcile_operator.go b/controllers/operandrequest/reconcile_operator.go index 08ec0810..8202004d 100644 --- a/controllers/operandrequest/reconcile_operator.go +++ b/controllers/operandrequest/reconcile_operator.go @@ -18,11 +18,13 @@ package operandrequest import ( "context" + "encoding/json" "fmt" "regexp" "sort" "strings" "sync" + "time" gset "github.com/deckarep/golang-set" olmv1 "github.com/operator-framework/api/pkg/operators/v1" @@ -35,6 +37,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/types" + utilerrors "k8s.io/apimachinery/pkg/util/errors" "k8s.io/klog" "sigs.k8s.io/controller-runtime/pkg/client" @@ -67,8 +70,21 @@ func (r *Reconciler) reconcileOperator(ctx context.Context, requestInstance *ope } else { requestInstance.SetNoSuitableRegistryCondition(registryKey.String(), err.Error(), operatorv1alpha1.ResourceTypeOperandRegistry, corev1.ConditionTrue, &r.Mutex) } + t := time.Now() + formatted := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02d", + t.Year(), t.Month(), t.Day(), + t.Hour(), t.Minute(), t.Second()) + mergePatch, _ := json.Marshal(map[string]interface{}{ + "metadata": map[string]interface{}{ + "annotations": map[string]interface{}{ + constant.FindOperandRegistry: formatted, + }, + }, + }) + if patchErr := r.Patch(ctx, requestInstance, client.RawPatch(types.MergePatchType, mergePatch)); patchErr != nil { + return utilerrors.NewAggregate([]error{err, patchErr}) + } klog.Errorf("Failed to get suitable OperandRegistry %s: %v", registryKey.String(), err) - return err } merr := &util.MultiErr{} @@ -119,9 +135,14 @@ func (r *Reconciler) reconcileOperator(ctx context.Context, requestInstance *ope func (r *Reconciler) reconcileSubscription(ctx context.Context, requestInstance *operatorv1alpha1.OperandRequest, registryInstance *operatorv1alpha1.OperandRegistry, operand operatorv1alpha1.Operand, registryKey types.NamespacedName, mu sync.Locker) error { // Check the requested Operand if exist in specific OperandRegistry - opt := registryInstance.GetOperator(operand.Name) + var opt *operatorv1alpha1.Operator + if registryInstance != nil { + opt = registryInstance.GetOperator(operand.Name) + } if opt == nil { - klog.V(1).Infof("Operator %s not found in the OperandRegistry %s/%s", operand.Name, registryInstance.Namespace, registryInstance.Name) + if registryInstance != nil { + klog.V(1).Infof("Operator %s not found in the OperandRegistry %s/%s", operand.Name, registryInstance.Namespace, registryInstance.Name) + } requestInstance.SetNotFoundOperatorFromRegistryCondition(operand.Name, operatorv1alpha1.ResourceTypeSub, corev1.ConditionTrue, mu) requestInstance.SetMemberStatus(operand.Name, operatorv1alpha1.OperatorNotFound, operatorv1alpha1.ServiceNotFound, mu) return nil @@ -157,6 +178,7 @@ func (r *Reconciler) reconcileSubscription(ctx context.Context, requestInstance // Subscription existing and managed by OperandRequest controller if _, ok := sub.Labels[constant.OpreqLabel]; ok { originalSub := sub.DeepCopy() + var isMatchedChannel bool // add annotations to existing Subscriptions for upgrade case if sub.Annotations == nil { @@ -167,12 +189,14 @@ func (r *Reconciler) reconcileSubscription(ctx context.Context, requestInstance sub.Annotations[requestInstance.Namespace+"."+requestInstance.Name+"."+operand.Name+"/request"] = opt.Channel if opt.InstallMode == operatorv1alpha1.InstallModeNoop { + isMatchedChannel = true requestInstance.SetNoSuitableRegistryCondition(registryKey.String(), opt.Name+" is in maintenance status", operatorv1alpha1.ResourceTypeOperandRegistry, corev1.ConditionTrue, &r.Mutex) requestInstance.SetMemberStatus(operand.Name, operatorv1alpha1.OperatorRunning, operatorv1alpha1.ServiceRunning, mu) //set operator channel back to previous one if it is tombstone service sub.Annotations[requestInstance.Namespace+"."+requestInstance.Name+"."+operand.Name+"/request"] = sub.Spec.Channel } else { + requestInstance.SetNotFoundOperatorFromRegistryCondition(operand.Name, operatorv1alpha1.ResourceTypeSub, corev1.ConditionFalse, mu) // check request annotation in subscription, get all available channels var semverlList []string @@ -193,6 +217,7 @@ func (r *Reconciler) reconcileSubscription(ctx context.Context, requestInstance // update the spec iff channel in sub matches channel in opreg if sub.Spec.Channel == opt.Channel { + isMatchedChannel = true sub.Spec.CatalogSource = opt.SourceName sub.Spec.CatalogSourceNamespace = opt.SourceNamespace sub.Spec.Package = opt.PackageName @@ -213,6 +238,13 @@ func (r *Reconciler) reconcileSubscription(ctx context.Context, requestInstance } requestInstance.SetMemberStatus(opt.Name, operatorv1alpha1.OperatorUpdating, "", mu) } + + if !isMatchedChannel { + requestInstance.SetNoConflictOperatorCondition(operand.Name, operatorv1alpha1.ResourceTypeSub, corev1.ConditionFalse, mu) + requestInstance.SetMemberStatus(opt.Name, operatorv1alpha1.OperatorFailed, "", mu) + } else { + requestInstance.SetNoConflictOperatorCondition(operand.Name, operatorv1alpha1.ResourceTypeSub, corev1.ConditionTrue, mu) + } } else { // Subscription existing and not managed by OperandRequest controller klog.V(1).Infof("Subscription %s in namespace %s isn't created by ODLM. Ignore update/delete it.", sub.Name, sub.Namespace) @@ -290,7 +322,6 @@ func (r *Reconciler) deleteSubscription(ctx context.Context, operandName string, namespace := r.GetOperatorNamespace(op.InstallMode, op.Namespace) sub, err := r.GetSubscription(ctx, operandName, namespace, op.PackageName) - originalsub := sub.DeepCopy() if apierrors.IsNotFound(err) { klog.V(3).Infof("There is no Subscription %s or %s in the namespace %s", operandName, op.PackageName, namespace) return nil @@ -316,28 +347,21 @@ func (r *Reconciler) deleteSubscription(ctx context.Context, operandName string, reqNs := requestInstance.ObjectMeta.Namespace delete(sub.Annotations, reqNs+"."+reqName+"."+op.Name+"/request") - var semverlList []string var annoSlice []string reg, _ := regexp.Compile(`^(.*)\.(.*)\.(.*)\/request`) - for anno, channel := range sub.Annotations { + for anno := range sub.Annotations { if reg.MatchString(anno) { annoSlice = append(annoSlice, anno) - if semver.IsValid(channel) { - semverlList = append(semverlList, channel) - } } } if len(annoSlice) != 0 { - // update channel to minmial version remaining in annotations - if len(semverlList) != 0 && !util.Contains(semverlList, sub.Spec.Channel) { - sort.Sort(semver.ByVersion(semverlList)) - sub.Spec.Channel = semverlList[0] - } // remove the associated registry from annotation of subscription - if err := r.Patch(ctx, sub, client.MergeFrom(originalsub)); err != nil { - requestInstance.SetUpdatingCondition(sub.Name, operatorv1alpha1.ResourceTypeSub, corev1.ConditionFalse, &r.Mutex) + if err = r.updateSubscription(ctx, requestInstance, sub); err != nil { + requestInstance.SetMemberStatus(op.Name, operatorv1alpha1.OperatorFailed, "", &r.Mutex) return err } + requestInstance.SetMemberStatus(op.Name, operatorv1alpha1.OperatorUpdating, "", &r.Mutex) + klog.V(1).Infof("Did not delete Subscription %s/%s which is requested by other OperandRequests", sub.Namespace, sub.Name) return nil } diff --git a/controllers/operator/manager.go b/controllers/operator/manager.go index e1c81603..0ed67f13 100644 --- a/controllers/operator/manager.go +++ b/controllers/operator/manager.go @@ -89,7 +89,7 @@ func (m *ODLMOperator) GetOperandRegistry(ctx context.Context, key types.Namespa if o.SourceName == "" || o.SourceNamespace == "" { catalogSourceName, catalogSourceNs, err := m.GetCatalogSourceFromPackage(ctx, o.PackageName, o.Namespace, o.Channel, key.Namespace, excludedCatalogSources) if err != nil { - return reg, err + return nil, err } if catalogSourceName == "" || catalogSourceNs == "" { From 417b855f8f1be60b9f896639d9080a2d569daf5a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 27 Apr 2023 05:50:19 +0800 Subject: [PATCH 014/179] build(deps): bump golang.org/x/text from 0.3.6 to 0.3.8 (#898) Bumps [golang.org/x/text](https://github.com/golang/text) from 0.3.6 to 0.3.8. - [Release notes](https://github.com/golang/text/releases) - [Commits](https://github.com/golang/text/compare/v0.3.6...v0.3.8) --- updated-dependencies: - dependency-name: golang.org/x/text dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 4 ++-- go.sum | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index 75295cc7..f8fba07b 100644 --- a/go.mod +++ b/go.mod @@ -60,9 +60,9 @@ require ( go.uber.org/zap v1.18.1 // indirect golang.org/x/net v0.0.0-20211209124913-491a49abca63 // indirect golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d // indirect - golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c // indirect + golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f // indirect golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d // indirect - golang.org/x/text v0.3.6 // indirect + golang.org/x/text v0.3.8 // indirect golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect google.golang.org/appengine v1.6.7 // indirect diff --git a/go.sum b/go.sum index f0f0ef53..c382f1d5 100644 --- a/go.sum +++ b/go.sum @@ -1034,8 +1034,9 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f h1:v4INt8xihDGvnrfjMDVXGxw9wrfxYyCjk0KbXjhR55s= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d h1:SZxvLBoTP5yHO3Frd4z4vrF+DBX9vMVanchswa69toE= @@ -1047,8 +1048,9 @@ golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3 golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.8 h1:nAL+RVCQ9uMn3vJZbV+MRnydTJFPf8qqY42YiA6MrqY= +golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= From 97a954d3212c3c11cdb10558a08ed9912582e25a Mon Sep 17 00:00:00 2001 From: Daniel Fan Date: Thu, 18 May 2023 00:03:58 -0400 Subject: [PATCH 015/179] Update test case (#927) * Update Kind cluster version Signed-off-by: Daniel Fan * Update OLM version and install script to v0.24.0 Signed-off-by: Daniel Fan * update test cases Signed-off-by: Daniel Fan * update CRD template Signed-off-by: Daniel Fan * set owner reference for CR created by OpReq Signed-off-by: Daniel Fan * Update error msg Signed-off-by: Daniel Fan * Update go mod Signed-off-by: Daniel Fan * Update Makefile to build bundle and catalog image Signed-off-by: Daniel Fan --------- Signed-off-by: Daniel Fan --- Makefile | 49 +- api/v1alpha1/operandrequest_types.go | 6 +- ...fecycle-manager.clusterserviceversion.yaml | 35 +- .../operator.ibm.com_operandregistries.yaml | 1059 +++++++++-------- .../operator.ibm.com_operandrequests.yaml | 21 +- common/Makefile.common.mk | 16 +- common/scripts/install-olm.sh | 36 +- .../operator.ibm.com_operandregistries.yaml | 1059 +++++++++-------- .../operator.ibm.com_operandrequests.yaml | 48 + .../operator_v1alpha1_operandconfig.yaml | 17 +- .../operator_v1alpha1_operandregistry.yaml | 14 +- .../operator_v1alpha1_operandrequest.yaml | 4 +- .../namespacescope_suite_test.go | 10 +- .../operandbindinfo_suite_test.go | 10 +- .../operandconfig_controller_test.go | 68 +- .../operandconfig/operandconfig_suite_test.go | 10 +- .../operandregistry_controller_test.go | 68 +- .../operandregistry_suite_test.go | 10 +- .../operandrequest_controller.go | 3 +- .../operandrequest_controller_test.go | 266 ++--- .../operandrequest_suite_test.go | 10 +- .../operandrequest/reconcile_operand.go | 5 + controllers/testutil/test_data.go | 29 +- controllers/testutil/test_util.go | 87 +- go.mod | 105 +- go.sum | 634 ++++++++-- test/e2e/constants.go | 2 +- test/e2e/e2e_suite_test.go | 6 +- test/e2e/helpers_test.go | 100 +- test/e2e/odlm_test.go | 58 +- test/e2e/utils_test.go | 4 +- 31 files changed, 2270 insertions(+), 1579 deletions(-) diff --git a/Makefile b/Makefile index 4493b9d9..93dafffb 100644 --- a/Makefile +++ b/Makefile @@ -32,7 +32,7 @@ VERSION ?= $(shell git describe --exact-match 2> /dev/null || \ git describe --match=$(git rev-parse --short=8 HEAD) --always --dirty --abbrev=8) RELEASE_VERSION ?= $(shell cat ./version/version.go | grep "Version =" | awk '{ print $$3}' | tr -d '"') LATEST_VERSION ?= latest -OPERATOR_SDK_VERSION=v1.10.0 +OPERATOR_SDK_VERSION=v1.24.0 YQ_VERSION=v4.3.1 LOCAL_OS := $(shell uname) @@ -134,21 +134,21 @@ else YQ=$(shell which yq) endif -# operator-sdk: -# ifneq ($(shell operator-sdk version | cut -d ',' -f1 | cut -d ':' -f2 | tr -d '"' | xargs | cut -d '.' -f1), v1) -# @{ \ -# if [ "$(shell ./bin/operator-sdk version | cut -d ',' -f1 | cut -d ':' -f2 | tr -d '"' | xargs)" != $(OPERATOR_SDK_VERSION) ]; then \ -# set -e ; \ -# mkdir -p bin ;\ -# echo "Downloading operator-sdk..." ;\ -# curl -sSLo ./bin/operator-sdk "https://github.com/operator-framework/operator-sdk/releases/download/$(OPERATOR_SDK_VERSION)/operator-sdk_$(LOCAL_OS)_$(LOCAL_ARCH)" ;\ -# chmod +x ./bin/operator-sdk ;\ -# fi ;\ -# } -# OPERATOR_SDK=$(realpath ./bin/operator-sdk) -# else -# OPERATOR_SDK=$(shell which operator-sdk) -# endif +operator-sdk: +ifneq ($(shell operator-sdk version | cut -d ',' -f1 | cut -d ':' -f2 | tr -d '"' | xargs | cut -d '.' -f1), v1) + @{ \ + if [ "$(shell ./bin/operator-sdk version | cut -d ',' -f1 | cut -d ':' -f2 | tr -d '"' | xargs)" != $(OPERATOR_SDK_VERSION) ]; then \ + set -e ; \ + mkdir -p bin ;\ + echo "Downloading operator-sdk..." ;\ + curl -sSLo ./bin/operator-sdk "https://github.com/operator-framework/operator-sdk/releases/download/$(OPERATOR_SDK_VERSION)/operator-sdk_$(LOCAL_OS)_$(LOCAL_ARCH)" ;\ + chmod +x ./bin/operator-sdk ;\ + fi ;\ + } +OPERATOR_SDK=$(realpath ./bin/operator-sdk) +else +OPERATOR_SDK=$(shell which operator-sdk) +endif code-dev: ## Run the default dev commands which are the go tidy, fmt, vet then execute the $ make code-gen @echo Running the common required commands for developments purposes @@ -225,7 +225,7 @@ kind-start: kind echo "KIND Cluster already exists" && exit 0 || \ echo "Creating KIND Cluster" && \ ${KIND} create cluster --name ${KIND_CLUSTER_NAME} --config=./common/config/kind-config.yaml && \ - common/scripts/install-olm.sh 0.16.1 + common/scripts/install-olm.sh v0.24.0 kind-delete: @@ -268,16 +268,19 @@ build-push-image: $(CONFIG_DOCKER_TARGET) build-operator-image ## Build and pus @docker tag $(OPERATOR_IMAGE_NAME)-$(LOCAL_ARCH):$(VERSION) $(ARTIFACTORYA_REGISTRY)/$(OPERATOR_IMAGE_NAME)-$(LOCAL_ARCH):$(VERSION) @docker push $(ARTIFACTORYA_REGISTRY)/$(OPERATOR_IMAGE_NAME)-$(LOCAL_ARCH):$(VERSION) -build-dev-bundle-image: yq +build-push-bundle-image: yq @cp -f bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml /tmp/operand-deployment-lifecycle-manager.clusterserviceversion.yaml $(YQ) eval -i 'del(.spec.replaces)' bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml - docker build -f bundle.Dockerfile -t $(QUAY_REGISTRY)/$(BUNDLE_IMAGE_NAME):dev . - docker push $(QUAY_REGISTRY)/$(BUNDLE_IMAGE_NAME):dev - @mv /tmp/operand-deployment-lifecycle-manager.clusterserviceversion.yaml bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml - -build-push-bundle-image: $(CONFIG_DOCKER_TARGET_QUAY) build-bundle-image ## Build and push the bundle images. + @docker build -f bundle.Dockerfile -t $(QUAY_REGISTRY)/$(BUNDLE_IMAGE_NAME)-$(LOCAL_ARCH):$(VERSION) . @echo "Pushing the $(BUNDLE_IMAGE_NAME) docker image for $(LOCAL_ARCH)..." @docker push $(QUAY_REGISTRY)/$(BUNDLE_IMAGE_NAME)-$(LOCAL_ARCH):$(VERSION) + @mv /tmp/operand-deployment-lifecycle-manager.clusterserviceversion.yaml bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml + +build-catalog-source: + @opm -u docker index add --bundles $(QUAY_REGISTRY)/$(BUNDLE_IMAGE_NAME)-$(LOCAL_ARCH):$(VERSION) --tag $(QUAY_REGISTRY)/$(OPERATOR_IMAGE_NAME)-catalog:$(VERSION) + @docker push $(QUAY_REGISTRY)/$(OPERATOR_IMAGE_NAME)-catalog:$(VERSION) + +build-catalog: build-push-bundle-image build-catalog-source multiarch-image: $(CONFIG_DOCKER_TARGET) ## Generate multiarch images for operator image. @MAX_PULLING_RETRY=20 RETRY_INTERVAL=30 common/scripts/multiarch_image.sh $(ARTIFACTORYA_REGISTRY) $(OPERATOR_IMAGE_NAME) $(VERSION) $(RELEASE_VERSION) diff --git a/api/v1alpha1/operandrequest_types.go b/api/v1alpha1/operandrequest_types.go index c0248f32..b2634365 100644 --- a/api/v1alpha1/operandrequest_types.go +++ b/api/v1alpha1/operandrequest_types.go @@ -169,11 +169,11 @@ type OperandStatus struct { //Top level CR status ie the CR created by ODLM APIVersion string `json:"apiVersion,omitempty"` Namespace string `json:"namespace,omitempty"` Kind string `json:"kind,omitempty"` - // Type string `json:"type,omitempty"` - Status string `json:"status,omitempty"` - // LastTransitionTime string `json:"lastTransitionTime,omitempty"` //might need to change the variable type + Status string `json:"status,omitempty"` // Message string `json:"message,omitempty"` ManagedResources []ResourceStatus `json:"managedResources,omitempty"` + // Type string `json:"type,omitempty"` + // LastTransitionTime string `json:"lastTransitionTime,omitempty"` //might need to change the variable type } type ServiceStatus struct { //Top level service status diff --git a/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml b/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml index 6f56ddd7..2a976910 100644 --- a/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml +++ b/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml @@ -18,19 +18,22 @@ metadata: "spec": { "services": [ { - "name": "etcd", + "name": "jaeger", "spec": { - "etcdCluster": { - "size": 1 + "jaeger": { + "strategy": "allinone" } } }, { - "name": "jenkins", + "name": "mongodb-atlas-kubernetes", "spec": { - "jenkins": { - "service": { - "port": 8081 + "atlasDeployment": { + "deploymentSpec": { + "name": "test-deployment" + }, + "projectRef": { + "name": "my-project" } } } @@ -52,19 +55,19 @@ metadata: "spec": { "operators": [ { - "channel": "clusterwide-alpha", + "channel": "stable", "installMode": "cluster", - "name": "etcd", - "namespace": "etcd-cluster-operator", - "packageName": "etcd", + "name": "jaeger", + "namespace": "default", + "packageName": "jaeger", "sourceName": "community-operators", "sourceNamespace": "openshift-marketplace" }, { - "channel": "alpha", - "name": "jenkins", + "channel": "stable", + "name": "mongodb-atlas-kubernetes", "namespace": "default", - "packageName": "jenkins-operator", + "packageName": "mongodb-atlas-kubernetes", "sourceName": "community-operators", "sourceNamespace": "openshift-marketplace" } @@ -87,10 +90,10 @@ metadata: { "operands": [ { - "name": "etcd" + "name": "jaeger" }, { - "name": "jenkins" + "name": "mongodb-atlas-kubernetes" } ], "registry": "example-service" diff --git a/bundle/manifests/operator.ibm.com_operandregistries.yaml b/bundle/manifests/operator.ibm.com_operandregistries.yaml index 4849798a..6cd0ce3f 100644 --- a/bundle/manifests/operator.ibm.com_operandregistries.yaml +++ b/bundle/manifests/operator.ibm.com_operandregistries.yaml @@ -63,12 +63,11 @@ spec: description: Description of a common service. type: string installMode: - description: 'The install mode of an operator, could be namespace, - cluster or no-op. Valid values are: - "namespace" (default): operator + description: 'The install mode of an operator, either namespace + or cluster. Valid values are: - "namespace" (default): operator is deployed in namespace of OperandRegistry; - "cluster": - operator is deployed in "openshift-operators" namespace; - "no-op": - operator is not supported to be fresh deployed via OperandRequest, - only upgrade and deletion are allowed;' + operator is deployed in "openshift-operators" namespace; - + "no-op": operator is not supported to be fresh deployed;' type: string installPlanApproval: description: 'Approval mode for emitted InstallPlans. Valid @@ -126,14 +125,16 @@ spec: type: string value: description: 'Variable references $(VAR_NAME) are - expanded using the previous defined environment + expanded using the previously defined environment variables in the container and any service environment variables. If a variable cannot be resolved, the reference in the input string will be unchanged. - The $(VAR_NAME) syntax can be escaped with a double - $$, ie: $$(VAR_NAME). Escaped references will never - be expanded, regardless of whether the variable - exists or not. Defaults to "".' + Double $$ are reduced to a single $, which allows + for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" + will produce the string literal "$(VAR_NAME)". Escaped + references will never be expanded, regardless of + whether the variable exists or not. Defaults to + "".' type: string valueFrom: description: Source for the environment variable's @@ -448,128 +449,133 @@ spec: that may be accessed by any container in the pod. properties: awsElasticBlockStore: - description: 'AWSElasticBlockStore represents an AWS + description: 'awsElasticBlockStore represents an AWS Disk resource that is attached to a kubelet''s host machine and then exposed to the pod. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' properties: fsType: - description: 'Filesystem type of the volume that - you want to mount. Tip: Ensure that the filesystem - type is supported by the host operating system. - Examples: "ext4", "xfs", "ntfs". Implicitly - inferred to be "ext4" if unspecified. More info: - https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore + description: 'fsType is the filesystem type of + the volume that you want to mount. Tip: Ensure + that the filesystem type is supported by the + host operating system. Examples: "ext4", "xfs", + "ntfs". Implicitly inferred to be "ext4" if + unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore TODO: how do we prevent errors in the filesystem from compromising the machine' type: string partition: - description: 'The partition in the volume that - you want to mount. If omitted, the default is - to mount by volume name. Examples: For volume - /dev/sda1, you specify the partition as "1". - Similarly, the volume partition for /dev/sda - is "0" (or you can leave the property empty).' + description: 'partition is the partition in the + volume that you want to mount. If omitted, the + default is to mount by volume name. Examples: + For volume /dev/sda1, you specify the partition + as "1". Similarly, the volume partition for + /dev/sda is "0" (or you can leave the property + empty).' format: int32 type: integer readOnly: - description: 'Specify "true" to force and set - the ReadOnly property in VolumeMounts to "true". - If omitted, the default is "false". More info: + description: 'readOnly value true will force the + readOnly setting in VolumeMounts. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' type: boolean volumeID: - description: 'Unique ID of the persistent disk - resource in AWS (Amazon EBS volume). More info: - https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' + description: 'volumeID is unique ID of the persistent + disk resource in AWS (Amazon EBS volume). More + info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' type: string required: - volumeID type: object azureDisk: - description: AzureDisk represents an Azure Data Disk + description: azureDisk represents an Azure Data Disk mount on the host and bind mount to the pod. properties: cachingMode: - description: 'Host Caching mode: None, Read Only, - Read Write.' + description: 'cachingMode is the Host Caching + mode: None, Read Only, Read Write.' type: string diskName: - description: The Name of the data disk in the - blob storage + description: diskName is the Name of the data + disk in the blob storage type: string diskURI: - description: The URI the data disk in the blob - storage + description: diskURI is the URI of data disk in + the blob storage type: string fsType: - description: Filesystem type to mount. Must be - a filesystem type supported by the host operating - system. Ex. "ext4", "xfs", "ntfs". Implicitly - inferred to be "ext4" if unspecified. + description: fsType is Filesystem type to mount. + Must be a filesystem type supported by the host + operating system. Ex. "ext4", "xfs", "ntfs". + Implicitly inferred to be "ext4" if unspecified. type: string kind: - description: 'Expected values Shared: multiple - blob disks per storage account Dedicated: single - blob disk per storage account Managed: azure - managed data disk (only in managed availability + description: 'kind expected values are Shared: + multiple blob disks per storage account Dedicated: + single blob disk per storage account Managed: + azure managed data disk (only in managed availability set). defaults to shared' type: string readOnly: - description: Defaults to false (read/write). ReadOnly - here will force the ReadOnly setting in VolumeMounts. + description: readOnly Defaults to false (read/write). + ReadOnly here will force the ReadOnly setting + in VolumeMounts. type: boolean required: - diskName - diskURI type: object azureFile: - description: AzureFile represents an Azure File Service + description: azureFile represents an Azure File Service mount on the host and bind mount to the pod. properties: readOnly: - description: Defaults to false (read/write). ReadOnly - here will force the ReadOnly setting in VolumeMounts. + description: readOnly defaults to false (read/write). + ReadOnly here will force the ReadOnly setting + in VolumeMounts. type: boolean secretName: - description: the name of secret that contains - Azure Storage Account Name and Key + description: secretName is the name of secret + that contains Azure Storage Account Name and + Key type: string shareName: - description: Share Name + description: shareName is the azure share Name type: string required: - secretName - shareName type: object cephfs: - description: CephFS represents a Ceph FS mount on + description: cephFS represents a Ceph FS mount on the host that shares a pod's lifetime properties: monitors: - description: 'Required: Monitors is a collection - of Ceph monitors More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + description: 'monitors is Required: Monitors is + a collection of Ceph monitors More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' items: type: string type: array path: - description: 'Optional: Used as the mounted root, - rather than the full Ceph tree, default is /' + description: 'path is Optional: Used as the mounted + root, rather than the full Ceph tree, default + is /' type: string readOnly: - description: 'Optional: Defaults to false (read/write). - ReadOnly here will force the ReadOnly setting - in VolumeMounts. More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + description: 'readOnly is Optional: Defaults to + false (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. More info: + https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' type: boolean secretFile: - description: 'Optional: SecretFile is the path - to key ring for User, default is /etc/ceph/user.secret - More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + description: 'secretFile is Optional: SecretFile + is the path to key ring for User, default is + /etc/ceph/user.secret More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' type: string secretRef: - description: 'Optional: SecretRef is reference - to the authentication secret for User, default - is empty. More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + description: 'secretRef is Optional: SecretRef + is reference to the authentication secret for + User, default is empty. More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' properties: name: description: 'Name of the referent. More info: @@ -579,32 +585,33 @@ spec: type: string type: object user: - description: 'Optional: User is the rados user - name, default is admin More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + description: 'user is optional: User is the rados + user name, default is admin More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' type: string required: - monitors type: object cinder: - description: 'Cinder represents a cinder volume attached + description: 'cinder represents a cinder volume attached and mounted on kubelets host machine. More info: https://examples.k8s.io/mysql-cinder-pd/README.md' properties: fsType: - description: 'Filesystem type to mount. Must be - a filesystem type supported by the host operating - system. Examples: "ext4", "xfs", "ntfs". Implicitly - inferred to be "ext4" if unspecified. More info: - https://examples.k8s.io/mysql-cinder-pd/README.md' + description: 'fsType is the filesystem type to + mount. Must be a filesystem type supported by + the host operating system. Examples: "ext4", + "xfs", "ntfs". Implicitly inferred to be "ext4" + if unspecified. More info: https://examples.k8s.io/mysql-cinder-pd/README.md' type: string readOnly: - description: 'Optional: Defaults to false (read/write). + description: 'readOnly defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts. More info: https://examples.k8s.io/mysql-cinder-pd/README.md' type: boolean secretRef: - description: 'Optional: points to a secret object - containing parameters used to connect to OpenStack.' + description: 'secretRef is optional: points to + a secret object containing parameters used to + connect to OpenStack.' properties: name: description: 'Name of the referent. More info: @@ -614,33 +621,33 @@ spec: type: string type: object volumeID: - description: 'volume id used to identify the volume + description: 'volumeID used to identify the volume in cinder. More info: https://examples.k8s.io/mysql-cinder-pd/README.md' type: string required: - volumeID type: object configMap: - description: ConfigMap represents a configMap that + description: configMap represents a configMap that should populate this volume properties: defaultMode: - description: 'Optional: mode bits used to set - permissions on created files by default. Must - be an octal value between 0000 and 0777 or a - decimal value between 0 and 511. YAML accepts - both octal and decimal values, JSON requires - decimal values for mode bits. Defaults to 0644. - Directories within the path are not affected - by this setting. This might be in conflict with - other options that affect the file mode, like - fsGroup, and the result can be other mode bits - set.' + description: 'defaultMode is optional: mode bits + used to set permissions on created files by + default. Must be an octal value between 0000 + and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, + JSON requires decimal values for mode bits. + Defaults to 0644. Directories within the path + are not affected by this setting. This might + be in conflict with other options that affect + the file mode, like fsGroup, and the result + can be other mode bits set.' format: int32 type: integer items: - description: If unspecified, each key-value pair - in the Data field of the referenced ConfigMap + description: items if unspecified, each key-value + pair in the Data field of the referenced ConfigMap will be projected into the volume as a file whose name is the key and content is the value. If specified, the listed keys will be projected @@ -655,27 +662,28 @@ spec: a volume. properties: key: - description: The key to project. + description: key is the key to project. type: string mode: - description: 'Optional: mode bits used to - set permissions on this file. Must be - an octal value between 0000 and 0777 or - a decimal value between 0 and 511. YAML - accepts both octal and decimal values, - JSON requires decimal values for mode - bits. If not specified, the volume defaultMode - will be used. This might be in conflict - with other options that affect the file - mode, like fsGroup, and the result can - be other mode bits set.' + description: 'mode is Optional: mode bits + used to set permissions on this file. + Must be an octal value between 0000 and + 0777 or a decimal value between 0 and + 511. YAML accepts both octal and decimal + values, JSON requires decimal values for + mode bits. If not specified, the volume + defaultMode will be used. This might be + in conflict with other options that affect + the file mode, like fsGroup, and the result + can be other mode bits set.' format: int32 type: integer path: - description: The relative path of the file - to map the key to. May not be an absolute - path. May not contain the path element - '..'. May not start with the string '..'. + description: path is the relative path of + the file to map the key to. May not be + an absolute path. May not contain the + path element '..'. May not start with + the string '..'. type: string required: - key @@ -689,29 +697,29 @@ spec: uid?' type: string optional: - description: Specify whether the ConfigMap or - its keys must be defined + description: optional specify whether the ConfigMap + or its keys must be defined type: boolean type: object csi: - description: CSI (Container Storage Interface) represents + description: csi (Container Storage Interface) represents ephemeral storage that is handled by certain external CSI drivers (Beta feature). properties: driver: - description: Driver is the name of the CSI driver + description: driver is the name of the CSI driver that handles this volume. Consult with your admin for the correct name as registered in the cluster. type: string fsType: - description: Filesystem type to mount. Ex. "ext4", - "xfs", "ntfs". If not provided, the empty value - is passed to the associated CSI driver which - will determine the default filesystem to apply. + description: fsType to mount. Ex. "ext4", "xfs", + "ntfs". If not provided, the empty value is + passed to the associated CSI driver which will + determine the default filesystem to apply. type: string nodePublishSecretRef: - description: NodePublishSecretRef is a reference + description: nodePublishSecretRef is a reference to the secret object containing sensitive information to pass to the CSI driver to complete the CSI NodePublishVolume and NodeUnpublishVolume calls. @@ -728,13 +736,13 @@ spec: type: string type: object readOnly: - description: Specifies a read-only configuration + description: readOnly specifies a read-only configuration for the volume. Defaults to false (read/write). type: boolean volumeAttributes: additionalProperties: type: string - description: VolumeAttributes stores driver-specific + description: volumeAttributes stores driver-specific properties that are passed to the CSI driver. Consult your driver's documentation for supported values. @@ -743,7 +751,7 @@ spec: - driver type: object downwardAPI: - description: DownwardAPI represents downward API about + description: downwardAPI represents downward API about the pod that should populate this volume properties: defaultMode: @@ -840,33 +848,34 @@ spec: type: array type: object emptyDir: - description: 'EmptyDir represents a temporary directory + description: 'emptyDir represents a temporary directory that shares a pod''s lifetime. More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir' properties: medium: - description: 'What type of storage medium should - back this directory. The default is "" which - means to use the node''s default medium. Must - be an empty string (default) or Memory. More - info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir' + description: 'medium represents what type of storage + medium should back this directory. The default + is "" which means to use the node''s default + medium. Must be an empty string (default) or + Memory. More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir' type: string sizeLimit: anyOf: - type: integer - type: string - description: 'Total amount of local storage required - for this EmptyDir volume. The size limit is - also applicable for memory medium. The maximum - usage on memory medium EmptyDir would be the - minimum value between the SizeLimit specified - here and the sum of memory limits of all containers - in a pod. The default is nil which means that - the limit is undefined. More info: http://kubernetes.io/docs/user-guide/volumes#emptydir' + description: 'sizeLimit is the total amount of + local storage required for this EmptyDir volume. + The size limit is also applicable for memory + medium. The maximum usage on memory medium EmptyDir + would be the minimum value between the SizeLimit + specified here and the sum of memory limits + of all containers in a pod. The default is nil + which means that the limit is undefined. More + info: http://kubernetes.io/docs/user-guide/volumes#emptydir' pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true type: object ephemeral: - description: "Ephemeral represents a volume that is + description: "ephemeral represents a volume that is handled by a cluster storage driver. The volume's lifecycle is tied to the pod that defines it - it will be created before the pod starts, and deleted @@ -886,9 +895,7 @@ spec: to be used that way - see the documentation of the driver for more information. \n A pod can use both types of ephemeral volumes and persistent volumes - at the same time. \n This is a beta feature and - only available when the GenericEphemeralVolume feature - gate is enabled." + at the same time." properties: volumeClaimTemplate: description: "Will be used to create a stand-alone @@ -929,26 +936,76 @@ spec: are also valid here. properties: accessModes: - description: 'AccessModes contains the + description: 'accessModes contains the desired access modes the volume should have. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1' items: type: string type: array dataSource: - description: 'This field can be used to - specify either: * An existing VolumeSnapshot - object (snapshot.storage.k8s.io/VolumeSnapshot) + description: 'dataSource field can be + used to specify either: * An existing + VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) * An existing PVC (PersistentVolumeClaim) - * An existing custom resource that implements - data population (Alpha) In order to - use custom resource types that implement - data population, the AnyVolumeDataSource - feature gate must be enabled. If the - provisioner or an external controller + If the provisioner or an external controller can support the specified data source, it will create a new volume based on - the contents of the specified data source.' + the contents of the specified data source. + If the AnyVolumeDataSource feature gate + is enabled, this field will always have + the same contents as the DataSourceRef + field.' + properties: + apiGroup: + description: APIGroup is the group + for the resource being referenced. + If APIGroup is not specified, the + specified Kind must be in the core + API group. For any other third-party + types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource + being referenced + type: string + name: + description: Name is the name of resource + being referenced + type: string + required: + - kind + - name + type: object + dataSourceRef: + description: 'dataSourceRef specifies + the object from which to populate the + volume with data, if a non-empty volume + is desired. This may be any local object + from a non-empty API group (non core + object) or a PersistentVolumeClaim object. + When this field is specified, volume + binding will only succeed if the type + of the specified object matches some + installed volume populator or dynamic + provisioner. This field will replace + the functionality of the DataSource + field and as such if both fields are + non-empty, they must have the same value. + For backwards compatibility, both fields + (DataSource and DataSourceRef) will + be set to the same value automatically + if one of them is empty and the other + is non-empty. There are two important + differences between DataSource and DataSourceRef: + * While DataSource only allows two specific + types of objects, DataSourceRef allows + any non-core object, as well as PersistentVolumeClaim + objects. * While DataSource ignores + disallowed values (dropping them), DataSourceRef preserves + all values, and generates an error if + a disallowed value is specified. (Beta) + Using this field requires the AnyVolumeDataSource + feature gate to be enabled.' properties: apiGroup: description: APIGroup is the group @@ -971,9 +1028,15 @@ spec: - name type: object resources: - description: 'Resources represents the + description: 'resources represents the minimum resources the volume should - have. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources' + have. If RecoverVolumeExpansionFailure + feature is enabled users are allowed + to specify resource requirements that + are lower than previous value but must + still be higher than capacity recorded + in the status field of the claim. More + info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources' properties: limits: additionalProperties: @@ -1003,8 +1066,8 @@ spec: type: object type: object selector: - description: A label query over volumes - to consider for binding. + description: selector is a label query + over volumes to consider for binding. properties: matchExpressions: description: matchExpressions is a @@ -1060,8 +1123,9 @@ spec: type: object type: object storageClassName: - description: 'Name of the StorageClass - required by the claim. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1' + description: 'storageClassName is the + name of the StorageClass required by + the claim. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1' type: string volumeMode: description: volumeMode defines what type @@ -1070,7 +1134,7 @@ spec: not included in claim spec. type: string volumeName: - description: VolumeName is the binding + description: volumeName is the binding reference to the PersistentVolume backing this claim. type: string @@ -1080,74 +1144,77 @@ spec: type: object type: object fc: - description: FC represents a Fibre Channel resource + description: fc represents a Fibre Channel resource that is attached to a kubelet's host machine and then exposed to the pod. properties: fsType: - description: 'Filesystem type to mount. Must be - a filesystem type supported by the host operating - system. Ex. "ext4", "xfs", "ntfs". Implicitly - inferred to be "ext4" if unspecified. TODO: - how do we prevent errors in the filesystem from - compromising the machine' + description: 'fsType is the filesystem type to + mount. Must be a filesystem type supported by + the host operating system. Ex. "ext4", "xfs", + "ntfs". Implicitly inferred to be "ext4" if + unspecified. TODO: how do we prevent errors + in the filesystem from compromising the machine' type: string lun: - description: 'Optional: FC target lun number' + description: 'lun is Optional: FC target lun number' format: int32 type: integer readOnly: - description: 'Optional: Defaults to false (read/write). - ReadOnly here will force the ReadOnly setting - in VolumeMounts.' + description: 'readOnly is Optional: Defaults to + false (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts.' type: boolean targetWWNs: - description: 'Optional: FC target worldwide names - (WWNs)' + description: 'targetWWNs is Optional: FC target + worldwide names (WWNs)' items: type: string type: array wwids: - description: 'Optional: FC volume world wide identifiers - (wwids) Either wwids or combination of targetWWNs - and lun must be set, but not both simultaneously.' + description: 'wwids Optional: FC volume world + wide identifiers (wwids) Either wwids or combination + of targetWWNs and lun must be set, but not both + simultaneously.' items: type: string type: array type: object flexVolume: - description: FlexVolume represents a generic volume + description: flexVolume represents a generic volume resource that is provisioned/attached using an exec based plugin. properties: driver: - description: Driver is the name of the driver + description: driver is the name of the driver to use for this volume. type: string fsType: - description: Filesystem type to mount. Must be - a filesystem type supported by the host operating - system. Ex. "ext4", "xfs", "ntfs". The default - filesystem depends on FlexVolume script. + description: fsType is the filesystem type to + mount. Must be a filesystem type supported by + the host operating system. Ex. "ext4", "xfs", + "ntfs". The default filesystem depends on FlexVolume + script. type: string options: additionalProperties: type: string - description: 'Optional: Extra command options - if any.' + description: 'options is Optional: this field + holds extra command options if any.' type: object readOnly: - description: 'Optional: Defaults to false (read/write). - ReadOnly here will force the ReadOnly setting - in VolumeMounts.' + description: 'readOnly is Optional: defaults to + false (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts.' type: boolean secretRef: - description: 'Optional: SecretRef is reference - to the secret object containing sensitive information - to pass to the plugin scripts. This may be empty - if no secret object is specified. If the secret - object contains more than one secret, all secrets - are passed to the plugin scripts.' + description: 'secretRef is Optional: secretRef + is reference to the secret object containing + sensitive information to pass to the plugin + scripts. This may be empty if no secret object + is specified. If the secret object contains + more than one secret, all secrets are passed + to the plugin scripts.' properties: name: description: 'Name of the referent. More info: @@ -1160,52 +1227,52 @@ spec: - driver type: object flocker: - description: Flocker represents a Flocker volume attached + description: flocker represents a Flocker volume attached to a kubelet's host machine. This depends on the Flocker control service being running properties: datasetName: - description: Name of the dataset stored as metadata - -> name on the dataset for Flocker should be - considered as deprecated + description: datasetName is Name of the dataset + stored as metadata -> name on the dataset for + Flocker should be considered as deprecated type: string datasetUUID: - description: UUID of the dataset. This is unique - identifier of a Flocker dataset + description: datasetUUID is the UUID of the dataset. + This is unique identifier of a Flocker dataset type: string type: object gcePersistentDisk: - description: 'GCEPersistentDisk represents a GCE Disk + description: 'gcePersistentDisk represents a GCE Disk resource that is attached to a kubelet''s host machine and then exposed to the pod. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' properties: fsType: - description: 'Filesystem type of the volume that - you want to mount. Tip: Ensure that the filesystem - type is supported by the host operating system. - Examples: "ext4", "xfs", "ntfs". Implicitly - inferred to be "ext4" if unspecified. More info: - https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk + description: 'fsType is filesystem type of the + volume that you want to mount. Tip: Ensure that + the filesystem type is supported by the host + operating system. Examples: "ext4", "xfs", "ntfs". + Implicitly inferred to be "ext4" if unspecified. + More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk TODO: how do we prevent errors in the filesystem from compromising the machine' type: string partition: - description: 'The partition in the volume that - you want to mount. If omitted, the default is - to mount by volume name. Examples: For volume - /dev/sda1, you specify the partition as "1". - Similarly, the volume partition for /dev/sda - is "0" (or you can leave the property empty). - More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + description: 'partition is the partition in the + volume that you want to mount. If omitted, the + default is to mount by volume name. Examples: + For volume /dev/sda1, you specify the partition + as "1". Similarly, the volume partition for + /dev/sda is "0" (or you can leave the property + empty). More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' format: int32 type: integer pdName: - description: 'Unique name of the PD resource in - GCE. Used to identify the disk in GCE. More - info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + description: 'pdName is unique name of the PD + resource in GCE. Used to identify the disk in + GCE. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' type: string readOnly: - description: 'ReadOnly here will force the ReadOnly + description: 'readOnly here will force the ReadOnly setting in VolumeMounts. Defaults to false. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' type: boolean @@ -1213,7 +1280,7 @@ spec: - pdName type: object gitRepo: - description: 'GitRepo represents a git repository + description: 'gitRepo represents a git repository at a particular revision. DEPRECATED: GitRepo is deprecated. To provision a container with a git repo, mount an EmptyDir into an InitContainer that @@ -1221,38 +1288,38 @@ spec: into the Pod''s container.' properties: directory: - description: Target directory name. Must not contain - or start with '..'. If '.' is supplied, the - volume directory will be the git repository. Otherwise, - if specified, the volume will contain the git - repository in the subdirectory with the given - name. + description: directory is the target directory + name. Must not contain or start with '..'. If + '.' is supplied, the volume directory will be + the git repository. Otherwise, if specified, + the volume will contain the git repository in + the subdirectory with the given name. type: string repository: - description: Repository URL + description: repository is the URL type: string revision: - description: Commit hash for the specified revision. + description: revision is the commit hash for the + specified revision. type: string required: - repository type: object glusterfs: - description: 'Glusterfs represents a Glusterfs mount + description: 'glusterfs represents a Glusterfs mount on the host that shares a pod''s lifetime. More info: https://examples.k8s.io/volumes/glusterfs/README.md' properties: endpoints: - description: 'EndpointsName is the endpoint name - that details Glusterfs topology. More info: - https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod' + description: 'endpoints is the endpoint name that + details Glusterfs topology. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod' type: string path: - description: 'Path is the Glusterfs volume path. + description: 'path is the Glusterfs volume path. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod' type: string readOnly: - description: 'ReadOnly here will force the Glusterfs + description: 'readOnly here will force the Glusterfs volume to be mounted with read-only permissions. Defaults to false. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod' type: boolean @@ -1261,7 +1328,7 @@ spec: - path type: object hostPath: - description: 'HostPath represents a pre-existing file + description: 'hostPath represents a pre-existing file or directory on the host machine that is directly exposed to the container. This is generally used for system agents or other privileged things that @@ -1272,72 +1339,75 @@ spec: host directories as read/write.' properties: path: - description: 'Path of the directory on the host. + description: 'path of the directory on the host. If the path is a symlink, it will follow the link to the real path. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath' type: string type: - description: 'Type for HostPath Volume Defaults + description: 'type for HostPath Volume Defaults to "" More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath' type: string required: - path type: object iscsi: - description: 'ISCSI represents an ISCSI Disk resource + description: 'iscsi represents an ISCSI Disk resource that is attached to a kubelet''s host machine and then exposed to the pod. More info: https://examples.k8s.io/volumes/iscsi/README.md' properties: chapAuthDiscovery: - description: whether support iSCSI Discovery CHAP - authentication + description: chapAuthDiscovery defines whether + support iSCSI Discovery CHAP authentication type: boolean chapAuthSession: - description: whether support iSCSI Session CHAP - authentication + description: chapAuthSession defines whether support + iSCSI Session CHAP authentication type: boolean fsType: - description: 'Filesystem type of the volume that - you want to mount. Tip: Ensure that the filesystem - type is supported by the host operating system. - Examples: "ext4", "xfs", "ntfs". Implicitly - inferred to be "ext4" if unspecified. More info: - https://kubernetes.io/docs/concepts/storage/volumes#iscsi + description: 'fsType is the filesystem type of + the volume that you want to mount. Tip: Ensure + that the filesystem type is supported by the + host operating system. Examples: "ext4", "xfs", + "ntfs". Implicitly inferred to be "ext4" if + unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#iscsi TODO: how do we prevent errors in the filesystem from compromising the machine' type: string initiatorName: - description: Custom iSCSI Initiator Name. If initiatorName - is specified with iscsiInterface simultaneously, - new iSCSI interface : will be created for the connection. + description: initiatorName is the custom iSCSI + Initiator Name. If initiatorName is specified + with iscsiInterface simultaneously, new iSCSI + interface : will + be created for the connection. type: string iqn: - description: Target iSCSI Qualified Name. + description: iqn is the target iSCSI Qualified + Name. type: string iscsiInterface: - description: iSCSI Interface Name that uses an - iSCSI transport. Defaults to 'default' (tcp). + description: iscsiInterface is the interface Name + that uses an iSCSI transport. Defaults to 'default' + (tcp). type: string lun: - description: iSCSI Target Lun number. + description: lun represents iSCSI Target Lun number. format: int32 type: integer portals: - description: iSCSI Target Portal List. The portal - is either an IP or ip_addr:port if the port - is other than default (typically TCP ports 860 - and 3260). + description: portals is the iSCSI Target Portal + List. The portal is either an IP or ip_addr:port + if the port is other than default (typically + TCP ports 860 and 3260). items: type: string type: array readOnly: - description: ReadOnly here will force the ReadOnly + description: readOnly here will force the ReadOnly setting in VolumeMounts. Defaults to false. type: boolean secretRef: - description: CHAP Secret for iSCSI target and - initiator authentication + description: secretRef is the CHAP Secret for + iSCSI target and initiator authentication properties: name: description: 'Name of the referent. More info: @@ -1347,10 +1417,10 @@ spec: type: string type: object targetPortal: - description: iSCSI Target Portal. The Portal is - either an IP or ip_addr:port if the port is - other than default (typically TCP ports 860 - and 3260). + description: targetPortal is iSCSI Target Portal. + The Portal is either an IP or ip_addr:port if + the port is other than default (typically TCP + ports 860 and 3260). type: string required: - iqn @@ -1358,24 +1428,24 @@ spec: - targetPortal type: object name: - description: 'Volume''s name. Must be a DNS_LABEL + description: 'name of the volume. Must be a DNS_LABEL and unique within the pod. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' type: string nfs: - description: 'NFS represents an NFS mount on the host + description: 'nfs represents an NFS mount on the host that shares a pod''s lifetime More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' properties: path: - description: 'Path that is exported by the NFS + description: 'path that is exported by the NFS server. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' type: string readOnly: - description: 'ReadOnly here will force the NFS + description: 'readOnly here will force the NFS export to be mounted with read-only permissions. Defaults to false. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' type: boolean server: - description: 'Server is the hostname or IP address + description: 'server is the hostname or IP address of the NFS server. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' type: string required: @@ -1383,134 +1453,138 @@ spec: - server type: object persistentVolumeClaim: - description: 'PersistentVolumeClaimVolumeSource represents + description: 'persistentVolumeClaimVolumeSource represents a reference to a PersistentVolumeClaim in the same namespace. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims' properties: claimName: - description: 'ClaimName is the name of a PersistentVolumeClaim + description: 'claimName is the name of a PersistentVolumeClaim in the same namespace as the pod using this volume. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims' type: string readOnly: - description: Will force the ReadOnly setting in - VolumeMounts. Default false. + description: readOnly Will force the ReadOnly + setting in VolumeMounts. Default false. type: boolean required: - claimName type: object photonPersistentDisk: - description: PhotonPersistentDisk represents a PhotonController + description: photonPersistentDisk represents a PhotonController persistent disk attached and mounted on kubelets host machine properties: fsType: - description: Filesystem type to mount. Must be - a filesystem type supported by the host operating - system. Ex. "ext4", "xfs", "ntfs". Implicitly - inferred to be "ext4" if unspecified. + description: fsType is the filesystem type to + mount. Must be a filesystem type supported by + the host operating system. Ex. "ext4", "xfs", + "ntfs". Implicitly inferred to be "ext4" if + unspecified. type: string pdID: - description: ID that identifies Photon Controller - persistent disk + description: pdID is the ID that identifies Photon + Controller persistent disk type: string required: - pdID type: object portworxVolume: - description: PortworxVolume represents a portworx + description: portworxVolume represents a portworx volume attached and mounted on kubelets host machine properties: fsType: - description: FSType represents the filesystem + description: fSType represents the filesystem type to mount Must be a filesystem type supported by the host operating system. Ex. "ext4", "xfs". Implicitly inferred to be "ext4" if unspecified. type: string readOnly: - description: Defaults to false (read/write). ReadOnly - here will force the ReadOnly setting in VolumeMounts. + description: readOnly defaults to false (read/write). + ReadOnly here will force the ReadOnly setting + in VolumeMounts. type: boolean volumeID: - description: VolumeID uniquely identifies a Portworx + description: volumeID uniquely identifies a Portworx volume type: string required: - volumeID type: object projected: - description: Items for all in one resources secrets, - configmaps, and downward API + description: projected items for all in one resources + secrets, configmaps, and downward API properties: defaultMode: - description: Mode bits used to set permissions - on created files by default. Must be an octal - value between 0000 and 0777 or a decimal value - between 0 and 511. YAML accepts both octal and - decimal values, JSON requires decimal values - for mode bits. Directories within the path are - not affected by this setting. This might be - in conflict with other options that affect the - file mode, like fsGroup, and the result can - be other mode bits set. + description: defaultMode are the mode bits used + to set permissions on created files by default. + Must be an octal value between 0000 and 0777 + or a decimal value between 0 and 511. YAML accepts + both octal and decimal values, JSON requires + decimal values for mode bits. Directories within + the path are not affected by this setting. This + might be in conflict with other options that + affect the file mode, like fsGroup, and the + result can be other mode bits set. format: int32 type: integer sources: - description: list of volume projections + description: sources is the list of volume projections items: description: Projection that may be projected along with other supported volume types properties: configMap: - description: information about the configMap - data to project + description: configMap information about + the configMap data to project properties: items: - description: If unspecified, each key-value - pair in the Data field of the referenced - ConfigMap will be projected into the - volume as a file whose name is the - key and content is the value. If specified, - the listed keys will be projected - into the specified paths, and unlisted - keys will not be present. If a key - is specified which is not present - in the ConfigMap, the volume setup - will error unless it is marked optional. - Paths must be relative and may not - contain the '..' path or start with - '..'. + description: items if unspecified, each + key-value pair in the Data field of + the referenced ConfigMap will be projected + into the volume as a file whose name + is the key and content is the value. + If specified, the listed keys will + be projected into the specified paths, + and unlisted keys will not be present. + If a key is specified which is not + present in the ConfigMap, the volume + setup will error unless it is marked + optional. Paths must be relative and + may not contain the '..' path or start + with '..'. items: description: Maps a string key to a path within a volume. properties: key: - description: The key to project. + description: key is the key to + project. type: string mode: - description: 'Optional: mode bits - used to set permissions on this - file. Must be an octal value - between 0000 and 0777 or a decimal - value between 0 and 511. YAML - accepts both octal and decimal - values, JSON requires decimal - values for mode bits. If not - specified, the volume defaultMode - will be used. This might be - in conflict with other options - that affect the file mode, like - fsGroup, and the result can - be other mode bits set.' + description: 'mode is Optional: + mode bits used to set permissions + on this file. Must be an octal + value between 0000 and 0777 + or a decimal value between 0 + and 511. YAML accepts both octal + and decimal values, JSON requires + decimal values for mode bits. + If not specified, the volume + defaultMode will be used. This + might be in conflict with other + options that affect the file + mode, like fsGroup, and the + result can be other mode bits + set.' format: int32 type: integer path: - description: The relative path - of the file to map the key to. - May not be an absolute path. - May not contain the path element - '..'. May not start with the - string '..'. + description: path is the relative + path of the file to map the + key to. May not be an absolute + path. May not contain the path + element '..'. May not start + with the string '..'. type: string required: - key @@ -1524,13 +1598,14 @@ spec: kind, uid?' type: string optional: - description: Specify whether the ConfigMap - or its keys must be defined + description: optional specify whether + the ConfigMap or its keys must be + defined type: boolean type: object downwardAPI: - description: information about the downwardAPI - data to project + description: downwardAPI information about + the downwardAPI data to project properties: items: description: Items is a list of DownwardAPIVolume @@ -1621,55 +1696,57 @@ spec: type: array type: object secret: - description: information about the secret - data to project + description: secret information about the + secret data to project properties: items: - description: If unspecified, each key-value - pair in the Data field of the referenced - Secret will be projected into the - volume as a file whose name is the - key and content is the value. If specified, - the listed keys will be projected - into the specified paths, and unlisted - keys will not be present. If a key - is specified which is not present - in the Secret, the volume setup will - error unless it is marked optional. - Paths must be relative and may not - contain the '..' path or start with - '..'. + description: items if unspecified, each + key-value pair in the Data field of + the referenced Secret will be projected + into the volume as a file whose name + is the key and content is the value. + If specified, the listed keys will + be projected into the specified paths, + and unlisted keys will not be present. + If a key is specified which is not + present in the Secret, the volume + setup will error unless it is marked + optional. Paths must be relative and + may not contain the '..' path or start + with '..'. items: description: Maps a string key to a path within a volume. properties: key: - description: The key to project. + description: key is the key to + project. type: string mode: - description: 'Optional: mode bits - used to set permissions on this - file. Must be an octal value - between 0000 and 0777 or a decimal - value between 0 and 511. YAML - accepts both octal and decimal - values, JSON requires decimal - values for mode bits. If not - specified, the volume defaultMode - will be used. This might be - in conflict with other options - that affect the file mode, like - fsGroup, and the result can - be other mode bits set.' + description: 'mode is Optional: + mode bits used to set permissions + on this file. Must be an octal + value between 0000 and 0777 + or a decimal value between 0 + and 511. YAML accepts both octal + and decimal values, JSON requires + decimal values for mode bits. + If not specified, the volume + defaultMode will be used. This + might be in conflict with other + options that affect the file + mode, like fsGroup, and the + result can be other mode bits + set.' format: int32 type: integer path: - description: The relative path - of the file to map the key to. - May not be an absolute path. - May not contain the path element - '..'. May not start with the - string '..'. + description: path is the relative + path of the file to map the + key to. May not be an absolute + path. May not contain the path + element '..'. May not start + with the string '..'. type: string required: - key @@ -1683,16 +1760,18 @@ spec: kind, uid?' type: string optional: - description: Specify whether the Secret - or its key must be defined + description: optional field specify + whether the Secret or its key must + be defined type: boolean type: object serviceAccountToken: - description: information about the serviceAccountToken - data to project + description: serviceAccountToken is information + about the serviceAccountToken data to + project properties: audience: - description: Audience is the intended + description: audience is the intended audience of the token. A recipient of a token must identify itself with an identifier specified in the audience @@ -1701,7 +1780,7 @@ spec: to the identifier of the apiserver. type: string expirationSeconds: - description: ExpirationSeconds is the + description: expirationSeconds is the requested duration of validity of the service account token. As the token approaches expiration, the kubelet @@ -1715,7 +1794,7 @@ spec: format: int64 type: integer path: - description: Path is the path relative + description: path is the path relative to the mount point of the file to project the token into. type: string @@ -1726,36 +1805,36 @@ spec: type: array type: object quobyte: - description: Quobyte represents a Quobyte mount on + description: quobyte represents a Quobyte mount on the host that shares a pod's lifetime properties: group: - description: Group to map volume access to Default + description: group to map volume access to Default is no group type: string readOnly: - description: ReadOnly here will force the Quobyte + description: readOnly here will force the Quobyte volume to be mounted with read-only permissions. Defaults to false. type: boolean registry: - description: Registry represents a single or multiple + description: registry represents a single or multiple Quobyte Registry services specified as a string as host:port pair (multiple entries are separated with commas) which acts as the central registry for volumes type: string tenant: - description: Tenant owning the given Quobyte volume + description: tenant owning the given Quobyte volume in the Backend Used with dynamically provisioned Quobyte volumes, value is set by the plugin type: string user: - description: User to map volume access to Defaults + description: user to map volume access to Defaults to serivceaccount user type: string volume: - description: Volume is a string that references + description: volume is a string that references an already created Quobyte volume by name. type: string required: @@ -1763,46 +1842,46 @@ spec: - volume type: object rbd: - description: 'RBD represents a Rados Block Device + description: 'rbd represents a Rados Block Device mount on the host that shares a pod''s lifetime. More info: https://examples.k8s.io/volumes/rbd/README.md' properties: fsType: - description: 'Filesystem type of the volume that - you want to mount. Tip: Ensure that the filesystem - type is supported by the host operating system. - Examples: "ext4", "xfs", "ntfs". Implicitly - inferred to be "ext4" if unspecified. More info: - https://kubernetes.io/docs/concepts/storage/volumes#rbd + description: 'fsType is the filesystem type of + the volume that you want to mount. Tip: Ensure + that the filesystem type is supported by the + host operating system. Examples: "ext4", "xfs", + "ntfs". Implicitly inferred to be "ext4" if + unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#rbd TODO: how do we prevent errors in the filesystem from compromising the machine' type: string image: - description: 'The rados image name. More info: - https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + description: 'image is the rados image name. More + info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' type: string keyring: - description: 'Keyring is the path to key ring + description: 'keyring is the path to key ring for RBDUser. Default is /etc/ceph/keyring. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' type: string monitors: - description: 'A collection of Ceph monitors. More - info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + description: 'monitors is a collection of Ceph + monitors. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' items: type: string type: array pool: - description: 'The rados pool name. Default is - rbd. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + description: 'pool is the rados pool name. Default + is rbd. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' type: string readOnly: - description: 'ReadOnly here will force the ReadOnly + description: 'readOnly here will force the ReadOnly setting in VolumeMounts. Defaults to false. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' type: boolean secretRef: - description: 'SecretRef is name of the authentication + description: 'secretRef is name of the authentication secret for RBDUser. If provided overrides keyring. Default is nil. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' properties: @@ -1814,37 +1893,39 @@ spec: type: string type: object user: - description: 'The rados user name. Default is - admin. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + description: 'user is the rados user name. Default + is admin. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' type: string required: - image - monitors type: object scaleIO: - description: ScaleIO represents a ScaleIO persistent + description: scaleIO represents a ScaleIO persistent volume attached and mounted on Kubernetes nodes. properties: fsType: - description: Filesystem type to mount. Must be - a filesystem type supported by the host operating - system. Ex. "ext4", "xfs", "ntfs". Default is - "xfs". + description: fsType is the filesystem type to + mount. Must be a filesystem type supported by + the host operating system. Ex. "ext4", "xfs", + "ntfs". Default is "xfs". type: string gateway: - description: The host address of the ScaleIO API - Gateway. + description: gateway is the host address of the + ScaleIO API Gateway. type: string protectionDomain: - description: The name of the ScaleIO Protection - Domain for the configured storage. + description: protectionDomain is the name of the + ScaleIO Protection Domain for the configured + storage. type: string readOnly: - description: Defaults to false (read/write). ReadOnly - here will force the ReadOnly setting in VolumeMounts. + description: readOnly Defaults to false (read/write). + ReadOnly here will force the ReadOnly setting + in VolumeMounts. type: boolean secretRef: - description: SecretRef references to the secret + description: secretRef references to the secret for ScaleIO user and other sensitive information. If this is not provided, Login operation will fail. @@ -1857,26 +1938,26 @@ spec: type: string type: object sslEnabled: - description: Flag to enable/disable SSL communication - with Gateway, default false + description: sslEnabled Flag enable/disable SSL + communication with Gateway, default false type: boolean storageMode: - description: Indicates whether the storage for - a volume should be ThickProvisioned or ThinProvisioned. - Default is ThinProvisioned. + description: storageMode indicates whether the + storage for a volume should be ThickProvisioned + or ThinProvisioned. Default is ThinProvisioned. type: string storagePool: - description: The ScaleIO Storage Pool associated - with the protection domain. + description: storagePool is the ScaleIO Storage + Pool associated with the protection domain. type: string system: - description: The name of the storage system as - configured in ScaleIO. + description: system is the name of the storage + system as configured in ScaleIO. type: string volumeName: - description: The name of a volume already created - in the ScaleIO system that is associated with - this volume source. + description: volumeName is the name of a volume + already created in the ScaleIO system that is + associated with this volume source. type: string required: - gateway @@ -1884,29 +1965,29 @@ spec: - system type: object secret: - description: 'Secret represents a secret that should + description: 'secret represents a secret that should populate this volume. More info: https://kubernetes.io/docs/concepts/storage/volumes#secret' properties: defaultMode: - description: 'Optional: mode bits used to set - permissions on created files by default. Must - be an octal value between 0000 and 0777 or a - decimal value between 0 and 511. YAML accepts - both octal and decimal values, JSON requires - decimal values for mode bits. Defaults to 0644. - Directories within the path are not affected - by this setting. This might be in conflict with - other options that affect the file mode, like - fsGroup, and the result can be other mode bits - set.' + description: 'defaultMode is Optional: mode bits + used to set permissions on created files by + default. Must be an octal value between 0000 + and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, + JSON requires decimal values for mode bits. + Defaults to 0644. Directories within the path + are not affected by this setting. This might + be in conflict with other options that affect + the file mode, like fsGroup, and the result + can be other mode bits set.' format: int32 type: integer items: - description: If unspecified, each key-value pair - in the Data field of the referenced Secret will - be projected into the volume as a file whose - name is the key and content is the value. If - specified, the listed keys will be projected + description: items If unspecified, each key-value + pair in the Data field of the referenced Secret + will be projected into the volume as a file + whose name is the key and content is the value. + If specified, the listed keys will be projected into the specified paths, and unlisted keys will not be present. If a key is specified which is not present in the Secret, the volume setup @@ -1918,27 +1999,28 @@ spec: a volume. properties: key: - description: The key to project. + description: key is the key to project. type: string mode: - description: 'Optional: mode bits used to - set permissions on this file. Must be - an octal value between 0000 and 0777 or - a decimal value between 0 and 511. YAML - accepts both octal and decimal values, - JSON requires decimal values for mode - bits. If not specified, the volume defaultMode - will be used. This might be in conflict - with other options that affect the file - mode, like fsGroup, and the result can - be other mode bits set.' + description: 'mode is Optional: mode bits + used to set permissions on this file. + Must be an octal value between 0000 and + 0777 or a decimal value between 0 and + 511. YAML accepts both octal and decimal + values, JSON requires decimal values for + mode bits. If not specified, the volume + defaultMode will be used. This might be + in conflict with other options that affect + the file mode, like fsGroup, and the result + can be other mode bits set.' format: int32 type: integer path: - description: The relative path of the file - to map the key to. May not be an absolute - path. May not contain the path element - '..'. May not start with the string '..'. + description: path is the relative path of + the file to map the key to. May not be + an absolute path. May not contain the + path element '..'. May not start with + the string '..'. type: string required: - key @@ -1946,30 +2028,32 @@ spec: type: object type: array optional: - description: Specify whether the Secret or its - keys must be defined + description: optional field specify whether the + Secret or its keys must be defined type: boolean secretName: - description: 'Name of the secret in the pod''s - namespace to use. More info: https://kubernetes.io/docs/concepts/storage/volumes#secret' + description: 'secretName is the name of the secret + in the pod''s namespace to use. More info: https://kubernetes.io/docs/concepts/storage/volumes#secret' type: string type: object storageos: - description: StorageOS represents a StorageOS volume + description: storageOS represents a StorageOS volume attached and mounted on Kubernetes nodes. properties: fsType: - description: Filesystem type to mount. Must be - a filesystem type supported by the host operating - system. Ex. "ext4", "xfs", "ntfs". Implicitly - inferred to be "ext4" if unspecified. + description: fsType is the filesystem type to + mount. Must be a filesystem type supported by + the host operating system. Ex. "ext4", "xfs", + "ntfs". Implicitly inferred to be "ext4" if + unspecified. type: string readOnly: - description: Defaults to false (read/write). ReadOnly - here will force the ReadOnly setting in VolumeMounts. + description: readOnly defaults to false (read/write). + ReadOnly here will force the ReadOnly setting + in VolumeMounts. type: boolean secretRef: - description: SecretRef specifies the secret to + description: secretRef specifies the secret to use for obtaining the StorageOS API credentials. If not specified, default values will be attempted. properties: @@ -1981,12 +2065,12 @@ spec: type: string type: object volumeName: - description: VolumeName is the human-readable + description: volumeName is the human-readable name of the StorageOS volume. Volume names are only unique within a namespace. type: string volumeNamespace: - description: VolumeNamespace specifies the scope + description: volumeNamespace specifies the scope of the volume within StorageOS. If no namespace is specified then the Pod's namespace will be used. This allows the Kubernetes name scoping @@ -1999,26 +2083,27 @@ spec: type: string type: object vsphereVolume: - description: VsphereVolume represents a vSphere volume + description: vsphereVolume represents a vSphere volume attached and mounted on kubelets host machine properties: fsType: - description: Filesystem type to mount. Must be - a filesystem type supported by the host operating - system. Ex. "ext4", "xfs", "ntfs". Implicitly - inferred to be "ext4" if unspecified. + description: fsType is filesystem type to mount. + Must be a filesystem type supported by the host + operating system. Ex. "ext4", "xfs", "ntfs". + Implicitly inferred to be "ext4" if unspecified. type: string storagePolicyID: - description: Storage Policy Based Management (SPBM) - profile ID associated with the StoragePolicyName. + description: storagePolicyID is the storage Policy + Based Management (SPBM) profile ID associated + with the StoragePolicyName. type: string storagePolicyName: - description: Storage Policy Based Management (SPBM) - profile name. + description: storagePolicyName is the storage + Policy Based Management (SPBM) profile name. type: string volumePath: - description: Path that identifies vSphere volume - vmdk + description: volumePath is the path that identifies + vSphere volume vmdk type: string required: - volumePath diff --git a/bundle/manifests/operator.ibm.com_operandrequests.yaml b/bundle/manifests/operator.ibm.com_operandrequests.yaml index f50a7623..86bedad2 100644 --- a/bundle/manifests/operator.ibm.com_operandrequests.yaml +++ b/bundle/manifests/operator.ibm.com_operandrequests.yaml @@ -218,30 +218,25 @@ spec: description: Phase is the cluster running phase. type: string services: - description: Status for each of the services and their dependent resources specified in this request - type: array + description: Services reflect the status of operands beyond whether + they have been created items: - type: object properties: namespace: type: string operatorName: type: string resources: - description: Status of CRs created by ODLM that belong to a given service. This info comes from CRs like IM's Authentication and is populated by ODLM. - type: array + description: LastUpdateTime string `json:"lastTransitionTime,omitempty"` items: - type: object properties: apiVersion: type: string kind: type: string managedResources: - description: Status of resources that fall under the umbrella of the CR in the level above. - type: array + description: Message string `json:"message,omitempty"` items: - type: object properties: apiVersion: type: string @@ -252,15 +247,23 @@ spec: objectName: type: string status: + description: Type string `json:"type,omitempty"` type: string + type: object + type: array namespace: type: string objectName: type: string status: type: string + type: object + type: array status: + description: Type string `json:"type,omitempty"` type: string + type: object + type: array type: object x-kubernetes-preserve-unknown-fields: true type: object diff --git a/common/Makefile.common.mk b/common/Makefile.common.mk index 4b896678..5ea7edab 100644 --- a/common/Makefile.common.mk +++ b/common/Makefile.common.mk @@ -21,7 +21,7 @@ PROJECT ?= oceanic-guard-191815 ZONE ?= us-east5-c CLUSTER ?= bedrock-prow -NAMESPACESCOPE_VERSION = 1.1.1 +NAMESPACESCOPE_VERSION = 1.17.3 OLM_API_VERSION = 0.3.8 activate-serviceaccount: @@ -71,14 +71,14 @@ fetch-test-crds: rm -rf api-${OLM_API_VERSION} v${OLM_API_VERSION}.tar.gz ;\ } @{ \ - curl -L -O "https://github.com/horis233/jenkins-operator/archive/v0.3.3.tar.gz" ;\ - tar -zxf v0.3.3.tar.gz jenkins-operator-0.3.3/deploy/crds && mv jenkins-operator-0.3.3/deploy/crds/jenkins_v1alpha2_jenkins_crd.yaml ${ENVCRDS_DIR}/jenkins_v1alpha2_jenkins_crd.yaml ;\ - rm -rf jenkins-operator-0.3.3 v0.3.3.tar.gz ;\ + curl -L -O "https://github.com/mongodb/mongodb-atlas-kubernetes/archive/refs/tags/v1.7.3.tar.gz" ;\ + tar -zxf v1.7.3.tar.gz mongodb-atlas-kubernetes-1.7.3/deploy/crds && mv mongodb-atlas-kubernetes-1.7.3/deploy/crds/* ${ENVCRDS_DIR} ;\ + rm -rf mongodb-atlas-kubernetes-1.7.3 v1.7.3.tar.gz ;\ } @{ \ - curl -L -O "https://github.com/horis233/etcd-operator/archive/v0.9.4-crd.tar.gz" ;\ - tar -zxf v0.9.4-crd.tar.gz etcd-operator-0.9.4-crd/deploy/crds && mv etcd-operator-0.9.4-crd/deploy/crds/etcdclusters.etcd.database.coreos.com.crd.yaml ${ENVCRDS_DIR}/etcdclusters.etcd.database.coreos.com.crd.yaml ;\ - rm -rf etcd-operator-0.9.4-crd v0.9.4-crd.tar.gz ;\ + curl -L -O "https://github.com/jaegertracing/jaeger-operator/archive/refs/tags/v1.36.0.tar.gz" ;\ + tar -zxf v1.36.0.tar.gz jaeger-operator-1.36.0/bundle/manifests && mv jaeger-operator-1.36.0/bundle/manifests/jaegertracing.io_jaegers.yaml ${ENVCRDS_DIR}/jaegertracing.io_jaegers.yaml ;\ + rm -rf jaeger-operator-1.36.0 v1.36.0.tar.gz ;\ } @{ \ curl -L -O "https://github.com/IBM/ibm-namespace-scope-operator/archive/v${NAMESPACESCOPE_VERSION}.tar.gz" ;\ @@ -97,7 +97,7 @@ kustomize: ## Download kustomize locally if necessary. KIND ?= $(shell pwd)/common/bin/kind kind: ## Download kind locally if necessary. - $(call go-get-tool,$(KIND),sigs.k8s.io/kind@v0.10.0) + $(call go-get-tool,$(KIND),sigs.k8s.io/kind@v0.17.0) ENVTEST = $(shell pwd)/common/bin/setup-envtest setup-envtest: ## Download envtest-setup locally if necessary. diff --git a/common/scripts/install-olm.sh b/common/scripts/install-olm.sh index 52f831fb..f5ccb3f0 100755 --- a/common/scripts/install-olm.sh +++ b/common/scripts/install-olm.sh @@ -19,31 +19,49 @@ set -e -if [[ ${#@} -ne 1 ]]; then - echo "Usage: $0 version" +default_base_url=https://github.com/operator-framework/operator-lifecycle-manager/releases/download + +if [[ ${#@} -lt 1 || ${#@} -gt 2 ]]; then + echo "Usage: $0 version [base_url]" echo "* version: the github release version" + echo "* base_url: the github base URL (Default: $default_base_url)" + exit 1 +fi + +if kubectl get deployment olm-operator -n openshift-operator-lifecycle-manager > /dev/null 2>&1; then + echo "OLM is already installed in a different configuration. This is common if you are not running a vanilla Kubernetes cluster. Exiting..." exit 1 fi -release=$1 -url=https://github.com/operator-framework/operator-lifecycle-manager/releases/download/${release} +release="$1" +base_url="${2:-${default_base_url}}" +url="${base_url}/${release}" namespace=olm -kubectl apply -f ${url}/crds.yaml -kubectl apply -f ${url}/olm.yaml +if kubectl get deployment olm-operator -n ${namespace} > /dev/null 2>&1; then + echo "OLM is already installed in ${namespace} namespace. Exiting..." + exit 1 +fi + +kubectl create -f "${url}/crds.yaml" +kubectl wait --for=condition=Established -f "${url}/crds.yaml" +kubectl create -f "${url}/olm.yaml" # wait for deployments to be ready kubectl rollout status -w deployment/olm-operator --namespace="${namespace}" kubectl rollout status -w deployment/catalog-operator --namespace="${namespace}" -retries=50 -until [[ $retries == 0 || $new_csv_phase == "Succeeded" ]]; do +retries=30 +until [[ $retries == 0 ]]; do new_csv_phase=$(kubectl get csv -n "${namespace}" packageserver -o jsonpath='{.status.phase}' 2>/dev/null || echo "Waiting for CSV to appear") if [[ $new_csv_phase != "$csv_phase" ]]; then csv_phase=$new_csv_phase echo "Package server phase: $csv_phase" fi - sleep 1 + if [[ "$new_csv_phase" == "Succeeded" ]]; then + break + fi + sleep 10 retries=$((retries - 1)) done diff --git a/config/crd/bases/operator.ibm.com_operandregistries.yaml b/config/crd/bases/operator.ibm.com_operandregistries.yaml index 22ebc07d..ff43caec 100644 --- a/config/crd/bases/operator.ibm.com_operandregistries.yaml +++ b/config/crd/bases/operator.ibm.com_operandregistries.yaml @@ -61,12 +61,11 @@ spec: description: Description of a common service. type: string installMode: - description: 'The install mode of an operator, could be namespace - cluster, or no-op. Valid values are: - "namespace" (default): operator + description: 'The install mode of an operator, either namespace + or cluster. Valid values are: - "namespace" (default): operator is deployed in namespace of OperandRegistry; - "cluster": - operator is deployed in "openshift-operators" namespace; - "no-op": - operator is not supported to be fresh deployed via OperandRequest, - only upgrade and deletion are allowed;' + operator is deployed in "openshift-operators" namespace; - + "no-op": operator is not supported to be fresh deployed;' type: string installPlanApproval: description: 'Approval mode for emitted InstallPlans. Valid @@ -124,14 +123,16 @@ spec: type: string value: description: 'Variable references $(VAR_NAME) are - expanded using the previous defined environment + expanded using the previously defined environment variables in the container and any service environment variables. If a variable cannot be resolved, the reference in the input string will be unchanged. - The $(VAR_NAME) syntax can be escaped with a double - $$, ie: $$(VAR_NAME). Escaped references will never - be expanded, regardless of whether the variable - exists or not. Defaults to "".' + Double $$ are reduced to a single $, which allows + for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" + will produce the string literal "$(VAR_NAME)". Escaped + references will never be expanded, regardless of + whether the variable exists or not. Defaults to + "".' type: string valueFrom: description: Source for the environment variable's @@ -446,128 +447,133 @@ spec: that may be accessed by any container in the pod. properties: awsElasticBlockStore: - description: 'AWSElasticBlockStore represents an AWS + description: 'awsElasticBlockStore represents an AWS Disk resource that is attached to a kubelet''s host machine and then exposed to the pod. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' properties: fsType: - description: 'Filesystem type of the volume that - you want to mount. Tip: Ensure that the filesystem - type is supported by the host operating system. - Examples: "ext4", "xfs", "ntfs". Implicitly - inferred to be "ext4" if unspecified. More info: - https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore + description: 'fsType is the filesystem type of + the volume that you want to mount. Tip: Ensure + that the filesystem type is supported by the + host operating system. Examples: "ext4", "xfs", + "ntfs". Implicitly inferred to be "ext4" if + unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore TODO: how do we prevent errors in the filesystem from compromising the machine' type: string partition: - description: 'The partition in the volume that - you want to mount. If omitted, the default is - to mount by volume name. Examples: For volume - /dev/sda1, you specify the partition as "1". - Similarly, the volume partition for /dev/sda - is "0" (or you can leave the property empty).' + description: 'partition is the partition in the + volume that you want to mount. If omitted, the + default is to mount by volume name. Examples: + For volume /dev/sda1, you specify the partition + as "1". Similarly, the volume partition for + /dev/sda is "0" (or you can leave the property + empty).' format: int32 type: integer readOnly: - description: 'Specify "true" to force and set - the ReadOnly property in VolumeMounts to "true". - If omitted, the default is "false". More info: + description: 'readOnly value true will force the + readOnly setting in VolumeMounts. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' type: boolean volumeID: - description: 'Unique ID of the persistent disk - resource in AWS (Amazon EBS volume). More info: - https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' + description: 'volumeID is unique ID of the persistent + disk resource in AWS (Amazon EBS volume). More + info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' type: string required: - volumeID type: object azureDisk: - description: AzureDisk represents an Azure Data Disk + description: azureDisk represents an Azure Data Disk mount on the host and bind mount to the pod. properties: cachingMode: - description: 'Host Caching mode: None, Read Only, - Read Write.' + description: 'cachingMode is the Host Caching + mode: None, Read Only, Read Write.' type: string diskName: - description: The Name of the data disk in the - blob storage + description: diskName is the Name of the data + disk in the blob storage type: string diskURI: - description: The URI the data disk in the blob - storage + description: diskURI is the URI of data disk in + the blob storage type: string fsType: - description: Filesystem type to mount. Must be - a filesystem type supported by the host operating - system. Ex. "ext4", "xfs", "ntfs". Implicitly - inferred to be "ext4" if unspecified. + description: fsType is Filesystem type to mount. + Must be a filesystem type supported by the host + operating system. Ex. "ext4", "xfs", "ntfs". + Implicitly inferred to be "ext4" if unspecified. type: string kind: - description: 'Expected values Shared: multiple - blob disks per storage account Dedicated: single - blob disk per storage account Managed: azure - managed data disk (only in managed availability + description: 'kind expected values are Shared: + multiple blob disks per storage account Dedicated: + single blob disk per storage account Managed: + azure managed data disk (only in managed availability set). defaults to shared' type: string readOnly: - description: Defaults to false (read/write). ReadOnly - here will force the ReadOnly setting in VolumeMounts. + description: readOnly Defaults to false (read/write). + ReadOnly here will force the ReadOnly setting + in VolumeMounts. type: boolean required: - diskName - diskURI type: object azureFile: - description: AzureFile represents an Azure File Service + description: azureFile represents an Azure File Service mount on the host and bind mount to the pod. properties: readOnly: - description: Defaults to false (read/write). ReadOnly - here will force the ReadOnly setting in VolumeMounts. + description: readOnly defaults to false (read/write). + ReadOnly here will force the ReadOnly setting + in VolumeMounts. type: boolean secretName: - description: the name of secret that contains - Azure Storage Account Name and Key + description: secretName is the name of secret + that contains Azure Storage Account Name and + Key type: string shareName: - description: Share Name + description: shareName is the azure share Name type: string required: - secretName - shareName type: object cephfs: - description: CephFS represents a Ceph FS mount on + description: cephFS represents a Ceph FS mount on the host that shares a pod's lifetime properties: monitors: - description: 'Required: Monitors is a collection - of Ceph monitors More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + description: 'monitors is Required: Monitors is + a collection of Ceph monitors More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' items: type: string type: array path: - description: 'Optional: Used as the mounted root, - rather than the full Ceph tree, default is /' + description: 'path is Optional: Used as the mounted + root, rather than the full Ceph tree, default + is /' type: string readOnly: - description: 'Optional: Defaults to false (read/write). - ReadOnly here will force the ReadOnly setting - in VolumeMounts. More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + description: 'readOnly is Optional: Defaults to + false (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. More info: + https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' type: boolean secretFile: - description: 'Optional: SecretFile is the path - to key ring for User, default is /etc/ceph/user.secret - More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + description: 'secretFile is Optional: SecretFile + is the path to key ring for User, default is + /etc/ceph/user.secret More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' type: string secretRef: - description: 'Optional: SecretRef is reference - to the authentication secret for User, default - is empty. More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + description: 'secretRef is Optional: SecretRef + is reference to the authentication secret for + User, default is empty. More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' properties: name: description: 'Name of the referent. More info: @@ -577,32 +583,33 @@ spec: type: string type: object user: - description: 'Optional: User is the rados user - name, default is admin More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + description: 'user is optional: User is the rados + user name, default is admin More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' type: string required: - monitors type: object cinder: - description: 'Cinder represents a cinder volume attached + description: 'cinder represents a cinder volume attached and mounted on kubelets host machine. More info: https://examples.k8s.io/mysql-cinder-pd/README.md' properties: fsType: - description: 'Filesystem type to mount. Must be - a filesystem type supported by the host operating - system. Examples: "ext4", "xfs", "ntfs". Implicitly - inferred to be "ext4" if unspecified. More info: - https://examples.k8s.io/mysql-cinder-pd/README.md' + description: 'fsType is the filesystem type to + mount. Must be a filesystem type supported by + the host operating system. Examples: "ext4", + "xfs", "ntfs". Implicitly inferred to be "ext4" + if unspecified. More info: https://examples.k8s.io/mysql-cinder-pd/README.md' type: string readOnly: - description: 'Optional: Defaults to false (read/write). + description: 'readOnly defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts. More info: https://examples.k8s.io/mysql-cinder-pd/README.md' type: boolean secretRef: - description: 'Optional: points to a secret object - containing parameters used to connect to OpenStack.' + description: 'secretRef is optional: points to + a secret object containing parameters used to + connect to OpenStack.' properties: name: description: 'Name of the referent. More info: @@ -612,33 +619,33 @@ spec: type: string type: object volumeID: - description: 'volume id used to identify the volume + description: 'volumeID used to identify the volume in cinder. More info: https://examples.k8s.io/mysql-cinder-pd/README.md' type: string required: - volumeID type: object configMap: - description: ConfigMap represents a configMap that + description: configMap represents a configMap that should populate this volume properties: defaultMode: - description: 'Optional: mode bits used to set - permissions on created files by default. Must - be an octal value between 0000 and 0777 or a - decimal value between 0 and 511. YAML accepts - both octal and decimal values, JSON requires - decimal values for mode bits. Defaults to 0644. - Directories within the path are not affected - by this setting. This might be in conflict with - other options that affect the file mode, like - fsGroup, and the result can be other mode bits - set.' + description: 'defaultMode is optional: mode bits + used to set permissions on created files by + default. Must be an octal value between 0000 + and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, + JSON requires decimal values for mode bits. + Defaults to 0644. Directories within the path + are not affected by this setting. This might + be in conflict with other options that affect + the file mode, like fsGroup, and the result + can be other mode bits set.' format: int32 type: integer items: - description: If unspecified, each key-value pair - in the Data field of the referenced ConfigMap + description: items if unspecified, each key-value + pair in the Data field of the referenced ConfigMap will be projected into the volume as a file whose name is the key and content is the value. If specified, the listed keys will be projected @@ -653,27 +660,28 @@ spec: a volume. properties: key: - description: The key to project. + description: key is the key to project. type: string mode: - description: 'Optional: mode bits used to - set permissions on this file. Must be - an octal value between 0000 and 0777 or - a decimal value between 0 and 511. YAML - accepts both octal and decimal values, - JSON requires decimal values for mode - bits. If not specified, the volume defaultMode - will be used. This might be in conflict - with other options that affect the file - mode, like fsGroup, and the result can - be other mode bits set.' + description: 'mode is Optional: mode bits + used to set permissions on this file. + Must be an octal value between 0000 and + 0777 or a decimal value between 0 and + 511. YAML accepts both octal and decimal + values, JSON requires decimal values for + mode bits. If not specified, the volume + defaultMode will be used. This might be + in conflict with other options that affect + the file mode, like fsGroup, and the result + can be other mode bits set.' format: int32 type: integer path: - description: The relative path of the file - to map the key to. May not be an absolute - path. May not contain the path element - '..'. May not start with the string '..'. + description: path is the relative path of + the file to map the key to. May not be + an absolute path. May not contain the + path element '..'. May not start with + the string '..'. type: string required: - key @@ -687,29 +695,29 @@ spec: uid?' type: string optional: - description: Specify whether the ConfigMap or - its keys must be defined + description: optional specify whether the ConfigMap + or its keys must be defined type: boolean type: object csi: - description: CSI (Container Storage Interface) represents + description: csi (Container Storage Interface) represents ephemeral storage that is handled by certain external CSI drivers (Beta feature). properties: driver: - description: Driver is the name of the CSI driver + description: driver is the name of the CSI driver that handles this volume. Consult with your admin for the correct name as registered in the cluster. type: string fsType: - description: Filesystem type to mount. Ex. "ext4", - "xfs", "ntfs". If not provided, the empty value - is passed to the associated CSI driver which - will determine the default filesystem to apply. + description: fsType to mount. Ex. "ext4", "xfs", + "ntfs". If not provided, the empty value is + passed to the associated CSI driver which will + determine the default filesystem to apply. type: string nodePublishSecretRef: - description: NodePublishSecretRef is a reference + description: nodePublishSecretRef is a reference to the secret object containing sensitive information to pass to the CSI driver to complete the CSI NodePublishVolume and NodeUnpublishVolume calls. @@ -726,13 +734,13 @@ spec: type: string type: object readOnly: - description: Specifies a read-only configuration + description: readOnly specifies a read-only configuration for the volume. Defaults to false (read/write). type: boolean volumeAttributes: additionalProperties: type: string - description: VolumeAttributes stores driver-specific + description: volumeAttributes stores driver-specific properties that are passed to the CSI driver. Consult your driver's documentation for supported values. @@ -741,7 +749,7 @@ spec: - driver type: object downwardAPI: - description: DownwardAPI represents downward API about + description: downwardAPI represents downward API about the pod that should populate this volume properties: defaultMode: @@ -838,33 +846,34 @@ spec: type: array type: object emptyDir: - description: 'EmptyDir represents a temporary directory + description: 'emptyDir represents a temporary directory that shares a pod''s lifetime. More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir' properties: medium: - description: 'What type of storage medium should - back this directory. The default is "" which - means to use the node''s default medium. Must - be an empty string (default) or Memory. More - info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir' + description: 'medium represents what type of storage + medium should back this directory. The default + is "" which means to use the node''s default + medium. Must be an empty string (default) or + Memory. More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir' type: string sizeLimit: anyOf: - type: integer - type: string - description: 'Total amount of local storage required - for this EmptyDir volume. The size limit is - also applicable for memory medium. The maximum - usage on memory medium EmptyDir would be the - minimum value between the SizeLimit specified - here and the sum of memory limits of all containers - in a pod. The default is nil which means that - the limit is undefined. More info: http://kubernetes.io/docs/user-guide/volumes#emptydir' + description: 'sizeLimit is the total amount of + local storage required for this EmptyDir volume. + The size limit is also applicable for memory + medium. The maximum usage on memory medium EmptyDir + would be the minimum value between the SizeLimit + specified here and the sum of memory limits + of all containers in a pod. The default is nil + which means that the limit is undefined. More + info: http://kubernetes.io/docs/user-guide/volumes#emptydir' pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true type: object ephemeral: - description: "Ephemeral represents a volume that is + description: "ephemeral represents a volume that is handled by a cluster storage driver. The volume's lifecycle is tied to the pod that defines it - it will be created before the pod starts, and deleted @@ -884,9 +893,7 @@ spec: to be used that way - see the documentation of the driver for more information. \n A pod can use both types of ephemeral volumes and persistent volumes - at the same time. \n This is a beta feature and - only available when the GenericEphemeralVolume feature - gate is enabled." + at the same time." properties: volumeClaimTemplate: description: "Will be used to create a stand-alone @@ -927,26 +934,76 @@ spec: are also valid here. properties: accessModes: - description: 'AccessModes contains the + description: 'accessModes contains the desired access modes the volume should have. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1' items: type: string type: array dataSource: - description: 'This field can be used to - specify either: * An existing VolumeSnapshot - object (snapshot.storage.k8s.io/VolumeSnapshot) + description: 'dataSource field can be + used to specify either: * An existing + VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) * An existing PVC (PersistentVolumeClaim) - * An existing custom resource that implements - data population (Alpha) In order to - use custom resource types that implement - data population, the AnyVolumeDataSource - feature gate must be enabled. If the - provisioner or an external controller + If the provisioner or an external controller can support the specified data source, it will create a new volume based on - the contents of the specified data source.' + the contents of the specified data source. + If the AnyVolumeDataSource feature gate + is enabled, this field will always have + the same contents as the DataSourceRef + field.' + properties: + apiGroup: + description: APIGroup is the group + for the resource being referenced. + If APIGroup is not specified, the + specified Kind must be in the core + API group. For any other third-party + types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource + being referenced + type: string + name: + description: Name is the name of resource + being referenced + type: string + required: + - kind + - name + type: object + dataSourceRef: + description: 'dataSourceRef specifies + the object from which to populate the + volume with data, if a non-empty volume + is desired. This may be any local object + from a non-empty API group (non core + object) or a PersistentVolumeClaim object. + When this field is specified, volume + binding will only succeed if the type + of the specified object matches some + installed volume populator or dynamic + provisioner. This field will replace + the functionality of the DataSource + field and as such if both fields are + non-empty, they must have the same value. + For backwards compatibility, both fields + (DataSource and DataSourceRef) will + be set to the same value automatically + if one of them is empty and the other + is non-empty. There are two important + differences between DataSource and DataSourceRef: + * While DataSource only allows two specific + types of objects, DataSourceRef allows + any non-core object, as well as PersistentVolumeClaim + objects. * While DataSource ignores + disallowed values (dropping them), DataSourceRef preserves + all values, and generates an error if + a disallowed value is specified. (Beta) + Using this field requires the AnyVolumeDataSource + feature gate to be enabled.' properties: apiGroup: description: APIGroup is the group @@ -969,9 +1026,15 @@ spec: - name type: object resources: - description: 'Resources represents the + description: 'resources represents the minimum resources the volume should - have. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources' + have. If RecoverVolumeExpansionFailure + feature is enabled users are allowed + to specify resource requirements that + are lower than previous value but must + still be higher than capacity recorded + in the status field of the claim. More + info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources' properties: limits: additionalProperties: @@ -1001,8 +1064,8 @@ spec: type: object type: object selector: - description: A label query over volumes - to consider for binding. + description: selector is a label query + over volumes to consider for binding. properties: matchExpressions: description: matchExpressions is a @@ -1058,8 +1121,9 @@ spec: type: object type: object storageClassName: - description: 'Name of the StorageClass - required by the claim. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1' + description: 'storageClassName is the + name of the StorageClass required by + the claim. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1' type: string volumeMode: description: volumeMode defines what type @@ -1068,7 +1132,7 @@ spec: not included in claim spec. type: string volumeName: - description: VolumeName is the binding + description: volumeName is the binding reference to the PersistentVolume backing this claim. type: string @@ -1078,74 +1142,77 @@ spec: type: object type: object fc: - description: FC represents a Fibre Channel resource + description: fc represents a Fibre Channel resource that is attached to a kubelet's host machine and then exposed to the pod. properties: fsType: - description: 'Filesystem type to mount. Must be - a filesystem type supported by the host operating - system. Ex. "ext4", "xfs", "ntfs". Implicitly - inferred to be "ext4" if unspecified. TODO: - how do we prevent errors in the filesystem from - compromising the machine' + description: 'fsType is the filesystem type to + mount. Must be a filesystem type supported by + the host operating system. Ex. "ext4", "xfs", + "ntfs". Implicitly inferred to be "ext4" if + unspecified. TODO: how do we prevent errors + in the filesystem from compromising the machine' type: string lun: - description: 'Optional: FC target lun number' + description: 'lun is Optional: FC target lun number' format: int32 type: integer readOnly: - description: 'Optional: Defaults to false (read/write). - ReadOnly here will force the ReadOnly setting - in VolumeMounts.' + description: 'readOnly is Optional: Defaults to + false (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts.' type: boolean targetWWNs: - description: 'Optional: FC target worldwide names - (WWNs)' + description: 'targetWWNs is Optional: FC target + worldwide names (WWNs)' items: type: string type: array wwids: - description: 'Optional: FC volume world wide identifiers - (wwids) Either wwids or combination of targetWWNs - and lun must be set, but not both simultaneously.' + description: 'wwids Optional: FC volume world + wide identifiers (wwids) Either wwids or combination + of targetWWNs and lun must be set, but not both + simultaneously.' items: type: string type: array type: object flexVolume: - description: FlexVolume represents a generic volume + description: flexVolume represents a generic volume resource that is provisioned/attached using an exec based plugin. properties: driver: - description: Driver is the name of the driver + description: driver is the name of the driver to use for this volume. type: string fsType: - description: Filesystem type to mount. Must be - a filesystem type supported by the host operating - system. Ex. "ext4", "xfs", "ntfs". The default - filesystem depends on FlexVolume script. + description: fsType is the filesystem type to + mount. Must be a filesystem type supported by + the host operating system. Ex. "ext4", "xfs", + "ntfs". The default filesystem depends on FlexVolume + script. type: string options: additionalProperties: type: string - description: 'Optional: Extra command options - if any.' + description: 'options is Optional: this field + holds extra command options if any.' type: object readOnly: - description: 'Optional: Defaults to false (read/write). - ReadOnly here will force the ReadOnly setting - in VolumeMounts.' + description: 'readOnly is Optional: defaults to + false (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts.' type: boolean secretRef: - description: 'Optional: SecretRef is reference - to the secret object containing sensitive information - to pass to the plugin scripts. This may be empty - if no secret object is specified. If the secret - object contains more than one secret, all secrets - are passed to the plugin scripts.' + description: 'secretRef is Optional: secretRef + is reference to the secret object containing + sensitive information to pass to the plugin + scripts. This may be empty if no secret object + is specified. If the secret object contains + more than one secret, all secrets are passed + to the plugin scripts.' properties: name: description: 'Name of the referent. More info: @@ -1158,52 +1225,52 @@ spec: - driver type: object flocker: - description: Flocker represents a Flocker volume attached + description: flocker represents a Flocker volume attached to a kubelet's host machine. This depends on the Flocker control service being running properties: datasetName: - description: Name of the dataset stored as metadata - -> name on the dataset for Flocker should be - considered as deprecated + description: datasetName is Name of the dataset + stored as metadata -> name on the dataset for + Flocker should be considered as deprecated type: string datasetUUID: - description: UUID of the dataset. This is unique - identifier of a Flocker dataset + description: datasetUUID is the UUID of the dataset. + This is unique identifier of a Flocker dataset type: string type: object gcePersistentDisk: - description: 'GCEPersistentDisk represents a GCE Disk + description: 'gcePersistentDisk represents a GCE Disk resource that is attached to a kubelet''s host machine and then exposed to the pod. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' properties: fsType: - description: 'Filesystem type of the volume that - you want to mount. Tip: Ensure that the filesystem - type is supported by the host operating system. - Examples: "ext4", "xfs", "ntfs". Implicitly - inferred to be "ext4" if unspecified. More info: - https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk + description: 'fsType is filesystem type of the + volume that you want to mount. Tip: Ensure that + the filesystem type is supported by the host + operating system. Examples: "ext4", "xfs", "ntfs". + Implicitly inferred to be "ext4" if unspecified. + More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk TODO: how do we prevent errors in the filesystem from compromising the machine' type: string partition: - description: 'The partition in the volume that - you want to mount. If omitted, the default is - to mount by volume name. Examples: For volume - /dev/sda1, you specify the partition as "1". - Similarly, the volume partition for /dev/sda - is "0" (or you can leave the property empty). - More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + description: 'partition is the partition in the + volume that you want to mount. If omitted, the + default is to mount by volume name. Examples: + For volume /dev/sda1, you specify the partition + as "1". Similarly, the volume partition for + /dev/sda is "0" (or you can leave the property + empty). More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' format: int32 type: integer pdName: - description: 'Unique name of the PD resource in - GCE. Used to identify the disk in GCE. More - info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + description: 'pdName is unique name of the PD + resource in GCE. Used to identify the disk in + GCE. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' type: string readOnly: - description: 'ReadOnly here will force the ReadOnly + description: 'readOnly here will force the ReadOnly setting in VolumeMounts. Defaults to false. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' type: boolean @@ -1211,7 +1278,7 @@ spec: - pdName type: object gitRepo: - description: 'GitRepo represents a git repository + description: 'gitRepo represents a git repository at a particular revision. DEPRECATED: GitRepo is deprecated. To provision a container with a git repo, mount an EmptyDir into an InitContainer that @@ -1219,38 +1286,38 @@ spec: into the Pod''s container.' properties: directory: - description: Target directory name. Must not contain - or start with '..'. If '.' is supplied, the - volume directory will be the git repository. Otherwise, - if specified, the volume will contain the git - repository in the subdirectory with the given - name. + description: directory is the target directory + name. Must not contain or start with '..'. If + '.' is supplied, the volume directory will be + the git repository. Otherwise, if specified, + the volume will contain the git repository in + the subdirectory with the given name. type: string repository: - description: Repository URL + description: repository is the URL type: string revision: - description: Commit hash for the specified revision. + description: revision is the commit hash for the + specified revision. type: string required: - repository type: object glusterfs: - description: 'Glusterfs represents a Glusterfs mount + description: 'glusterfs represents a Glusterfs mount on the host that shares a pod''s lifetime. More info: https://examples.k8s.io/volumes/glusterfs/README.md' properties: endpoints: - description: 'EndpointsName is the endpoint name - that details Glusterfs topology. More info: - https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod' + description: 'endpoints is the endpoint name that + details Glusterfs topology. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod' type: string path: - description: 'Path is the Glusterfs volume path. + description: 'path is the Glusterfs volume path. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod' type: string readOnly: - description: 'ReadOnly here will force the Glusterfs + description: 'readOnly here will force the Glusterfs volume to be mounted with read-only permissions. Defaults to false. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod' type: boolean @@ -1259,7 +1326,7 @@ spec: - path type: object hostPath: - description: 'HostPath represents a pre-existing file + description: 'hostPath represents a pre-existing file or directory on the host machine that is directly exposed to the container. This is generally used for system agents or other privileged things that @@ -1270,72 +1337,75 @@ spec: host directories as read/write.' properties: path: - description: 'Path of the directory on the host. + description: 'path of the directory on the host. If the path is a symlink, it will follow the link to the real path. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath' type: string type: - description: 'Type for HostPath Volume Defaults + description: 'type for HostPath Volume Defaults to "" More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath' type: string required: - path type: object iscsi: - description: 'ISCSI represents an ISCSI Disk resource + description: 'iscsi represents an ISCSI Disk resource that is attached to a kubelet''s host machine and then exposed to the pod. More info: https://examples.k8s.io/volumes/iscsi/README.md' properties: chapAuthDiscovery: - description: whether support iSCSI Discovery CHAP - authentication + description: chapAuthDiscovery defines whether + support iSCSI Discovery CHAP authentication type: boolean chapAuthSession: - description: whether support iSCSI Session CHAP - authentication + description: chapAuthSession defines whether support + iSCSI Session CHAP authentication type: boolean fsType: - description: 'Filesystem type of the volume that - you want to mount. Tip: Ensure that the filesystem - type is supported by the host operating system. - Examples: "ext4", "xfs", "ntfs". Implicitly - inferred to be "ext4" if unspecified. More info: - https://kubernetes.io/docs/concepts/storage/volumes#iscsi + description: 'fsType is the filesystem type of + the volume that you want to mount. Tip: Ensure + that the filesystem type is supported by the + host operating system. Examples: "ext4", "xfs", + "ntfs". Implicitly inferred to be "ext4" if + unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#iscsi TODO: how do we prevent errors in the filesystem from compromising the machine' type: string initiatorName: - description: Custom iSCSI Initiator Name. If initiatorName - is specified with iscsiInterface simultaneously, - new iSCSI interface : will be created for the connection. + description: initiatorName is the custom iSCSI + Initiator Name. If initiatorName is specified + with iscsiInterface simultaneously, new iSCSI + interface : will + be created for the connection. type: string iqn: - description: Target iSCSI Qualified Name. + description: iqn is the target iSCSI Qualified + Name. type: string iscsiInterface: - description: iSCSI Interface Name that uses an - iSCSI transport. Defaults to 'default' (tcp). + description: iscsiInterface is the interface Name + that uses an iSCSI transport. Defaults to 'default' + (tcp). type: string lun: - description: iSCSI Target Lun number. + description: lun represents iSCSI Target Lun number. format: int32 type: integer portals: - description: iSCSI Target Portal List. The portal - is either an IP or ip_addr:port if the port - is other than default (typically TCP ports 860 - and 3260). + description: portals is the iSCSI Target Portal + List. The portal is either an IP or ip_addr:port + if the port is other than default (typically + TCP ports 860 and 3260). items: type: string type: array readOnly: - description: ReadOnly here will force the ReadOnly + description: readOnly here will force the ReadOnly setting in VolumeMounts. Defaults to false. type: boolean secretRef: - description: CHAP Secret for iSCSI target and - initiator authentication + description: secretRef is the CHAP Secret for + iSCSI target and initiator authentication properties: name: description: 'Name of the referent. More info: @@ -1345,10 +1415,10 @@ spec: type: string type: object targetPortal: - description: iSCSI Target Portal. The Portal is - either an IP or ip_addr:port if the port is - other than default (typically TCP ports 860 - and 3260). + description: targetPortal is iSCSI Target Portal. + The Portal is either an IP or ip_addr:port if + the port is other than default (typically TCP + ports 860 and 3260). type: string required: - iqn @@ -1356,24 +1426,24 @@ spec: - targetPortal type: object name: - description: 'Volume''s name. Must be a DNS_LABEL + description: 'name of the volume. Must be a DNS_LABEL and unique within the pod. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' type: string nfs: - description: 'NFS represents an NFS mount on the host + description: 'nfs represents an NFS mount on the host that shares a pod''s lifetime More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' properties: path: - description: 'Path that is exported by the NFS + description: 'path that is exported by the NFS server. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' type: string readOnly: - description: 'ReadOnly here will force the NFS + description: 'readOnly here will force the NFS export to be mounted with read-only permissions. Defaults to false. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' type: boolean server: - description: 'Server is the hostname or IP address + description: 'server is the hostname or IP address of the NFS server. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' type: string required: @@ -1381,134 +1451,138 @@ spec: - server type: object persistentVolumeClaim: - description: 'PersistentVolumeClaimVolumeSource represents + description: 'persistentVolumeClaimVolumeSource represents a reference to a PersistentVolumeClaim in the same namespace. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims' properties: claimName: - description: 'ClaimName is the name of a PersistentVolumeClaim + description: 'claimName is the name of a PersistentVolumeClaim in the same namespace as the pod using this volume. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims' type: string readOnly: - description: Will force the ReadOnly setting in - VolumeMounts. Default false. + description: readOnly Will force the ReadOnly + setting in VolumeMounts. Default false. type: boolean required: - claimName type: object photonPersistentDisk: - description: PhotonPersistentDisk represents a PhotonController + description: photonPersistentDisk represents a PhotonController persistent disk attached and mounted on kubelets host machine properties: fsType: - description: Filesystem type to mount. Must be - a filesystem type supported by the host operating - system. Ex. "ext4", "xfs", "ntfs". Implicitly - inferred to be "ext4" if unspecified. + description: fsType is the filesystem type to + mount. Must be a filesystem type supported by + the host operating system. Ex. "ext4", "xfs", + "ntfs". Implicitly inferred to be "ext4" if + unspecified. type: string pdID: - description: ID that identifies Photon Controller - persistent disk + description: pdID is the ID that identifies Photon + Controller persistent disk type: string required: - pdID type: object portworxVolume: - description: PortworxVolume represents a portworx + description: portworxVolume represents a portworx volume attached and mounted on kubelets host machine properties: fsType: - description: FSType represents the filesystem + description: fSType represents the filesystem type to mount Must be a filesystem type supported by the host operating system. Ex. "ext4", "xfs". Implicitly inferred to be "ext4" if unspecified. type: string readOnly: - description: Defaults to false (read/write). ReadOnly - here will force the ReadOnly setting in VolumeMounts. + description: readOnly defaults to false (read/write). + ReadOnly here will force the ReadOnly setting + in VolumeMounts. type: boolean volumeID: - description: VolumeID uniquely identifies a Portworx + description: volumeID uniquely identifies a Portworx volume type: string required: - volumeID type: object projected: - description: Items for all in one resources secrets, - configmaps, and downward API + description: projected items for all in one resources + secrets, configmaps, and downward API properties: defaultMode: - description: Mode bits used to set permissions - on created files by default. Must be an octal - value between 0000 and 0777 or a decimal value - between 0 and 511. YAML accepts both octal and - decimal values, JSON requires decimal values - for mode bits. Directories within the path are - not affected by this setting. This might be - in conflict with other options that affect the - file mode, like fsGroup, and the result can - be other mode bits set. + description: defaultMode are the mode bits used + to set permissions on created files by default. + Must be an octal value between 0000 and 0777 + or a decimal value between 0 and 511. YAML accepts + both octal and decimal values, JSON requires + decimal values for mode bits. Directories within + the path are not affected by this setting. This + might be in conflict with other options that + affect the file mode, like fsGroup, and the + result can be other mode bits set. format: int32 type: integer sources: - description: list of volume projections + description: sources is the list of volume projections items: description: Projection that may be projected along with other supported volume types properties: configMap: - description: information about the configMap - data to project + description: configMap information about + the configMap data to project properties: items: - description: If unspecified, each key-value - pair in the Data field of the referenced - ConfigMap will be projected into the - volume as a file whose name is the - key and content is the value. If specified, - the listed keys will be projected - into the specified paths, and unlisted - keys will not be present. If a key - is specified which is not present - in the ConfigMap, the volume setup - will error unless it is marked optional. - Paths must be relative and may not - contain the '..' path or start with - '..'. + description: items if unspecified, each + key-value pair in the Data field of + the referenced ConfigMap will be projected + into the volume as a file whose name + is the key and content is the value. + If specified, the listed keys will + be projected into the specified paths, + and unlisted keys will not be present. + If a key is specified which is not + present in the ConfigMap, the volume + setup will error unless it is marked + optional. Paths must be relative and + may not contain the '..' path or start + with '..'. items: description: Maps a string key to a path within a volume. properties: key: - description: The key to project. + description: key is the key to + project. type: string mode: - description: 'Optional: mode bits - used to set permissions on this - file. Must be an octal value - between 0000 and 0777 or a decimal - value between 0 and 511. YAML - accepts both octal and decimal - values, JSON requires decimal - values for mode bits. If not - specified, the volume defaultMode - will be used. This might be - in conflict with other options - that affect the file mode, like - fsGroup, and the result can - be other mode bits set.' + description: 'mode is Optional: + mode bits used to set permissions + on this file. Must be an octal + value between 0000 and 0777 + or a decimal value between 0 + and 511. YAML accepts both octal + and decimal values, JSON requires + decimal values for mode bits. + If not specified, the volume + defaultMode will be used. This + might be in conflict with other + options that affect the file + mode, like fsGroup, and the + result can be other mode bits + set.' format: int32 type: integer path: - description: The relative path - of the file to map the key to. - May not be an absolute path. - May not contain the path element - '..'. May not start with the - string '..'. + description: path is the relative + path of the file to map the + key to. May not be an absolute + path. May not contain the path + element '..'. May not start + with the string '..'. type: string required: - key @@ -1522,13 +1596,14 @@ spec: kind, uid?' type: string optional: - description: Specify whether the ConfigMap - or its keys must be defined + description: optional specify whether + the ConfigMap or its keys must be + defined type: boolean type: object downwardAPI: - description: information about the downwardAPI - data to project + description: downwardAPI information about + the downwardAPI data to project properties: items: description: Items is a list of DownwardAPIVolume @@ -1619,55 +1694,57 @@ spec: type: array type: object secret: - description: information about the secret - data to project + description: secret information about the + secret data to project properties: items: - description: If unspecified, each key-value - pair in the Data field of the referenced - Secret will be projected into the - volume as a file whose name is the - key and content is the value. If specified, - the listed keys will be projected - into the specified paths, and unlisted - keys will not be present. If a key - is specified which is not present - in the Secret, the volume setup will - error unless it is marked optional. - Paths must be relative and may not - contain the '..' path or start with - '..'. + description: items if unspecified, each + key-value pair in the Data field of + the referenced Secret will be projected + into the volume as a file whose name + is the key and content is the value. + If specified, the listed keys will + be projected into the specified paths, + and unlisted keys will not be present. + If a key is specified which is not + present in the Secret, the volume + setup will error unless it is marked + optional. Paths must be relative and + may not contain the '..' path or start + with '..'. items: description: Maps a string key to a path within a volume. properties: key: - description: The key to project. + description: key is the key to + project. type: string mode: - description: 'Optional: mode bits - used to set permissions on this - file. Must be an octal value - between 0000 and 0777 or a decimal - value between 0 and 511. YAML - accepts both octal and decimal - values, JSON requires decimal - values for mode bits. If not - specified, the volume defaultMode - will be used. This might be - in conflict with other options - that affect the file mode, like - fsGroup, and the result can - be other mode bits set.' + description: 'mode is Optional: + mode bits used to set permissions + on this file. Must be an octal + value between 0000 and 0777 + or a decimal value between 0 + and 511. YAML accepts both octal + and decimal values, JSON requires + decimal values for mode bits. + If not specified, the volume + defaultMode will be used. This + might be in conflict with other + options that affect the file + mode, like fsGroup, and the + result can be other mode bits + set.' format: int32 type: integer path: - description: The relative path - of the file to map the key to. - May not be an absolute path. - May not contain the path element - '..'. May not start with the - string '..'. + description: path is the relative + path of the file to map the + key to. May not be an absolute + path. May not contain the path + element '..'. May not start + with the string '..'. type: string required: - key @@ -1681,16 +1758,18 @@ spec: kind, uid?' type: string optional: - description: Specify whether the Secret - or its key must be defined + description: optional field specify + whether the Secret or its key must + be defined type: boolean type: object serviceAccountToken: - description: information about the serviceAccountToken - data to project + description: serviceAccountToken is information + about the serviceAccountToken data to + project properties: audience: - description: Audience is the intended + description: audience is the intended audience of the token. A recipient of a token must identify itself with an identifier specified in the audience @@ -1699,7 +1778,7 @@ spec: to the identifier of the apiserver. type: string expirationSeconds: - description: ExpirationSeconds is the + description: expirationSeconds is the requested duration of validity of the service account token. As the token approaches expiration, the kubelet @@ -1713,7 +1792,7 @@ spec: format: int64 type: integer path: - description: Path is the path relative + description: path is the path relative to the mount point of the file to project the token into. type: string @@ -1724,36 +1803,36 @@ spec: type: array type: object quobyte: - description: Quobyte represents a Quobyte mount on + description: quobyte represents a Quobyte mount on the host that shares a pod's lifetime properties: group: - description: Group to map volume access to Default + description: group to map volume access to Default is no group type: string readOnly: - description: ReadOnly here will force the Quobyte + description: readOnly here will force the Quobyte volume to be mounted with read-only permissions. Defaults to false. type: boolean registry: - description: Registry represents a single or multiple + description: registry represents a single or multiple Quobyte Registry services specified as a string as host:port pair (multiple entries are separated with commas) which acts as the central registry for volumes type: string tenant: - description: Tenant owning the given Quobyte volume + description: tenant owning the given Quobyte volume in the Backend Used with dynamically provisioned Quobyte volumes, value is set by the plugin type: string user: - description: User to map volume access to Defaults + description: user to map volume access to Defaults to serivceaccount user type: string volume: - description: Volume is a string that references + description: volume is a string that references an already created Quobyte volume by name. type: string required: @@ -1761,46 +1840,46 @@ spec: - volume type: object rbd: - description: 'RBD represents a Rados Block Device + description: 'rbd represents a Rados Block Device mount on the host that shares a pod''s lifetime. More info: https://examples.k8s.io/volumes/rbd/README.md' properties: fsType: - description: 'Filesystem type of the volume that - you want to mount. Tip: Ensure that the filesystem - type is supported by the host operating system. - Examples: "ext4", "xfs", "ntfs". Implicitly - inferred to be "ext4" if unspecified. More info: - https://kubernetes.io/docs/concepts/storage/volumes#rbd + description: 'fsType is the filesystem type of + the volume that you want to mount. Tip: Ensure + that the filesystem type is supported by the + host operating system. Examples: "ext4", "xfs", + "ntfs". Implicitly inferred to be "ext4" if + unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#rbd TODO: how do we prevent errors in the filesystem from compromising the machine' type: string image: - description: 'The rados image name. More info: - https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + description: 'image is the rados image name. More + info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' type: string keyring: - description: 'Keyring is the path to key ring + description: 'keyring is the path to key ring for RBDUser. Default is /etc/ceph/keyring. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' type: string monitors: - description: 'A collection of Ceph monitors. More - info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + description: 'monitors is a collection of Ceph + monitors. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' items: type: string type: array pool: - description: 'The rados pool name. Default is - rbd. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + description: 'pool is the rados pool name. Default + is rbd. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' type: string readOnly: - description: 'ReadOnly here will force the ReadOnly + description: 'readOnly here will force the ReadOnly setting in VolumeMounts. Defaults to false. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' type: boolean secretRef: - description: 'SecretRef is name of the authentication + description: 'secretRef is name of the authentication secret for RBDUser. If provided overrides keyring. Default is nil. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' properties: @@ -1812,37 +1891,39 @@ spec: type: string type: object user: - description: 'The rados user name. Default is - admin. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + description: 'user is the rados user name. Default + is admin. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' type: string required: - image - monitors type: object scaleIO: - description: ScaleIO represents a ScaleIO persistent + description: scaleIO represents a ScaleIO persistent volume attached and mounted on Kubernetes nodes. properties: fsType: - description: Filesystem type to mount. Must be - a filesystem type supported by the host operating - system. Ex. "ext4", "xfs", "ntfs". Default is - "xfs". + description: fsType is the filesystem type to + mount. Must be a filesystem type supported by + the host operating system. Ex. "ext4", "xfs", + "ntfs". Default is "xfs". type: string gateway: - description: The host address of the ScaleIO API - Gateway. + description: gateway is the host address of the + ScaleIO API Gateway. type: string protectionDomain: - description: The name of the ScaleIO Protection - Domain for the configured storage. + description: protectionDomain is the name of the + ScaleIO Protection Domain for the configured + storage. type: string readOnly: - description: Defaults to false (read/write). ReadOnly - here will force the ReadOnly setting in VolumeMounts. + description: readOnly Defaults to false (read/write). + ReadOnly here will force the ReadOnly setting + in VolumeMounts. type: boolean secretRef: - description: SecretRef references to the secret + description: secretRef references to the secret for ScaleIO user and other sensitive information. If this is not provided, Login operation will fail. @@ -1855,26 +1936,26 @@ spec: type: string type: object sslEnabled: - description: Flag to enable/disable SSL communication - with Gateway, default false + description: sslEnabled Flag enable/disable SSL + communication with Gateway, default false type: boolean storageMode: - description: Indicates whether the storage for - a volume should be ThickProvisioned or ThinProvisioned. - Default is ThinProvisioned. + description: storageMode indicates whether the + storage for a volume should be ThickProvisioned + or ThinProvisioned. Default is ThinProvisioned. type: string storagePool: - description: The ScaleIO Storage Pool associated - with the protection domain. + description: storagePool is the ScaleIO Storage + Pool associated with the protection domain. type: string system: - description: The name of the storage system as - configured in ScaleIO. + description: system is the name of the storage + system as configured in ScaleIO. type: string volumeName: - description: The name of a volume already created - in the ScaleIO system that is associated with - this volume source. + description: volumeName is the name of a volume + already created in the ScaleIO system that is + associated with this volume source. type: string required: - gateway @@ -1882,29 +1963,29 @@ spec: - system type: object secret: - description: 'Secret represents a secret that should + description: 'secret represents a secret that should populate this volume. More info: https://kubernetes.io/docs/concepts/storage/volumes#secret' properties: defaultMode: - description: 'Optional: mode bits used to set - permissions on created files by default. Must - be an octal value between 0000 and 0777 or a - decimal value between 0 and 511. YAML accepts - both octal and decimal values, JSON requires - decimal values for mode bits. Defaults to 0644. - Directories within the path are not affected - by this setting. This might be in conflict with - other options that affect the file mode, like - fsGroup, and the result can be other mode bits - set.' + description: 'defaultMode is Optional: mode bits + used to set permissions on created files by + default. Must be an octal value between 0000 + and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, + JSON requires decimal values for mode bits. + Defaults to 0644. Directories within the path + are not affected by this setting. This might + be in conflict with other options that affect + the file mode, like fsGroup, and the result + can be other mode bits set.' format: int32 type: integer items: - description: If unspecified, each key-value pair - in the Data field of the referenced Secret will - be projected into the volume as a file whose - name is the key and content is the value. If - specified, the listed keys will be projected + description: items If unspecified, each key-value + pair in the Data field of the referenced Secret + will be projected into the volume as a file + whose name is the key and content is the value. + If specified, the listed keys will be projected into the specified paths, and unlisted keys will not be present. If a key is specified which is not present in the Secret, the volume setup @@ -1916,27 +1997,28 @@ spec: a volume. properties: key: - description: The key to project. + description: key is the key to project. type: string mode: - description: 'Optional: mode bits used to - set permissions on this file. Must be - an octal value between 0000 and 0777 or - a decimal value between 0 and 511. YAML - accepts both octal and decimal values, - JSON requires decimal values for mode - bits. If not specified, the volume defaultMode - will be used. This might be in conflict - with other options that affect the file - mode, like fsGroup, and the result can - be other mode bits set.' + description: 'mode is Optional: mode bits + used to set permissions on this file. + Must be an octal value between 0000 and + 0777 or a decimal value between 0 and + 511. YAML accepts both octal and decimal + values, JSON requires decimal values for + mode bits. If not specified, the volume + defaultMode will be used. This might be + in conflict with other options that affect + the file mode, like fsGroup, and the result + can be other mode bits set.' format: int32 type: integer path: - description: The relative path of the file - to map the key to. May not be an absolute - path. May not contain the path element - '..'. May not start with the string '..'. + description: path is the relative path of + the file to map the key to. May not be + an absolute path. May not contain the + path element '..'. May not start with + the string '..'. type: string required: - key @@ -1944,30 +2026,32 @@ spec: type: object type: array optional: - description: Specify whether the Secret or its - keys must be defined + description: optional field specify whether the + Secret or its keys must be defined type: boolean secretName: - description: 'Name of the secret in the pod''s - namespace to use. More info: https://kubernetes.io/docs/concepts/storage/volumes#secret' + description: 'secretName is the name of the secret + in the pod''s namespace to use. More info: https://kubernetes.io/docs/concepts/storage/volumes#secret' type: string type: object storageos: - description: StorageOS represents a StorageOS volume + description: storageOS represents a StorageOS volume attached and mounted on Kubernetes nodes. properties: fsType: - description: Filesystem type to mount. Must be - a filesystem type supported by the host operating - system. Ex. "ext4", "xfs", "ntfs". Implicitly - inferred to be "ext4" if unspecified. + description: fsType is the filesystem type to + mount. Must be a filesystem type supported by + the host operating system. Ex. "ext4", "xfs", + "ntfs". Implicitly inferred to be "ext4" if + unspecified. type: string readOnly: - description: Defaults to false (read/write). ReadOnly - here will force the ReadOnly setting in VolumeMounts. + description: readOnly defaults to false (read/write). + ReadOnly here will force the ReadOnly setting + in VolumeMounts. type: boolean secretRef: - description: SecretRef specifies the secret to + description: secretRef specifies the secret to use for obtaining the StorageOS API credentials. If not specified, default values will be attempted. properties: @@ -1979,12 +2063,12 @@ spec: type: string type: object volumeName: - description: VolumeName is the human-readable + description: volumeName is the human-readable name of the StorageOS volume. Volume names are only unique within a namespace. type: string volumeNamespace: - description: VolumeNamespace specifies the scope + description: volumeNamespace specifies the scope of the volume within StorageOS. If no namespace is specified then the Pod's namespace will be used. This allows the Kubernetes name scoping @@ -1997,26 +2081,27 @@ spec: type: string type: object vsphereVolume: - description: VsphereVolume represents a vSphere volume + description: vsphereVolume represents a vSphere volume attached and mounted on kubelets host machine properties: fsType: - description: Filesystem type to mount. Must be - a filesystem type supported by the host operating - system. Ex. "ext4", "xfs", "ntfs". Implicitly - inferred to be "ext4" if unspecified. + description: fsType is filesystem type to mount. + Must be a filesystem type supported by the host + operating system. Ex. "ext4", "xfs", "ntfs". + Implicitly inferred to be "ext4" if unspecified. type: string storagePolicyID: - description: Storage Policy Based Management (SPBM) - profile ID associated with the StoragePolicyName. + description: storagePolicyID is the storage Policy + Based Management (SPBM) profile ID associated + with the StoragePolicyName. type: string storagePolicyName: - description: Storage Policy Based Management (SPBM) - profile name. + description: storagePolicyName is the storage + Policy Based Management (SPBM) profile name. type: string volumePath: - description: Path that identifies vSphere volume - vmdk + description: volumePath is the path that identifies + vSphere volume vmdk type: string required: - volumePath diff --git a/config/crd/bases/operator.ibm.com_operandrequests.yaml b/config/crd/bases/operator.ibm.com_operandrequests.yaml index df4f8258..8fd2dd9d 100644 --- a/config/crd/bases/operator.ibm.com_operandrequests.yaml +++ b/config/crd/bases/operator.ibm.com_operandrequests.yaml @@ -215,7 +215,55 @@ spec: phase: description: Phase is the cluster running phase. type: string + services: + description: Services reflect the status of operands beyond whether + they have been created + items: + properties: + namespace: + type: string + operatorName: + type: string + resources: + description: LastUpdateTime string `json:"lastTransitionTime,omitempty"` + items: + properties: + apiVersion: + type: string + kind: + type: string + managedResources: + description: Message string `json:"message,omitempty"` + items: + properties: + apiVersion: + type: string + kind: + type: string + namespace: + type: string + objectName: + type: string + status: + description: Type string `json:"type,omitempty"` + type: string + type: object + type: array + namespace: + type: string + objectName: + type: string + status: + type: string + type: object + type: array + status: + description: Type string `json:"type,omitempty"` + type: string + type: object + type: array type: object + x-kubernetes-preserve-unknown-fields: true type: object served: true storage: true diff --git a/config/samples/operator_v1alpha1_operandconfig.yaml b/config/samples/operator_v1alpha1_operandconfig.yaml index c2aab7eb..539cb40a 100644 --- a/config/samples/operator_v1alpha1_operandconfig.yaml +++ b/config/samples/operator_v1alpha1_operandconfig.yaml @@ -8,12 +8,15 @@ metadata: name: example-service spec: services: - - name: etcd + - name: jaeger spec: - etcdCluster: - size: 1 - - name: jenkins + jaeger: + strategy: allinone + - name: mongodb-atlas-kubernetes spec: - jenkins: - service: - port: 8081 + atlasDeployment: + deploymentSpec: + name: test-deployment + projectRef: + name: my-project + diff --git a/config/samples/operator_v1alpha1_operandregistry.yaml b/config/samples/operator_v1alpha1_operandregistry.yaml index 77299701..77bd1fe6 100644 --- a/config/samples/operator_v1alpha1_operandregistry.yaml +++ b/config/samples/operator_v1alpha1_operandregistry.yaml @@ -8,16 +8,16 @@ metadata: name: example-service spec: operators: - - name: etcd - namespace: etcd-cluster-operator - channel: clusterwide-alpha + - name: jaeger + namespace: default + channel: stable installMode: cluster - packageName: etcd + packageName: jaeger sourceName: community-operators sourceNamespace: openshift-marketplace - - name: jenkins + - name: mongodb-atlas-kubernetes namespace: default - channel: alpha - packageName: jenkins-operator + channel: stable + packageName: mongodb-atlas-kubernetes sourceName: community-operators sourceNamespace: openshift-marketplace diff --git a/config/samples/operator_v1alpha1_operandrequest.yaml b/config/samples/operator_v1alpha1_operandrequest.yaml index 987825a1..9cf20f87 100644 --- a/config/samples/operator_v1alpha1_operandrequest.yaml +++ b/config/samples/operator_v1alpha1_operandrequest.yaml @@ -10,5 +10,5 @@ spec: requests: - registry: example-service operands: - - name: etcd - - name: jenkins + - name: jaeger + - name: mongodb-atlas-kubernetes diff --git a/controllers/namespacescope/namespacescope_suite_test.go b/controllers/namespacescope/namespacescope_suite_test.go index 9246ce58..652d0cc9 100644 --- a/controllers/namespacescope/namespacescope_suite_test.go +++ b/controllers/namespacescope/namespacescope_suite_test.go @@ -22,7 +22,7 @@ import ( "testing" "time" - etcdv1beta2 "github.com/coreos/etcd-operator/pkg/apis/etcd/v1beta2" + jaegerv1 "github.com/jaegertracing/jaeger-operator/apis/v1" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "github.com/onsi/gomega/gexec" @@ -33,7 +33,6 @@ import ( ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/envtest" - "sigs.k8s.io/controller-runtime/pkg/envtest/printer" logf "sigs.k8s.io/controller-runtime/pkg/log" "sigs.k8s.io/controller-runtime/pkg/log/zap" @@ -64,9 +63,8 @@ var ( func TestNamespaceScope(t *testing.T) { RegisterFailHandler(Fail) - RunSpecsWithDefaultAndCustomReporters(t, - "NamespaceScope Controller Suite", - []Reporter{printer.NewlineReporter{}}) + RunSpecs(t, + "NamespaceScope Controller Suite") } var _ = BeforeSuite(func(done Done) { @@ -94,7 +92,7 @@ var _ = BeforeSuite(func(done Done) { Expect(err).NotTo(HaveOccurred()) err = olmv1.AddToScheme(clientgoscheme.Scheme) Expect(err).NotTo(HaveOccurred()) - err = etcdv1beta2.AddToScheme(clientgoscheme.Scheme) + err = jaegerv1.AddToScheme(clientgoscheme.Scheme) Expect(err).NotTo(HaveOccurred()) k8sClient, err = client.New(cfg, client.Options{Scheme: clientgoscheme.Scheme}) diff --git a/controllers/operandbindinfo/operandbindinfo_suite_test.go b/controllers/operandbindinfo/operandbindinfo_suite_test.go index 8fa02f95..c321d3ec 100644 --- a/controllers/operandbindinfo/operandbindinfo_suite_test.go +++ b/controllers/operandbindinfo/operandbindinfo_suite_test.go @@ -22,7 +22,7 @@ import ( "testing" "time" - etcdv1beta2 "github.com/coreos/etcd-operator/pkg/apis/etcd/v1beta2" + jaegerv1 "github.com/jaegertracing/jaeger-operator/apis/v1" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "github.com/onsi/gomega/gexec" @@ -33,7 +33,6 @@ import ( ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/envtest" - "sigs.k8s.io/controller-runtime/pkg/envtest/printer" logf "sigs.k8s.io/controller-runtime/pkg/log" "sigs.k8s.io/controller-runtime/pkg/log/zap" @@ -63,9 +62,8 @@ var ( func TestOperandBindInfo(t *testing.T) { RegisterFailHandler(Fail) - RunSpecsWithDefaultAndCustomReporters(t, - "OperandBindInfo Controller Suite", - []Reporter{printer.NewlineReporter{}}) + RunSpecs(t, + "OperandBindInfo Controller Suite") } var _ = BeforeSuite(func(done Done) { @@ -92,7 +90,7 @@ var _ = BeforeSuite(func(done Done) { Expect(err).NotTo(HaveOccurred()) err = olmv1.AddToScheme(clientgoscheme.Scheme) Expect(err).NotTo(HaveOccurred()) - err = etcdv1beta2.AddToScheme(clientgoscheme.Scheme) + err = jaegerv1.AddToScheme(clientgoscheme.Scheme) Expect(err).NotTo(HaveOccurred()) k8sClient, err = client.New(cfg, client.Options{Scheme: clientgoscheme.Scheme}) diff --git a/controllers/operandconfig/operandconfig_controller_test.go b/controllers/operandconfig/operandconfig_controller_test.go index 5aa30e89..cd2ecb6f 100644 --- a/controllers/operandconfig/operandconfig_controller_test.go +++ b/controllers/operandconfig/operandconfig_controller_test.go @@ -106,52 +106,52 @@ var _ = Describe("OperandConfig controller", func() { Expect(k8sClient.Create(ctx, request)).Should(Succeed()) By("Setting status of the Subscriptions") - etcdSub := testutil.Subscription("etcd", operatorNamespaceName) + jaegerSub := testutil.Subscription("jaeger", operatorNamespaceName) Eventually(func() error { - k8sClient.Get(ctx, types.NamespacedName{Name: "etcd", Namespace: operatorNamespaceName}, etcdSub) - etcdSub.Status = testutil.SubscriptionStatus("etcd", operatorNamespaceName, "0.0.1") - return k8sClient.Status().Update(ctx, etcdSub) + k8sClient.Get(ctx, types.NamespacedName{Name: "jaeger", Namespace: operatorNamespaceName}, jaegerSub) + jaegerSub.Status = testutil.SubscriptionStatus("jaeger", operatorNamespaceName, "0.0.1") + return k8sClient.Status().Update(ctx, jaegerSub) }, timeout, interval).Should(Succeed()) - jenkinsSub := testutil.Subscription("jenkins", operatorNamespaceName) + mongodbSub := testutil.Subscription("mongodb-atlas-kubernetes", operatorNamespaceName) Eventually(func() error { - k8sClient.Get(ctx, types.NamespacedName{Name: "jenkins", Namespace: operatorNamespaceName}, jenkinsSub) - jenkinsSub.Status = testutil.SubscriptionStatus("jenkins", operatorNamespaceName, "0.0.1") - return k8sClient.Status().Update(ctx, jenkinsSub) + k8sClient.Get(ctx, types.NamespacedName{Name: "mongodb-atlas-kubernetes", Namespace: operatorNamespaceName}, mongodbSub) + mongodbSub.Status = testutil.SubscriptionStatus("mongodb-atlas-kubernetes", operatorNamespaceName, "0.0.1") + return k8sClient.Status().Update(ctx, mongodbSub) }, timeout, interval).Should(Succeed()) By("Creating and Setting status of the ClusterServiceVersions") - etcdCSV := testutil.ClusterServiceVersion("etcd-csv.v0.0.1", operatorNamespaceName, testutil.EtcdExample) - Expect(k8sClient.Create(ctx, etcdCSV)).Should(Succeed()) + jaegerCSV := testutil.ClusterServiceVersion("jaeger-csv.v0.0.1", operatorNamespaceName, testutil.JaegerExample) + Expect(k8sClient.Create(ctx, jaegerCSV)).Should(Succeed()) Eventually(func() error { - k8sClient.Get(ctx, types.NamespacedName{Name: "etcd-csv.v0.0.1", Namespace: operatorNamespaceName}, etcdCSV) - etcdCSV.Status = testutil.ClusterServiceVersionStatus() - return k8sClient.Status().Update(ctx, etcdCSV) + k8sClient.Get(ctx, types.NamespacedName{Name: "jaeger-csv.v0.0.1", Namespace: operatorNamespaceName}, jaegerCSV) + jaegerCSV.Status = testutil.ClusterServiceVersionStatus() + return k8sClient.Status().Update(ctx, jaegerCSV) }, timeout, interval).Should(Succeed()) - jenkinsCSV := testutil.ClusterServiceVersion("jenkins-csv.v0.0.1", operatorNamespaceName, testutil.JenkinsExample) - Expect(k8sClient.Create(ctx, jenkinsCSV)).Should(Succeed()) + mongodbCSV := testutil.ClusterServiceVersion("mongodb-atlas-kubernetes-csv.v0.0.1", operatorNamespaceName, testutil.MongodbExample) + Expect(k8sClient.Create(ctx, mongodbCSV)).Should(Succeed()) Eventually(func() error { - k8sClient.Get(ctx, types.NamespacedName{Name: "jenkins-csv.v0.0.1", Namespace: operatorNamespaceName}, jenkinsCSV) - jenkinsCSV.Status = testutil.ClusterServiceVersionStatus() - return k8sClient.Status().Update(ctx, jenkinsCSV) + k8sClient.Get(ctx, types.NamespacedName{Name: "mongodb-atlas-kubernetes-csv.v0.0.1", Namespace: operatorNamespaceName}, mongodbCSV) + mongodbCSV.Status = testutil.ClusterServiceVersionStatus() + return k8sClient.Status().Update(ctx, mongodbCSV) }, timeout, interval).Should(Succeed()) By("Creating and Setting status of the InstallPlan") - etcdIP := testutil.InstallPlan("etcd-install-plan", operatorNamespaceName) - Expect(k8sClient.Create(ctx, etcdIP)).Should(Succeed()) + jaegerIP := testutil.InstallPlan("jaeger-install-plan", operatorNamespaceName) + Expect(k8sClient.Create(ctx, jaegerIP)).Should(Succeed()) Eventually(func() error { - k8sClient.Get(ctx, types.NamespacedName{Name: "etcd-install-plan", Namespace: operatorNamespaceName}, etcdIP) - etcdIP.Status = testutil.InstallPlanStatus() - return k8sClient.Status().Update(ctx, etcdIP) + k8sClient.Get(ctx, types.NamespacedName{Name: "jaeger-install-plan", Namespace: operatorNamespaceName}, jaegerIP) + jaegerIP.Status = testutil.InstallPlanStatus() + return k8sClient.Status().Update(ctx, jaegerIP) }, timeout, interval).Should(Succeed()) - jenkinsIP := testutil.InstallPlan("jenkins-install-plan", operatorNamespaceName) - Expect(k8sClient.Create(ctx, jenkinsIP)).Should(Succeed()) + mongodbIP := testutil.InstallPlan("mongodb-atlas-kubernetes-install-plan", operatorNamespaceName) + Expect(k8sClient.Create(ctx, mongodbIP)).Should(Succeed()) Eventually(func() error { - k8sClient.Get(ctx, types.NamespacedName{Name: "jenkins-install-plan", Namespace: operatorNamespaceName}, jenkinsIP) - jenkinsIP.Status = testutil.InstallPlanStatus() - return k8sClient.Status().Update(ctx, jenkinsIP) + k8sClient.Get(ctx, types.NamespacedName{Name: "mongodb-atlas-kubernetes-install-plan", Namespace: operatorNamespaceName}, mongodbIP) + mongodbIP.Status = testutil.InstallPlanStatus() + return k8sClient.Status().Update(ctx, mongodbIP) }, timeout, interval).Should(Succeed()) By("Checking status of the OperandConfig") @@ -162,12 +162,12 @@ var _ = Describe("OperandConfig controller", func() { }, timeout, interval).Should(Equal(operatorv1alpha1.ServiceRunning)) By("Cleaning up olm resources") - Expect(k8sClient.Delete(ctx, etcdSub)).Should(Succeed()) - Expect(k8sClient.Delete(ctx, jenkinsSub)).Should(Succeed()) - Expect(k8sClient.Delete(ctx, etcdCSV)).Should(Succeed()) - Expect(k8sClient.Delete(ctx, jenkinsCSV)).Should(Succeed()) - Expect(k8sClient.Delete(ctx, etcdIP)).Should(Succeed()) - Expect(k8sClient.Delete(ctx, jenkinsIP)).Should(Succeed()) + Expect(k8sClient.Delete(ctx, jaegerSub)).Should(Succeed()) + Expect(k8sClient.Delete(ctx, mongodbSub)).Should(Succeed()) + Expect(k8sClient.Delete(ctx, jaegerCSV)).Should(Succeed()) + Expect(k8sClient.Delete(ctx, mongodbCSV)).Should(Succeed()) + Expect(k8sClient.Delete(ctx, jaegerIP)).Should(Succeed()) + Expect(k8sClient.Delete(ctx, mongodbIP)).Should(Succeed()) }) }) }) diff --git a/controllers/operandconfig/operandconfig_suite_test.go b/controllers/operandconfig/operandconfig_suite_test.go index 90bafc9d..1a6913c3 100644 --- a/controllers/operandconfig/operandconfig_suite_test.go +++ b/controllers/operandconfig/operandconfig_suite_test.go @@ -22,7 +22,7 @@ import ( "testing" "time" - etcdv1beta2 "github.com/coreos/etcd-operator/pkg/apis/etcd/v1beta2" + jaegerv1 "github.com/jaegertracing/jaeger-operator/apis/v1" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "github.com/onsi/gomega/gexec" @@ -33,7 +33,6 @@ import ( ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/envtest" - "sigs.k8s.io/controller-runtime/pkg/envtest/printer" logf "sigs.k8s.io/controller-runtime/pkg/log" "sigs.k8s.io/controller-runtime/pkg/log/zap" @@ -64,9 +63,8 @@ var ( func TestOperandConfig(t *testing.T) { RegisterFailHandler(Fail) - RunSpecsWithDefaultAndCustomReporters(t, - "OperandConfig Controller Suite", - []Reporter{printer.NewlineReporter{}}) + RunSpecs(t, + "OperandConfig Controller Suite") } var _ = BeforeSuite(func(done Done) { @@ -93,7 +91,7 @@ var _ = BeforeSuite(func(done Done) { Expect(err).NotTo(HaveOccurred()) err = olmv1.AddToScheme(clientgoscheme.Scheme) Expect(err).NotTo(HaveOccurred()) - err = etcdv1beta2.AddToScheme(clientgoscheme.Scheme) + err = jaegerv1.AddToScheme(clientgoscheme.Scheme) Expect(err).NotTo(HaveOccurred()) k8sClient, err = client.New(cfg, client.Options{Scheme: clientgoscheme.Scheme}) diff --git a/controllers/operandregistry/operandregistry_controller_test.go b/controllers/operandregistry/operandregistry_controller_test.go index b64d78c8..d655b336 100644 --- a/controllers/operandregistry/operandregistry_controller_test.go +++ b/controllers/operandregistry/operandregistry_controller_test.go @@ -105,52 +105,52 @@ var _ = Describe("OperandRegistry controller", func() { Expect(k8sClient.Create(ctx, request)).Should(Succeed()) By("Setting status of the Subscriptions") - etcdSub := testutil.Subscription("etcd", operatorNamespaceName) + jaegerSub := testutil.Subscription("jaeger", operatorNamespaceName) Eventually(func() error { - k8sClient.Get(ctx, types.NamespacedName{Name: "etcd", Namespace: operatorNamespaceName}, etcdSub) - etcdSub.Status = testutil.SubscriptionStatus("etcd", operatorNamespaceName, "0.0.1") - return k8sClient.Status().Update(ctx, etcdSub) + k8sClient.Get(ctx, types.NamespacedName{Name: "jaeger", Namespace: operatorNamespaceName}, jaegerSub) + jaegerSub.Status = testutil.SubscriptionStatus("jaeger", operatorNamespaceName, "0.0.1") + return k8sClient.Status().Update(ctx, jaegerSub) }, timeout, interval).Should(Succeed()) - jenkinsSub := testutil.Subscription("jenkins", operatorNamespaceName) + mongodbSub := testutil.Subscription("mongodb-atlas-kubernetes", operatorNamespaceName) Eventually(func() error { - k8sClient.Get(ctx, types.NamespacedName{Name: "jenkins", Namespace: operatorNamespaceName}, jenkinsSub) - jenkinsSub.Status = testutil.SubscriptionStatus("jenkins", operatorNamespaceName, "0.0.1") - return k8sClient.Status().Update(ctx, jenkinsSub) + k8sClient.Get(ctx, types.NamespacedName{Name: "mongodb-atlas-kubernetes", Namespace: operatorNamespaceName}, mongodbSub) + mongodbSub.Status = testutil.SubscriptionStatus("mongodb-atlas-kubernetes", operatorNamespaceName, "0.0.1") + return k8sClient.Status().Update(ctx, mongodbSub) }, timeout, interval).Should(Succeed()) By("Creating and Setting status of the ClusterServiceVersions") - etcdCSV := testutil.ClusterServiceVersion("etcd-csv.v0.0.1", operatorNamespaceName, testutil.EtcdExample) - Expect(k8sClient.Create(ctx, etcdCSV)).Should(Succeed()) + jaegerCSV := testutil.ClusterServiceVersion("jaeger-csv.v0.0.1", operatorNamespaceName, testutil.JaegerExample) + Expect(k8sClient.Create(ctx, jaegerCSV)).Should(Succeed()) Eventually(func() error { - k8sClient.Get(ctx, types.NamespacedName{Name: "etcd-csv.v0.0.1", Namespace: operatorNamespaceName}, etcdCSV) - etcdCSV.Status = testutil.ClusterServiceVersionStatus() - return k8sClient.Status().Update(ctx, etcdCSV) + k8sClient.Get(ctx, types.NamespacedName{Name: "jaeger-csv.v0.0.1", Namespace: operatorNamespaceName}, jaegerCSV) + jaegerCSV.Status = testutil.ClusterServiceVersionStatus() + return k8sClient.Status().Update(ctx, jaegerCSV) }, timeout, interval).Should(Succeed()) - jenkinsCSV := testutil.ClusterServiceVersion("jenkins-csv.v0.0.1", operatorNamespaceName, testutil.JenkinsExample) - Expect(k8sClient.Create(ctx, jenkinsCSV)).Should(Succeed()) + mongodbCSV := testutil.ClusterServiceVersion("mongodb-atlas-kubernetes-csv.v0.0.1", operatorNamespaceName, testutil.MongodbExample) + Expect(k8sClient.Create(ctx, mongodbCSV)).Should(Succeed()) Eventually(func() error { - k8sClient.Get(ctx, types.NamespacedName{Name: "jenkins-csv.v0.0.1", Namespace: operatorNamespaceName}, jenkinsCSV) - jenkinsCSV.Status = testutil.ClusterServiceVersionStatus() - return k8sClient.Status().Update(ctx, jenkinsCSV) + k8sClient.Get(ctx, types.NamespacedName{Name: "mongodb-atlas-kubernetes-csv.v0.0.1", Namespace: operatorNamespaceName}, mongodbCSV) + mongodbCSV.Status = testutil.ClusterServiceVersionStatus() + return k8sClient.Status().Update(ctx, mongodbCSV) }, timeout, interval).Should(Succeed()) By("Creating and Setting status of the InstallPlan") - etcdIP := testutil.InstallPlan("etcd-install-plan", operatorNamespaceName) - Expect(k8sClient.Create(ctx, etcdIP)).Should(Succeed()) + jaegerIP := testutil.InstallPlan("jaeger-install-plan", operatorNamespaceName) + Expect(k8sClient.Create(ctx, jaegerIP)).Should(Succeed()) Eventually(func() error { - k8sClient.Get(ctx, types.NamespacedName{Name: "etcd-install-plan", Namespace: operatorNamespaceName}, etcdIP) - etcdIP.Status = testutil.InstallPlanStatus() - return k8sClient.Status().Update(ctx, etcdIP) + k8sClient.Get(ctx, types.NamespacedName{Name: "jaeger-install-plan", Namespace: operatorNamespaceName}, jaegerIP) + jaegerIP.Status = testutil.InstallPlanStatus() + return k8sClient.Status().Update(ctx, jaegerIP) }, timeout, interval).Should(Succeed()) - jenkinsIP := testutil.InstallPlan("jenkins-install-plan", operatorNamespaceName) - Expect(k8sClient.Create(ctx, jenkinsIP)).Should(Succeed()) + mongodbIP := testutil.InstallPlan("mongodb-atlas-kubernetes-install-plan", operatorNamespaceName) + Expect(k8sClient.Create(ctx, mongodbIP)).Should(Succeed()) Eventually(func() error { - k8sClient.Get(ctx, types.NamespacedName{Name: "jenkins-install-plan", Namespace: operatorNamespaceName}, jenkinsIP) - jenkinsIP.Status = testutil.InstallPlanStatus() - return k8sClient.Status().Update(ctx, jenkinsIP) + k8sClient.Get(ctx, types.NamespacedName{Name: "mongodb-atlas-kubernetes-install-plan", Namespace: operatorNamespaceName}, mongodbIP) + mongodbIP.Status = testutil.InstallPlanStatus() + return k8sClient.Status().Update(ctx, mongodbIP) }, timeout, interval).Should(Succeed()) By("Checking status of the OperandRegistry") @@ -161,12 +161,12 @@ var _ = Describe("OperandRegistry controller", func() { }, timeout, interval).Should(Equal(operatorv1alpha1.RegistryRunning)) By("Cleaning up olm resources") - Expect(k8sClient.Delete(ctx, etcdSub)).Should(Succeed()) - Expect(k8sClient.Delete(ctx, jenkinsSub)).Should(Succeed()) - Expect(k8sClient.Delete(ctx, etcdCSV)).Should(Succeed()) - Expect(k8sClient.Delete(ctx, jenkinsCSV)).Should(Succeed()) - Expect(k8sClient.Delete(ctx, etcdIP)).Should(Succeed()) - Expect(k8sClient.Delete(ctx, jenkinsIP)).Should(Succeed()) + Expect(k8sClient.Delete(ctx, jaegerSub)).Should(Succeed()) + Expect(k8sClient.Delete(ctx, mongodbSub)).Should(Succeed()) + Expect(k8sClient.Delete(ctx, jaegerCSV)).Should(Succeed()) + Expect(k8sClient.Delete(ctx, mongodbCSV)).Should(Succeed()) + Expect(k8sClient.Delete(ctx, jaegerIP)).Should(Succeed()) + Expect(k8sClient.Delete(ctx, mongodbIP)).Should(Succeed()) }) }) }) diff --git a/controllers/operandregistry/operandregistry_suite_test.go b/controllers/operandregistry/operandregistry_suite_test.go index b73c1845..04582485 100644 --- a/controllers/operandregistry/operandregistry_suite_test.go +++ b/controllers/operandregistry/operandregistry_suite_test.go @@ -22,7 +22,7 @@ import ( "testing" "time" - etcdv1beta2 "github.com/coreos/etcd-operator/pkg/apis/etcd/v1beta2" + jaegerv1 "github.com/jaegertracing/jaeger-operator/apis/v1" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "github.com/onsi/gomega/gexec" @@ -33,7 +33,6 @@ import ( ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/envtest" - "sigs.k8s.io/controller-runtime/pkg/envtest/printer" logf "sigs.k8s.io/controller-runtime/pkg/log" "sigs.k8s.io/controller-runtime/pkg/log/zap" @@ -63,9 +62,8 @@ var ( func TestOperandRegistry(t *testing.T) { RegisterFailHandler(Fail) - RunSpecsWithDefaultAndCustomReporters(t, - "OperandRegistry Controller Suite", - []Reporter{printer.NewlineReporter{}}) + RunSpecs(t, + "OperandRegistry Controller Suite") } var _ = BeforeSuite(func(done Done) { @@ -92,7 +90,7 @@ var _ = BeforeSuite(func(done Done) { Expect(err).NotTo(HaveOccurred()) err = olmv1.AddToScheme(clientgoscheme.Scheme) Expect(err).NotTo(HaveOccurred()) - err = etcdv1beta2.AddToScheme(clientgoscheme.Scheme) + err = jaegerv1.AddToScheme(clientgoscheme.Scheme) Expect(err).NotTo(HaveOccurred()) k8sClient, err = client.New(cfg, client.Options{Scheme: clientgoscheme.Scheme}) diff --git a/controllers/operandrequest/operandrequest_controller.go b/controllers/operandrequest/operandrequest_controller.go index 8e4284b2..6c5957eb 100644 --- a/controllers/operandrequest/operandrequest_controller.go +++ b/controllers/operandrequest/operandrequest_controller.go @@ -31,6 +31,7 @@ import ( "github.com/pkg/errors" authorizationv1 "k8s.io/api/authorization/v1" corev1 "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/types" utilerrors "k8s.io/apimachinery/pkg/util/errors" "k8s.io/klog" @@ -79,7 +80,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctrl.Re if reflect.DeepEqual(originalInstance.Status, requestInstance.Status) { return } - if err := r.Client.Status().Patch(ctx, requestInstance, client.MergeFrom(originalInstance)); err != nil { + if err := r.Client.Status().Patch(ctx, requestInstance, client.MergeFrom(originalInstance)); err != nil && !apierrors.IsNotFound(err) { reconcileErr = utilerrors.NewAggregate([]error{reconcileErr, fmt.Errorf("error while patching OperandRequest.Status: %v", err)}) } }() diff --git a/controllers/operandrequest/operandrequest_controller_test.go b/controllers/operandrequest/operandrequest_controller_test.go index c1aa2b28..019111d7 100644 --- a/controllers/operandrequest/operandrequest_controller_test.go +++ b/controllers/operandrequest/operandrequest_controller_test.go @@ -20,9 +20,9 @@ import ( "context" "crypto/sha256" "encoding/hex" - "reflect" - v1beta2 "github.com/coreos/etcd-operator/pkg/apis/etcd/v1beta2" + "github.com/google/go-cmp/cmp" + jaegerv1 "github.com/jaegertracing/jaeger-operator/apis/v1" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" olmv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1" @@ -36,7 +36,7 @@ import ( // +kubebuilder:docs-gen:collapse=Imports -var _ = Describe("OperandRegistry controller", func() { +var _ = Describe("OperandRequest controller", func() { const ( name1 = "ibm-cloudpak-name" name2 = "ibm-cloudpack-name-2" @@ -126,102 +126,102 @@ var _ = Describe("OperandRegistry controller", func() { By("Setting status of the Subscriptions") Eventually(func() error { - etcdSub := &olmv1alpha1.Subscription{} - Expect(k8sClient.Get(ctx, types.NamespacedName{Name: "etcd", Namespace: operatorNamespaceName}, etcdSub)).Should(Succeed()) - etcdSub.Status = testutil.SubscriptionStatus("etcd", operatorNamespaceName, "0.0.1") - return k8sClient.Status().Update(ctx, etcdSub) + jaegerSub := &olmv1alpha1.Subscription{} + Expect(k8sClient.Get(ctx, types.NamespacedName{Name: "jaeger", Namespace: operatorNamespaceName}, jaegerSub)).Should(Succeed()) + jaegerSub.Status = testutil.SubscriptionStatus("jaeger", operatorNamespaceName, "0.0.1") + return k8sClient.Status().Update(ctx, jaegerSub) }, testutil.Timeout, testutil.Interval).Should(Succeed()) Eventually(func() error { - jenkinsSub := &olmv1alpha1.Subscription{} - Expect(k8sClient.Get(ctx, types.NamespacedName{Name: "jenkins", Namespace: operatorNamespaceName}, jenkinsSub)).Should(Succeed()) - jenkinsSub.Status = testutil.SubscriptionStatus("jenkins", operatorNamespaceName, "0.0.1") - return k8sClient.Status().Update(ctx, jenkinsSub) + mongodbSub := &olmv1alpha1.Subscription{} + Expect(k8sClient.Get(ctx, types.NamespacedName{Name: "mongodb-atlas-kubernetes", Namespace: operatorNamespaceName}, mongodbSub)).Should(Succeed()) + mongodbSub.Status = testutil.SubscriptionStatus("mongodb-atlas-kubernetes", operatorNamespaceName, "0.0.1") + return k8sClient.Status().Update(ctx, mongodbSub) }, testutil.Timeout, testutil.Interval).Should(Succeed()) By("Creating and Setting status of the ClusterServiceVersions") - etcdCSV := testutil.ClusterServiceVersion("etcd-csv.v0.0.1", operatorNamespaceName, testutil.EtcdExample) - Expect(k8sClient.Create(ctx, etcdCSV)).Should(Succeed()) + jaegerCSV := testutil.ClusterServiceVersion("jaeger-csv.v0.0.1", operatorNamespaceName, testutil.JaegerExample) + Expect(k8sClient.Create(ctx, jaegerCSV)).Should(Succeed()) Eventually(func() error { - k8sClient.Get(ctx, types.NamespacedName{Name: "etcd-csv.v0.0.1", Namespace: operatorNamespaceName}, etcdCSV) - etcdCSV.Status = testutil.ClusterServiceVersionStatus() - return k8sClient.Status().Update(ctx, etcdCSV) + k8sClient.Get(ctx, types.NamespacedName{Name: "jaeger-csv.v0.0.1", Namespace: operatorNamespaceName}, jaegerCSV) + jaegerCSV.Status = testutil.ClusterServiceVersionStatus() + return k8sClient.Status().Update(ctx, jaegerCSV) }, testutil.Timeout, testutil.Interval).Should(Succeed()) - jenkinsCSV := testutil.ClusterServiceVersion("jenkins-csv.v0.0.1", operatorNamespaceName, testutil.JenkinsExample) - Expect(k8sClient.Create(ctx, jenkinsCSV)).Should(Succeed()) + mongodbCSV := testutil.ClusterServiceVersion("mongodb-atlas-kubernetes-csv.v0.0.1", operatorNamespaceName, testutil.MongodbExample) + Expect(k8sClient.Create(ctx, mongodbCSV)).Should(Succeed()) Eventually(func() error { - k8sClient.Get(ctx, types.NamespacedName{Name: "jenkins-csv.v0.0.1", Namespace: operatorNamespaceName}, jenkinsCSV) - jenkinsCSV.Status = testutil.ClusterServiceVersionStatus() - return k8sClient.Status().Update(ctx, jenkinsCSV) + k8sClient.Get(ctx, types.NamespacedName{Name: "mongodb-atlas-kubernetes-csv.v0.0.1", Namespace: operatorNamespaceName}, mongodbCSV) + mongodbCSV.Status = testutil.ClusterServiceVersionStatus() + return k8sClient.Status().Update(ctx, mongodbCSV) }, testutil.Timeout, testutil.Interval).Should(Succeed()) By("Creating and Setting status of the InstallPlan") - etcdIP := testutil.InstallPlan("etcd-install-plan", operatorNamespaceName) - Expect(k8sClient.Create(ctx, etcdIP)).Should(Succeed()) + jaegerIP := testutil.InstallPlan("jaeger-install-plan", operatorNamespaceName) + Expect(k8sClient.Create(ctx, jaegerIP)).Should(Succeed()) Eventually(func() error { - k8sClient.Get(ctx, types.NamespacedName{Name: "etcd-install-plan", Namespace: operatorNamespaceName}, etcdIP) - etcdIP.Status = testutil.InstallPlanStatus() - return k8sClient.Status().Update(ctx, etcdIP) + k8sClient.Get(ctx, types.NamespacedName{Name: "jaeger-install-plan", Namespace: operatorNamespaceName}, jaegerIP) + jaegerIP.Status = testutil.InstallPlanStatus() + return k8sClient.Status().Update(ctx, jaegerIP) }, testutil.Timeout, testutil.Interval).Should(Succeed()) - jenkinsIP := testutil.InstallPlan("jenkins-install-plan", operatorNamespaceName) - Expect(k8sClient.Create(ctx, jenkinsIP)).Should(Succeed()) + mongodbIP := testutil.InstallPlan("mongodb-atlas-kubernetes-install-plan", operatorNamespaceName) + Expect(k8sClient.Create(ctx, mongodbIP)).Should(Succeed()) Eventually(func() error { - k8sClient.Get(ctx, types.NamespacedName{Name: "jenkins-install-plan", Namespace: operatorNamespaceName}, jenkinsIP) - jenkinsIP.Status = testutil.InstallPlanStatus() - return k8sClient.Status().Update(ctx, jenkinsIP) + k8sClient.Get(ctx, types.NamespacedName{Name: "mongodb-atlas-kubernetes-install-plan", Namespace: operatorNamespaceName}, mongodbIP) + mongodbIP.Status = testutil.InstallPlanStatus() + return k8sClient.Status().Update(ctx, mongodbIP) }, testutil.Timeout, testutil.Interval).Should(Succeed()) - By("Checking first CR of the etcd operator") + By("Checking first CR of the jaeger operator") Eventually(func() error { - etcdCluster := &v1beta2.EtcdCluster{} - err := k8sClient.Get(context.TODO(), types.NamespacedName{Name: "example", Namespace: namespaceName}, etcdCluster) + jaegerCR := &jaegerv1.Jaeger{} + err := k8sClient.Get(context.TODO(), types.NamespacedName{Name: "my-jaeger", Namespace: namespaceName}, jaegerCR) return err }, testutil.Timeout, testutil.Interval).Should(Succeed()) - By("Checking second CR of the etcd operator") + By("Checking second CR of the jaeger operator") Eventually(func() error { - etcdCluster := &v1beta2.EtcdCluster{} - crInfo := sha256.Sum256([]byte("etcd.database.coreos.com/v1beta2" + "EtcdCluster" + "1")) - etcdCRName := name1 + "-" + hex.EncodeToString(crInfo[:7]) - err := k8sClient.Get(context.TODO(), types.NamespacedName{Name: etcdCRName, Namespace: namespaceName}, etcdCluster) + jaegerCR := &jaegerv1.Jaeger{} + crInfo := sha256.Sum256([]byte("jaegertracing.io/v1" + "Jaeger" + "1")) + jaegerCRName := name1 + "-" + hex.EncodeToString(crInfo[:7]) + err := k8sClient.Get(context.TODO(), types.NamespacedName{Name: jaegerCRName, Namespace: namespaceName}, jaegerCR) return err }, testutil.Timeout, testutil.Interval).Should(Succeed()) By("Deleting the OperandRequest") Expect(k8sClient.Delete(ctx, requestWithCR)).Should(Succeed()) - By("Checking CR of the etcd operator has been deleted") + By("Checking CR of the jaeger operator has been deleted") Eventually(func() bool { - etcdCluster := &v1beta2.EtcdCluster{} - err := k8sClient.Get(context.TODO(), types.NamespacedName{Name: "example", Namespace: namespaceName}, etcdCluster) + jaegerCR := &jaegerv1.Jaeger{} + err := k8sClient.Get(context.TODO(), types.NamespacedName{Name: "my-jaeger", Namespace: namespaceName}, jaegerCR) return err != nil && errors.IsNotFound(err) }, testutil.Timeout, testutil.Interval).Should(BeTrue()) By("Checking operators have been deleted") Eventually(func() bool { - jenkinsSub := &olmv1alpha1.Subscription{} - err := k8sClient.Get(ctx, types.NamespacedName{Name: "jenkins", Namespace: operatorNamespaceName}, jenkinsSub) + mongodbSub := &olmv1alpha1.Subscription{} + err := k8sClient.Get(ctx, types.NamespacedName{Name: "mongodb-atlas-kubernetes", Namespace: operatorNamespaceName}, mongodbSub) return err != nil && errors.IsNotFound(err) }, testutil.Timeout, testutil.Interval).Should(BeTrue()) Eventually(func() bool { - jenkinsCSV := &olmv1alpha1.ClusterServiceVersion{} - err := k8sClient.Get(ctx, types.NamespacedName{Name: "jenkins-csv.v0.0.1", Namespace: operatorNamespaceName}, jenkinsCSV) + mongodbCSV := &olmv1alpha1.ClusterServiceVersion{} + err := k8sClient.Get(ctx, types.NamespacedName{Name: "mongodb-atlas-kubernetes-csv.v0.0.1", Namespace: operatorNamespaceName}, mongodbCSV) return err != nil && errors.IsNotFound(err) }, testutil.Timeout, testutil.Interval).Should(BeTrue()) Eventually(func() bool { - etcdSub := &olmv1alpha1.Subscription{} - err := k8sClient.Get(ctx, types.NamespacedName{Name: "etcd", Namespace: operatorNamespaceName}, etcdSub) + jaegerSub := &olmv1alpha1.Subscription{} + err := k8sClient.Get(ctx, types.NamespacedName{Name: "jaeger", Namespace: operatorNamespaceName}, jaegerSub) return err != nil && errors.IsNotFound(err) }, testutil.Timeout, testutil.Interval).Should(BeTrue()) Eventually(func() bool { - etcdCSV := &olmv1alpha1.ClusterServiceVersion{} - err := k8sClient.Get(ctx, types.NamespacedName{Name: "etcd-csv.v0.0.1", Namespace: operatorNamespaceName}, etcdCSV) + jaegerCSV := &olmv1alpha1.ClusterServiceVersion{} + err := k8sClient.Get(ctx, types.NamespacedName{Name: "jaeger-csv.v0.0.1", Namespace: operatorNamespaceName}, jaegerCSV) return err != nil && errors.IsNotFound(err) }, testutil.Timeout, testutil.Interval).Should(BeTrue()) @@ -258,68 +258,68 @@ var _ = Describe("OperandRegistry controller", func() { By("Setting status of the Subscriptions") Eventually(func() error { - etcdSub := &olmv1alpha1.Subscription{} - Expect(k8sClient.Get(ctx, types.NamespacedName{Name: "etcd", Namespace: operatorNamespaceName}, etcdSub)).Should(Succeed()) - etcdSub.Status = testutil.SubscriptionStatus("etcd", operatorNamespaceName, "0.0.1") - return k8sClient.Status().Update(ctx, etcdSub) + jaegerSub := &olmv1alpha1.Subscription{} + Expect(k8sClient.Get(ctx, types.NamespacedName{Name: "jaeger", Namespace: operatorNamespaceName}, jaegerSub)).Should(Succeed()) + jaegerSub.Status = testutil.SubscriptionStatus("jaeger", operatorNamespaceName, "0.0.1") + return k8sClient.Status().Update(ctx, jaegerSub) }, testutil.Timeout, testutil.Interval).Should(Succeed()) Eventually(func() error { - jenkinsSub := &olmv1alpha1.Subscription{} - Expect(k8sClient.Get(ctx, types.NamespacedName{Name: "jenkins", Namespace: operatorNamespaceName}, jenkinsSub)).Should(Succeed()) - jenkinsSub.Status = testutil.SubscriptionStatus("jenkins", operatorNamespaceName, "0.0.1") - return k8sClient.Status().Update(ctx, jenkinsSub) + mongodbSub := &olmv1alpha1.Subscription{} + Expect(k8sClient.Get(ctx, types.NamespacedName{Name: "mongodb-atlas-kubernetes", Namespace: operatorNamespaceName}, mongodbSub)).Should(Succeed()) + mongodbSub.Status = testutil.SubscriptionStatus("mongodb-atlas-kubernetes", operatorNamespaceName, "0.0.1") + return k8sClient.Status().Update(ctx, mongodbSub) }, testutil.Timeout, testutil.Interval).Should(Succeed()) By("Creating and Setting status of the ClusterServiceVersions") - etcdCSV := testutil.ClusterServiceVersion("etcd-csv.v0.0.1", operatorNamespaceName, testutil.EtcdExample) - Expect(k8sClient.Create(ctx, etcdCSV)).Should(Succeed()) + jaegerCSV := testutil.ClusterServiceVersion("jaeger-csv.v0.0.1", operatorNamespaceName, testutil.JaegerExample) + Expect(k8sClient.Create(ctx, jaegerCSV)).Should(Succeed()) Eventually(func() error { - k8sClient.Get(ctx, types.NamespacedName{Name: "etcd-csv.v0.0.1", Namespace: operatorNamespaceName}, etcdCSV) - etcdCSV.Status = testutil.ClusterServiceVersionStatus() - return k8sClient.Status().Update(ctx, etcdCSV) + k8sClient.Get(ctx, types.NamespacedName{Name: "jaeger-csv.v0.0.1", Namespace: operatorNamespaceName}, jaegerCSV) + jaegerCSV.Status = testutil.ClusterServiceVersionStatus() + return k8sClient.Status().Update(ctx, jaegerCSV) }, testutil.Timeout, testutil.Interval).Should(Succeed()) - jenkinsCSV := testutil.ClusterServiceVersion("jenkins-csv.v0.0.1", operatorNamespaceName, testutil.JenkinsExample) - Expect(k8sClient.Create(ctx, jenkinsCSV)).Should(Succeed()) + mongodbCSV := testutil.ClusterServiceVersion("mongodb-atlas-kubernetes-csv.v0.0.1", operatorNamespaceName, testutil.MongodbExample) + Expect(k8sClient.Create(ctx, mongodbCSV)).Should(Succeed()) Eventually(func() error { - k8sClient.Get(ctx, types.NamespacedName{Name: "jenkins-csv.v0.0.1", Namespace: operatorNamespaceName}, jenkinsCSV) - jenkinsCSV.Status = testutil.ClusterServiceVersionStatus() - return k8sClient.Status().Update(ctx, jenkinsCSV) + k8sClient.Get(ctx, types.NamespacedName{Name: "mongodb-atlas-kubernetes-csv.v0.0.1", Namespace: operatorNamespaceName}, mongodbCSV) + mongodbCSV.Status = testutil.ClusterServiceVersionStatus() + return k8sClient.Status().Update(ctx, mongodbCSV) }, testutil.Timeout, testutil.Interval).Should(Succeed()) By("Creating and Setting status of the InstallPlan") - etcdIP := testutil.InstallPlan("etcd-install-plan", operatorNamespaceName) - Expect(k8sClient.Create(ctx, etcdIP)).Should(Succeed()) + jaegerIP := testutil.InstallPlan("jaeger-install-plan", operatorNamespaceName) + Expect(k8sClient.Create(ctx, jaegerIP)).Should(Succeed()) Eventually(func() error { - k8sClient.Get(ctx, types.NamespacedName{Name: "etcd-install-plan", Namespace: operatorNamespaceName}, etcdIP) - etcdIP.Status = testutil.InstallPlanStatus() - return k8sClient.Status().Update(ctx, etcdIP) + k8sClient.Get(ctx, types.NamespacedName{Name: "jaeger-install-plan", Namespace: operatorNamespaceName}, jaegerIP) + jaegerIP.Status = testutil.InstallPlanStatus() + return k8sClient.Status().Update(ctx, jaegerIP) }, testutil.Timeout, testutil.Interval).Should(Succeed()) - jenkinsIP := testutil.InstallPlan("jenkins-install-plan", operatorNamespaceName) - Expect(k8sClient.Create(ctx, jenkinsIP)).Should(Succeed()) + mongodbIP := testutil.InstallPlan("mongodb-atlas-kubernetes-install-plan", operatorNamespaceName) + Expect(k8sClient.Create(ctx, mongodbIP)).Should(Succeed()) Eventually(func() error { - k8sClient.Get(ctx, types.NamespacedName{Name: "jenkins-install-plan", Namespace: operatorNamespaceName}, jenkinsIP) - jenkinsIP.Status = testutil.InstallPlanStatus() - return k8sClient.Status().Update(ctx, jenkinsIP) + k8sClient.Get(ctx, types.NamespacedName{Name: "mongodb-atlas-kubernetes-install-plan", Namespace: operatorNamespaceName}, mongodbIP) + mongodbIP.Status = testutil.InstallPlanStatus() + return k8sClient.Status().Update(ctx, mongodbIP) }, testutil.Timeout, testutil.Interval).Should(Succeed()) - By("Checking of the CR of the etcd operator") + By("Checking of the CR of the jaeger operator") Eventually(func() error { - etcdCluster := &v1beta2.EtcdCluster{} - err := k8sClient.Get(context.TODO(), types.NamespacedName{Name: "example", Namespace: registryNamespaceName}, etcdCluster) + jaegerCR := &jaegerv1.Jaeger{} + err := k8sClient.Get(context.TODO(), types.NamespacedName{Name: "my-jaeger", Namespace: registryNamespaceName}, jaegerCR) return err }, testutil.Timeout, testutil.Interval).Should(Succeed()) - By("Checking of the k8s resource of the etcd operator") + By("Checking of the k8s resource of the jaeger operator") Eventually(func() error { - etcdConfigMap := &corev1.ConfigMap{} - err := k8sClient.Get(context.TODO(), types.NamespacedName{Name: "jenkins-configmap", Namespace: registryNamespaceName}, etcdConfigMap) + jaegerConfigMap := &corev1.ConfigMap{} + err := k8sClient.Get(context.TODO(), types.NamespacedName{Name: "jaeger-configmap", Namespace: registryNamespaceName}, jaegerConfigMap) return err }, testutil.Timeout, testutil.Interval).Should(Succeed()) - By("Disabling the etcd operator from first OperandRequest") + By("Disabling the jaeger operator from first OperandRequest") requestInstance1 := &operatorv1alpha1.OperandRequest{} Expect(k8sClient.Get(ctx, requestKey1, requestInstance1)).Should(Succeed()) requestInstance1.Spec.Requests[0].Operands = requestInstance1.Spec.Requests[0].Operands[1:] @@ -327,12 +327,12 @@ var _ = Describe("OperandRegistry controller", func() { return k8sClient.Update(ctx, requestInstance1) }, testutil.Timeout, testutil.Interval).Should(Succeed()) Eventually(func() error { - etcdCluster := &v1beta2.EtcdCluster{} - err := k8sClient.Get(context.TODO(), types.NamespacedName{Name: "example", Namespace: registryNamespaceName}, etcdCluster) + jaegerCR := &jaegerv1.Jaeger{} + err := k8sClient.Get(context.TODO(), types.NamespacedName{Name: "my-jaeger", Namespace: registryNamespaceName}, jaegerCR) return err }, testutil.Timeout, testutil.Interval).Should(Succeed()) - By("Disabling the etcd operator from second OperandRequest") + By("Disabling the jaeger operator from second OperandRequest") requestInstance2 := &operatorv1alpha1.OperandRequest{} Expect(k8sClient.Get(ctx, requestKey2, requestInstance2)).Should(Succeed()) requestInstance2.Spec.Requests[0].Operands = requestInstance2.Spec.Requests[0].Operands[1:] @@ -340,18 +340,18 @@ var _ = Describe("OperandRegistry controller", func() { return k8sClient.Update(ctx, requestInstance2) }, testutil.Timeout, testutil.Interval).Should(Succeed()) Eventually(func() bool { - etcdCluster := &v1beta2.EtcdCluster{} - err := k8sClient.Get(context.TODO(), types.NamespacedName{Name: "example", Namespace: registryNamespaceName}, etcdCluster) + jaegerCR := &jaegerv1.Jaeger{} + err := k8sClient.Get(context.TODO(), types.NamespacedName{Name: "my-jaeger", Namespace: registryNamespaceName}, jaegerCR) return err != nil && errors.IsNotFound(err) }, testutil.Timeout, testutil.Interval).Should(BeTrue()) By("Deleting the first OperandRequest") Expect(k8sClient.Delete(ctx, request1)).Should(Succeed()) - By("Checking jenkins operator has not been deleted") + By("Checking mongodb operator has not been deleted") Eventually(func() error { - jenkinsCSV := &olmv1alpha1.ClusterServiceVersion{} - err := k8sClient.Get(ctx, types.NamespacedName{Name: "jenkins-csv.v0.0.1", Namespace: operatorNamespaceName}, jenkinsCSV) + mongodbCSV := &olmv1alpha1.ClusterServiceVersion{} + err := k8sClient.Get(ctx, types.NamespacedName{Name: "mongodb-atlas-kubernetes-csv.v0.0.1", Namespace: operatorNamespaceName}, mongodbCSV) return err }, testutil.Timeout, testutil.Interval).Should(Succeed()) @@ -360,21 +360,21 @@ var _ = Describe("OperandRegistry controller", func() { By("Checking the k8s resource has been deleted") Eventually(func() bool { - etcdConfigMap := &corev1.ConfigMap{} - err := k8sClient.Get(context.TODO(), types.NamespacedName{Name: "jenkins-configmap", Namespace: registryNamespaceName}, etcdConfigMap) + jaegerConfigMap := &corev1.ConfigMap{} + err := k8sClient.Get(context.TODO(), types.NamespacedName{Name: "jaeger-configmap", Namespace: registryNamespaceName}, jaegerConfigMap) return err != nil && errors.IsNotFound(err) }, testutil.Timeout, testutil.Interval).Should(BeTrue()) By("Checking operators have been deleted") Eventually(func() bool { - etcdCSV := &olmv1alpha1.ClusterServiceVersion{} - err := k8sClient.Get(ctx, types.NamespacedName{Name: "etcd-csv.v0.0.1", Namespace: operatorNamespaceName}, etcdCSV) + jaegerCSV := &olmv1alpha1.ClusterServiceVersion{} + err := k8sClient.Get(ctx, types.NamespacedName{Name: "jaeger-csv.v0.0.1", Namespace: operatorNamespaceName}, jaegerCSV) return err != nil && errors.IsNotFound(err) }, testutil.Timeout, testutil.Interval).Should(BeTrue()) Eventually(func() bool { - jenkinsCSV := &olmv1alpha1.ClusterServiceVersion{} - err := k8sClient.Get(ctx, types.NamespacedName{Name: "jenkins-csv.v0.0.1", Namespace: operatorNamespaceName}, jenkinsCSV) + mongodbCSV := &olmv1alpha1.ClusterServiceVersion{} + err := k8sClient.Get(ctx, types.NamespacedName{Name: "mongodb-atlas-kubernetes-csv.v0.0.1", Namespace: operatorNamespaceName}, mongodbCSV) return err != nil && errors.IsNotFound(err) }, testutil.Timeout, testutil.Interval).Should(BeTrue()) @@ -408,64 +408,64 @@ var _ = Describe("OperandRegistry controller", func() { By("Setting status of the Subscriptions") Eventually(func() error { - etcdSub := &olmv1alpha1.Subscription{} - Expect(k8sClient.Get(ctx, types.NamespacedName{Name: "etcd", Namespace: operatorNamespaceName}, etcdSub)).Should(Succeed()) - etcdSub.Status = testutil.SubscriptionStatus("etcd", operatorNamespaceName, "0.0.1") - return k8sClient.Status().Update(ctx, etcdSub) + jaegerSub := &olmv1alpha1.Subscription{} + Expect(k8sClient.Get(ctx, types.NamespacedName{Name: "jaeger", Namespace: operatorNamespaceName}, jaegerSub)).Should(Succeed()) + jaegerSub.Status = testutil.SubscriptionStatus("jaeger", operatorNamespaceName, "0.0.1") + return k8sClient.Status().Update(ctx, jaegerSub) }, testutil.Timeout, testutil.Interval).Should(Succeed()) Eventually(func() error { - jenkinsSub := &olmv1alpha1.Subscription{} - Expect(k8sClient.Get(ctx, types.NamespacedName{Name: "jenkins", Namespace: operatorNamespaceName}, jenkinsSub)).Should(Succeed()) - jenkinsSub.Status = testutil.SubscriptionStatus("jenkins", operatorNamespaceName, "0.0.1") - return k8sClient.Status().Update(ctx, jenkinsSub) + mongodbSub := &olmv1alpha1.Subscription{} + Expect(k8sClient.Get(ctx, types.NamespacedName{Name: "mongodb-atlas-kubernetes", Namespace: operatorNamespaceName}, mongodbSub)).Should(Succeed()) + mongodbSub.Status = testutil.SubscriptionStatus("mongodb-atlas-kubernetes", operatorNamespaceName, "0.0.1") + return k8sClient.Status().Update(ctx, mongodbSub) }, testutil.Timeout, testutil.Interval).Should(Succeed()) By("Creating and Setting status of the ClusterServiceVersions") - etcdCSV := testutil.ClusterServiceVersion("etcd-csv.v0.0.1", operatorNamespaceName, testutil.EtcdExample) - Expect(k8sClient.Create(ctx, etcdCSV)).Should(Succeed()) + jaegerCSV := testutil.ClusterServiceVersion("jaeger-csv.v0.0.1", operatorNamespaceName, testutil.JaegerExample) + Expect(k8sClient.Create(ctx, jaegerCSV)).Should(Succeed()) Eventually(func() error { - k8sClient.Get(ctx, types.NamespacedName{Name: "etcd-csv.v0.0.1", Namespace: operatorNamespaceName}, etcdCSV) - etcdCSV.Status = testutil.ClusterServiceVersionStatus() - return k8sClient.Status().Update(ctx, etcdCSV) + k8sClient.Get(ctx, types.NamespacedName{Name: "jaeger-csv.v0.0.1", Namespace: operatorNamespaceName}, jaegerCSV) + jaegerCSV.Status = testutil.ClusterServiceVersionStatus() + return k8sClient.Status().Update(ctx, jaegerCSV) }, testutil.Timeout, testutil.Interval).Should(Succeed()) - jenkinsCSV := testutil.ClusterServiceVersion("jenkins-csv.v0.0.1", operatorNamespaceName, testutil.JenkinsExample) - Expect(k8sClient.Create(ctx, jenkinsCSV)).Should(Succeed()) + mongodbCSV := testutil.ClusterServiceVersion("mongodb-atlas-kubernetes-csv.v0.0.1", operatorNamespaceName, testutil.MongodbExample) + Expect(k8sClient.Create(ctx, mongodbCSV)).Should(Succeed()) Eventually(func() error { - k8sClient.Get(ctx, types.NamespacedName{Name: "jenkins-csv.v0.0.1", Namespace: operatorNamespaceName}, jenkinsCSV) - jenkinsCSV.Status = testutil.ClusterServiceVersionStatus() - return k8sClient.Status().Update(ctx, jenkinsCSV) + k8sClient.Get(ctx, types.NamespacedName{Name: "mongodb-atlas-kubernetes-csv.v0.0.1", Namespace: operatorNamespaceName}, mongodbCSV) + mongodbCSV.Status = testutil.ClusterServiceVersionStatus() + return k8sClient.Status().Update(ctx, mongodbCSV) }, testutil.Timeout, testutil.Interval).Should(Succeed()) By("Creating and Setting status of the InstallPlan") - etcdIP := testutil.InstallPlan("etcd-install-plan", operatorNamespaceName) - Expect(k8sClient.Create(ctx, etcdIP)).Should(Succeed()) + jaegerIP := testutil.InstallPlan("jaeger-install-plan", operatorNamespaceName) + Expect(k8sClient.Create(ctx, jaegerIP)).Should(Succeed()) Eventually(func() error { - k8sClient.Get(ctx, types.NamespacedName{Name: "etcd-install-plan", Namespace: operatorNamespaceName}, etcdIP) - etcdIP.Status = testutil.InstallPlanStatus() - return k8sClient.Status().Update(ctx, etcdIP) + k8sClient.Get(ctx, types.NamespacedName{Name: "jaeger-install-plan", Namespace: operatorNamespaceName}, jaegerIP) + jaegerIP.Status = testutil.InstallPlanStatus() + return k8sClient.Status().Update(ctx, jaegerIP) }, testutil.Timeout, testutil.Interval).Should(Succeed()) - jenkinsIP := testutil.InstallPlan("jenkins-install-plan", operatorNamespaceName) - Expect(k8sClient.Create(ctx, jenkinsIP)).Should(Succeed()) + mongodbIP := testutil.InstallPlan("mongodb-atlas-kubernetes-install-plan", operatorNamespaceName) + Expect(k8sClient.Create(ctx, mongodbIP)).Should(Succeed()) Eventually(func() error { - k8sClient.Get(ctx, types.NamespacedName{Name: "jenkins-install-plan", Namespace: operatorNamespaceName}, jenkinsIP) - jenkinsIP.Status = testutil.InstallPlanStatus() - return k8sClient.Status().Update(ctx, jenkinsIP) + k8sClient.Get(ctx, types.NamespacedName{Name: "mongodb-atlas-kubernetes-install-plan", Namespace: operatorNamespaceName}, mongodbIP) + mongodbIP.Status = testutil.InstallPlanStatus() + return k8sClient.Status().Update(ctx, mongodbIP) }, testutil.Timeout, testutil.Interval).Should(Succeed()) // Check subscription Eventually(func() bool { - etcdSub := &olmv1alpha1.Subscription{} - Expect(k8sClient.Get(ctx, types.NamespacedName{Name: "etcd", Namespace: operatorNamespaceName}, etcdSub)).Should(Succeed()) - return (etcdSub != nil) + jaegerSub := &olmv1alpha1.Subscription{} + Expect(k8sClient.Get(ctx, types.NamespacedName{Name: "jaeger", Namespace: operatorNamespaceName}, jaegerSub)).Should(Succeed()) + return (jaegerSub != nil) }, testutil.Timeout, testutil.Interval).Should(BeTrue()) Eventually(func() bool { - etcdSub := &olmv1alpha1.Subscription{} - Expect(k8sClient.Get(ctx, types.NamespacedName{Name: "etcd", Namespace: operatorNamespaceName}, etcdSub)).Should(Succeed()) - return reflect.DeepEqual(etcdSub.Spec.Config, testutil.SubConfig) + jaegerSub := &olmv1alpha1.Subscription{} + Expect(k8sClient.Get(ctx, types.NamespacedName{Name: "jaeger", Namespace: operatorNamespaceName}, jaegerSub)).Should(Succeed()) + return cmp.Equal(jaegerSub.Spec.Config, testutil.SubConfig) }, testutil.Timeout, testutil.Interval).Should(BeTrue()) By("Deleting the OperandConfig") diff --git a/controllers/operandrequest/operandrequest_suite_test.go b/controllers/operandrequest/operandrequest_suite_test.go index f213aa8c..33353453 100644 --- a/controllers/operandrequest/operandrequest_suite_test.go +++ b/controllers/operandrequest/operandrequest_suite_test.go @@ -22,7 +22,7 @@ import ( "testing" "time" - etcdv1beta2 "github.com/coreos/etcd-operator/pkg/apis/etcd/v1beta2" + jaegerv1 "github.com/jaegertracing/jaeger-operator/apis/v1" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "github.com/onsi/gomega/gexec" @@ -33,7 +33,6 @@ import ( ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/envtest" - "sigs.k8s.io/controller-runtime/pkg/envtest/printer" logf "sigs.k8s.io/controller-runtime/pkg/log" "sigs.k8s.io/controller-runtime/pkg/log/zap" @@ -57,9 +56,8 @@ var ( func TestOperanRequest(t *testing.T) { RegisterFailHandler(Fail) - RunSpecsWithDefaultAndCustomReporters(t, - "OperandRequest Controller Suite", - []Reporter{printer.NewlineReporter{}}) + RunSpecs(t, + "OperandRequest Controller Suite") } var _ = BeforeSuite(func(done Done) { @@ -86,7 +84,7 @@ var _ = BeforeSuite(func(done Done) { Expect(err).NotTo(HaveOccurred()) err = olmv1.AddToScheme(clientgoscheme.Scheme) Expect(err).NotTo(HaveOccurred()) - err = etcdv1beta2.AddToScheme(clientgoscheme.Scheme) + err = jaegerv1.AddToScheme(clientgoscheme.Scheme) Expect(err).NotTo(HaveOccurred()) k8sClient, err = client.New(cfg, client.Options{Scheme: clientgoscheme.Scheme}) diff --git a/controllers/operandrequest/reconcile_operand.go b/controllers/operandrequest/reconcile_operand.go index 5808722b..39756a0e 100644 --- a/controllers/operandrequest/reconcile_operand.go +++ b/controllers/operandrequest/reconcile_operand.go @@ -40,6 +40,7 @@ import ( "k8s.io/apimachinery/pkg/util/wait" "k8s.io/client-go/discovery" "k8s.io/klog" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" operatorv1alpha1 "github.com/IBM/operand-deployment-lifecycle-manager/api/v1alpha1" constant "github.com/IBM/operand-deployment-lifecycle-manager/controllers/constant" @@ -380,6 +381,10 @@ func (r *Reconciler) reconcileCRwithRequest(ctx context.Context, requestInstance crFromRequest.SetNamespace(requestKey.Namespace) crFromRequest.SetAPIVersion(operand.APIVersion) crFromRequest.SetKind(operand.Kind) + // Set the OperandRequest as the controller of the CR from request + if err := controllerutil.SetControllerReference(requestInstance, &crFromRequest, r.Scheme); err != nil { + merr.Add(errors.Wrapf(err, "failed to set ownerReference for custom resource %s/%s", requestKey.Namespace, name)) + } err := r.Client.Get(ctx, types.NamespacedName{ Name: name, diff --git a/controllers/testutil/test_data.go b/controllers/testutil/test_data.go index 21532643..bc87e3a2 100644 --- a/controllers/testutil/test_data.go +++ b/controllers/testutil/test_data.go @@ -25,31 +25,38 @@ const ( Interval = time.Second * 5 ) -const EtcdExample string = ` +const JaegerExample string = ` [ { - "apiVersion": "etcd.database.coreos.com/v1beta2", - "kind": "EtcdCluster", + "apiVersion": "jaegertracing.io/v1", + "kind": "Jaeger", "metadata": { - "name": "example" + "name": "my-jaeger" }, "spec": { - "size": 3, - "version": "3.2.13" + "strategy": "allinone" } } ] ` -const JenkinsExample string = ` +const MongodbExample string = ` [ { - "apiVersion": "jenkins.io/v1alpha2", - "kind": "Jenkins", + "apiVersion": "atlas.mongodb.com/v1", + "kind": "AtlasDeployment", "metadata": { - "name": "example" + "name": "my-atlas-deployment" }, "spec": { - "service": {"port": 8081} + "deploymentSpec": { + "name": "test-deployment", + "providerSettings": { + "instanceSizeName": "M10", + "providerName": "AWS", + "regionName": "US_EAST_1" + } + }, + "projectRef": {"name": "my-project"} } } ] diff --git a/controllers/testutil/test_util.go b/controllers/testutil/test_util.go index b37f588c..16033f2b 100644 --- a/controllers/testutil/test_util.go +++ b/controllers/testutil/test_util.go @@ -74,21 +74,21 @@ func OperandRegistryObj(name, namespace, subNamespace string) *apiv1alpha1.Opera Spec: apiv1alpha1.OperandRegistrySpec{ Operators: []apiv1alpha1.Operator{ { - Name: "etcd", + Name: "jaeger", Namespace: subNamespace, SourceName: "community-operators", SourceNamespace: "openshift-marketplace", - PackageName: "etcd", - Channel: "singlenamespace-alpha", + PackageName: "jaeger", + Channel: "stable", Scope: "public", }, { - Name: "jenkins", + Name: "mongodb-atlas-kubernetes", Namespace: subNamespace, SourceName: "community-operators", SourceNamespace: "openshift-marketplace", - PackageName: "jenkins-operator", - Channel: "alpha", + PackageName: "mongodb-atlas-kubernetes", + Channel: "stable", Scope: "public", }, }, @@ -106,22 +106,22 @@ func OperandRegistryObjwithCfg(name, namespace, subNamespace string) *apiv1alpha Spec: apiv1alpha1.OperandRegistrySpec{ Operators: []apiv1alpha1.Operator{ { - Name: "etcd", + Name: "jaeger", Namespace: subNamespace, SourceName: "community-operators", SourceNamespace: "openshift-marketplace", - PackageName: "etcd", - Channel: "singlenamespace-alpha", + PackageName: "jaeger", + Channel: "stable", Scope: "public", SubscriptionConfig: SubConfig, }, { - Name: "jenkins", + Name: "mongodb-atlas-kubernetes", Namespace: subNamespace, SourceName: "community-operators", SourceNamespace: "openshift-marketplace", - PackageName: "jenkins-operator", - Channel: "alpha", + PackageName: "mongodb-atlas-kubernetes", + Channel: "stable", Scope: "public", }, }, @@ -139,32 +139,32 @@ func OperandConfigObj(name, namespace string) *apiv1alpha1.OperandConfig { Spec: apiv1alpha1.OperandConfigSpec{ Services: []apiv1alpha1.ConfigService{ { - Name: "etcd", + Name: "jaeger", Spec: map[string]runtime.RawExtension{ - "etcdCluster": {Raw: []byte(`{"size": 3}`)}, + "jaeger": {Raw: []byte(`{"strategy": "streaming"}`)}, }, Resources: []apiv1alpha1.ConfigResource{ { - Name: "jenkins-configmap", + Name: "jaeger-configmap", APIVersion: "v1", Kind: "ConfigMap", Labels: map[string]string{ - "etcd": "etcd-configmap", + "jaeger": "jaeger-configmap", }, Annotations: map[string]string{ - "etcd": "etcd-configmap", + "jaeger": "jaeger-configmap", }, Data: &runtime.RawExtension{ - Raw: []byte(`{"data": {"size": "3"}}`), + Raw: []byte(`{"data": {"strategy": "allinone"}}`), }, Force: false, }, }, }, { - Name: "jenkins", + Name: "mongodb-atlas-kubernetes", Spec: map[string]runtime.RawExtension{ - "jenkins": {Raw: []byte(`{"service":{"port": 8081}}`)}, + "atlasDeployment": {Raw: []byte(`{"deploymentSpec":{"name": "test-deployment"}, "projectRef": {"name": "my-updated-project"}}`)}, }, }, }, @@ -189,10 +189,10 @@ func OperandRequestObj(registryName, registryNamespace, requestName, requestName RegistryNamespace: registryNamespace, Operands: []apiv1alpha1.Operand{ { - Name: "etcd", + Name: "jaeger", }, { - Name: "jenkins", + Name: "mongodb-atlas-kubernetes", Bindings: map[string]apiv1alpha1.SecretConfigmap{ "public": { Secret: "secret4", @@ -224,29 +224,38 @@ func OperandRequestObjWithCR(registryName, registryNamespace, requestName, reque RegistryNamespace: registryNamespace, Operands: []apiv1alpha1.Operand{ { - Name: "etcd", - Kind: "EtcdCluster", - APIVersion: "etcd.database.coreos.com/v1beta2", - InstanceName: "example", + Name: "jaeger", + Kind: "Jaeger", + APIVersion: "jaegertracing.io/v1", + InstanceName: "my-jaeger", Spec: &runtime.RawExtension{ - Raw: []byte(`{"size": 3,"version": "3.2.13"}`), + Raw: []byte(`{"strategy": "allinone"}`), }, }, { - Name: "etcd", - Kind: "EtcdCluster", - APIVersion: "etcd.database.coreos.com/v1beta2", + Name: "jaeger", + Kind: "Jaeger", + APIVersion: "jaegertracing.io/v1", Spec: &runtime.RawExtension{ - Raw: []byte(`{"size": 3,"version": "3.2.15"}`), + Raw: []byte(`{"strategy": "streaming"}`), }, }, { - Name: "jenkins", - Kind: "Jenkins", - APIVersion: "jenkins.io/v1alpha2", - InstanceName: "example", + Name: "mongodb-atlas-kubernetes", + Kind: "AtlasDeployment", + APIVersion: "atlas.mongodb.com/v1", + InstanceName: "my-atlas-deployment", Spec: &runtime.RawExtension{ - Raw: []byte(`{"service": {"port": 8081}}`), + Raw: []byte(`{ + "deploymentSpec": { + "name": "test-deployment", + "providerSettings": { + "instanceSizeName": "M10", + "providerName": "AWS", + "regionName": "US_EAST_1" + } + }, + "projectRef": {"name": "my-project"}}`), }, }, }, @@ -273,10 +282,10 @@ func OperandRequestObjWithProtected(registryName, registryNamespace, requestName RegistryNamespace: registryNamespace, Operands: []apiv1alpha1.Operand{ { - Name: "etcd", + Name: "jaeger", }, { - Name: "jenkins", + Name: "mongodb-atlas-kubernetes", Bindings: map[string]apiv1alpha1.SecretConfigmap{ "protected": { Secret: "secret5", @@ -299,7 +308,7 @@ func OperandBindInfoObj(name, namespace, registryName, registryNamespace string) Namespace: namespace, }, Spec: apiv1alpha1.OperandBindInfoSpec{ - Operand: "jenkins", + Operand: "mongodb-atlas-kubernetes", Registry: registryName, RegistryNamespace: registryNamespace, Bindings: map[string]apiv1alpha1.SecretConfigmap{ diff --git a/go.mod b/go.mod index f8fba07b..d2696251 100644 --- a/go.mod +++ b/go.mod @@ -3,83 +3,104 @@ module github.com/IBM/operand-deployment-lifecycle-manager go 1.20 require ( - github.com/IBM/controller-filtered-cache v0.3.2 - github.com/IBM/ibm-namespace-scope-operator v1.0.0-alpha - github.com/coreos/etcd-operator v0.9.4 + github.com/IBM/controller-filtered-cache v0.3.5 + github.com/IBM/ibm-namespace-scope-operator v1.17.3 github.com/deckarep/golang-set v1.7.1 + github.com/google/go-cmp v0.5.9 + github.com/jaegertracing/jaeger-operator v1.36.0 github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 - github.com/onsi/ginkgo v1.16.4 - github.com/onsi/gomega v1.14.0 + github.com/onsi/ginkgo v1.16.5 + github.com/onsi/gomega v1.19.0 github.com/operator-framework/api v0.6.2 github.com/operator-framework/operator-lifecycle-manager v0.17.0 github.com/pkg/errors v0.9.1 golang.org/x/mod v0.7.0 - k8s.io/api v0.21.3 - k8s.io/apimachinery v0.21.14 - k8s.io/client-go v0.21.3 + k8s.io/api v0.24.3 + k8s.io/apiextensions-apiserver v0.24.2 + k8s.io/apimachinery v0.24.3 + k8s.io/client-go v0.24.3 k8s.io/klog v1.0.0 - sigs.k8s.io/controller-runtime v0.9.6 + sigs.k8s.io/controller-runtime v0.12.3 sigs.k8s.io/kubebuilder v1.0.9-0.20200805184228-f7a3b65dd250 ) require ( - cloud.google.com/go v0.54.0 // indirect + cloud.google.com/go/compute v1.6.1 // indirect + github.com/PuerkitoBio/purell v1.1.1 // indirect + github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/blang/semver v3.5.1+incompatible // indirect github.com/blang/semver/v4 v4.0.0 // indirect - github.com/cespare/xxhash/v2 v2.1.1 // indirect + github.com/cespare/xxhash/v2 v2.1.2 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/evanphx/json-patch v4.11.0+incompatible // indirect - github.com/fsnotify/fsnotify v1.4.9 // indirect - github.com/go-logr/logr v0.4.0 // indirect - github.com/go-logr/zapr v0.4.0 // indirect + github.com/emicklei/go-restful/v3 v3.8.0 // indirect + github.com/evanphx/json-patch v4.12.0+incompatible // indirect + github.com/fsnotify/fsnotify v1.5.4 // indirect + github.com/go-logr/logr v1.2.3 // indirect + github.com/go-logr/zapr v1.2.0 // indirect + github.com/go-openapi/jsonpointer v0.19.5 // indirect + github.com/go-openapi/jsonreference v0.19.5 // indirect + github.com/go-openapi/swag v0.19.14 // indirect github.com/gobuffalo/flect v0.2.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect + github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.2 // indirect - github.com/google/go-cmp v0.5.5 // indirect + github.com/google/gnostic v0.6.9 // indirect github.com/google/gofuzz v1.1.0 // indirect github.com/google/uuid v1.1.2 // indirect - github.com/googleapis/gnostic v0.5.5 // indirect - github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/hcl v1.0.0 // indirect github.com/imdario/mergo v0.3.12 // indirect - github.com/json-iterator/go v1.1.11 // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/magiconair/properties v1.8.6 // indirect + github.com/mailru/easyjson v0.7.6 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect - github.com/modern-go/reflect2 v1.0.1 // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/nxadm/tail v1.4.8 // indirect + github.com/openshift/elasticsearch-operator v0.0.0-20220708171007-a87102296ded // indirect github.com/operator-framework/operator-registry v1.13.6 // indirect - github.com/prometheus/client_golang v1.11.1 // indirect + github.com/pelletier/go-toml v1.9.5 // indirect + github.com/pelletier/go-toml/v2 v2.0.1 // indirect + github.com/prometheus/client_golang v1.12.2 // indirect github.com/prometheus/client_model v0.2.0 // indirect - github.com/prometheus/common v0.26.0 // indirect - github.com/prometheus/procfs v0.6.0 // indirect - github.com/sirupsen/logrus v1.7.0 // indirect + github.com/prometheus/common v0.32.1 // indirect + github.com/prometheus/procfs v0.7.3 // indirect + github.com/sirupsen/logrus v1.9.0 // indirect + github.com/spf13/afero v1.8.2 // indirect + github.com/spf13/cast v1.5.0 // indirect + github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect + github.com/spf13/viper v1.12.0 // indirect + github.com/subosito/gotenv v1.3.0 // indirect go.uber.org/atomic v1.7.0 // indirect go.uber.org/multierr v1.6.0 // indirect - go.uber.org/zap v1.18.1 // indirect - golang.org/x/net v0.0.0-20211209124913-491a49abca63 // indirect - golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d // indirect - golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f // indirect - golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d // indirect - golang.org/x/text v0.3.8 // indirect - golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect + go.uber.org/zap v1.19.1 // indirect + golang.org/x/net v0.7.0 // indirect + golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5 // indirect + golang.org/x/sys v0.5.0 // indirect + golang.org/x/term v0.5.0 // indirect + golang.org/x/text v0.7.0 // indirect + golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a // indirect - google.golang.org/grpc v1.30.0 // indirect - google.golang.org/protobuf v1.26.0 // indirect + google.golang.org/genproto v0.0.0-20220519153652-3a47de7e79bd // indirect + google.golang.org/grpc v1.48.0 // indirect + google.golang.org/protobuf v1.28.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect + gopkg.in/ini.v1 v1.66.4 // indirect gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect - gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect - k8s.io/apiextensions-apiserver v0.21.3 // indirect - k8s.io/component-base v0.21.3 // indirect - k8s.io/klog/v2 v2.9.0 // indirect - k8s.io/kube-openapi v0.0.0-20211110012726-3cc51fd1e909 // indirect - k8s.io/utils v0.0.0-20210722164352-7f3ee0f31471 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + k8s.io/component-base v0.24.2 // indirect + k8s.io/klog/v2 v2.60.1 // indirect + k8s.io/kube-openapi v0.0.0-20220627174259-011e075b9cb8 // indirect + k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9 // indirect + sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2 // indirect sigs.k8s.io/structured-merge-diff/v4 v4.2.1 // indirect - sigs.k8s.io/yaml v1.2.0 // indirect + sigs.k8s.io/yaml v1.3.0 // indirect ) // fix vulnerability: CVE-2021-3121 in github.com/gogo/protobuf v1.2.1 diff --git a/go.sum b/go.sum index c382f1d5..5a4facdb 100644 --- a/go.sum +++ b/go.sum @@ -5,37 +5,71 @@ cloud.google.com/go v0.37.4/go.mod h1:NHPJ89PdicEuT9hdPXMROBD91xc5uRDxsMtSB16k7h cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= -cloud.google.com/go v0.54.0 h1:3ithwDMr7/3vpAMXiH+ZQnYbuIsh+OPhUPMFC9enmn0= cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= +cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= +cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= +cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= +cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= +cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= +cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= +cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= +cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= +cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= +cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= +cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= +cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= +cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= +cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow= +cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM= +cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M= +cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s= +cloud.google.com/go/compute v1.6.1 h1:2sMmt8prCn7DPaG4Pmh0N3Inmc8cT8ae5k1M6VJ9Wqc= +cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= +cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/Azure/azure-sdk-for-go v16.2.1+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= -github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/Azure/go-autorest v10.8.1+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= github.com/Azure/go-autorest/autorest v0.11.1/go.mod h1:JFgpikqFJ/MleTTxwepExTKnFUKKszPS8UavbQYUMuw= -github.com/Azure/go-autorest/autorest v0.11.12/go.mod h1:eipySxLmqSyC5s5k1CLupqet0PSENBEDP93LQ9a8QYw= +github.com/Azure/go-autorest/autorest v0.11.18/go.mod h1:dSiJPy22c3u0OtOKDNttNgqpNFY/GeWa7GH/Pz56QRA= github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= github.com/Azure/go-autorest/autorest/adal v0.9.0/go.mod h1:/c022QCutn2P7uY+/oQWWNcK9YU+MH96NgK+jErpbcg= github.com/Azure/go-autorest/autorest/adal v0.9.5/go.mod h1:B7KF7jKIeC9Mct5spmyCB/A8CG/sEz1vwIRGv/bbw7A= +github.com/Azure/go-autorest/autorest/adal v0.9.13/go.mod h1:W/MM4U6nLxnIskrw4UwWzlHfGjwUS50aOsc/I3yuU8M= github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= @@ -44,14 +78,15 @@ github.com/Azure/go-autorest/autorest/mocks v0.4.0/go.mod h1:LTp+uSrOhSkaKrUy935 github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= +github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/IBM/controller-filtered-cache v0.3.2 h1:ghyg9s/NyrlyLvZayj65jy4Vcc1dSyD2cee5fp6Ki8Q= -github.com/IBM/controller-filtered-cache v0.3.2/go.mod h1:gEDzSQxUwcdScwsw59MTwchTjh6vzLWaSPffIkr85U4= -github.com/IBM/ibm-namespace-scope-operator v1.0.0-alpha h1:xU3IXZ2ZDumuL36mjSqcPZa3mS7XUJSXQYLR7VMUGy8= -github.com/IBM/ibm-namespace-scope-operator v1.0.0-alpha/go.mod h1:wkE4MMVf3IKwsu90Gxy4No/S5gZ/PC6EHKcoXKiX21Q= +github.com/IBM/controller-filtered-cache v0.3.5 h1:XoT+7B12jGeWHZBe3qOnXNCJukGtXP+MUVnu0Lq4BvM= +github.com/IBM/controller-filtered-cache v0.3.5/go.mod h1:Lu4gJQZ9TqO9FiQXq+JA5gXs8/4AoFmo4ee+PD5Lp/A= +github.com/IBM/ibm-namespace-scope-operator v1.17.3 h1:AS5EpRrHFxxGBR57KrEZu7MzkCQQNCoCBH4quu3XB3Q= +github.com/IBM/ibm-namespace-scope-operator v1.17.3/go.mod h1:tQ3ENUpO4IprjZypcH8UCzd0fT0fDYNlUuffGgyMZv8= github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd/go.mod h1:64YHyfSL2R96J44Nlwm39UHepQbyR5q10x7iYa1ks2E= github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= github.com/Masterminds/semver/v3 v3.0.3/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= @@ -69,8 +104,10 @@ github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8 github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d h1:UrqY+r/OJnIp5u0s1SbQ8dVfLCZJsnvazdBP5hS4iRs= github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ= @@ -85,16 +122,20 @@ github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk5 github.com/alessio/shellescape v0.0.0-20190409004728-b115ca0f9053/go.mod h1:xW8sBma2LE3QxFSzCnH9qe6gAE2yO9GvQaWwX89HxbE= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= github.com/antihax/optional v0.0.0-20180407024304-ca021399b1a6/go.mod h1:V8iCPQYkqmusNa815XgQio277wI47sdRh1dUOLdyC6Q= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20210826220005-b48c857c3a0e/go.mod h1:F7bn7fEU90QkQ3tnmaTx3LTKLEDqnwWODIYppRQ5hnY= github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg= github.com/aws/aws-sdk-go v1.15.11/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0= github.com/aws/aws-sdk-go v1.17.7/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM= github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20160804104726-4c0e84591b9a/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= @@ -115,6 +156,7 @@ github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2y github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= github.com/bshuster-repo/logrus-logstash-hook v0.4.1 h1:pgAtgj+A31JBVtEHu2uHuEx0n+2ukqUJnS2vVe5pQNA= github.com/bshuster-repo/logrus-logstash-hook v0.4.1/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk= +github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8= github.com/bugsnag/bugsnag-go v1.5.3 h1:yeRUT3mUE13jL1tGwvoQsKdVbAsQx9AJ+fqahKveP04= github.com/bugsnag/bugsnag-go v1.5.3/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8= @@ -123,19 +165,33 @@ github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3k github.com/bugsnag/panicwrap v1.2.0 h1:OzrKrRvXis8qEvOkfcxNcYbOd2O7xXS2nnKMEMABFQA= github.com/bugsnag/panicwrap v1.2.0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/certifi/gocertifi v0.0.0-20191021191039-0944d244cd40/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA= +github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.0/go.mod h1:dgIUBU3pDso/gPgZ1osOZ0iQf77oPR28Tjxl5dIMyVM= -github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= +github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5/go.mod h1:/iP1qXHoty45bqomnu2LM+VVyAEdWN+vtSHGlQgyxbw= 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/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= github.com/cockroachdb/cockroach-go v0.0.0-20181001143604-e0a95dfd547c/go.mod h1:XGLbWH/ujMcbPbhZq52Nv6UrCghb1yGn//133kEsvDk= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= +github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5/go.mod h1:h6jFvWxBdQXxjopDMZyH2UVceIRfR84bdzbkoKrsWNo= +github.com/cockroachdb/errors v1.2.4/go.mod h1:rQD95gz6FARkaKkQXUksEje/d9a6wBJoCr5oaCLELYA= +github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI= github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f h1:tSNMc+rJDfmYntojat8lljbt1mgKNpTxUZJsSzJ9Y1s= github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f/go.mod h1:OApqhQ4XNSNC13gXIwDjhOQxjWa/NxkwZXJ1EvqT0ko= github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw= @@ -156,19 +212,19 @@ github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kw github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/etcd-operator v0.9.4 h1:NkN7HxlYHl4vOY8+etHRA+zDedwYYLhKfIsxdEPM+Lc= -github.com/coreos/etcd-operator v0.9.4/go.mod h1:h6zWPsRcUpzmi9C3kEE5HZqy1oo+jK4VtjdemOxySbE= github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= @@ -235,29 +291,44 @@ github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkg github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/emicklei/go-restful/v3 v3.8.0 h1:eCZ8ulSerjdAiaNpF7GxXIE7ZCMo1moN1qX+S609eVw= +github.com/emicklei/go-restful/v3 v3.8.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= +github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= +github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ= github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch v4.5.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/evanphx/json-patch v4.11.0+incompatible h1:glyUF9yIYtMHzn8xaKw5rMhdWcwsYV8dZHIq5567/xs= -github.com/evanphx/json-patch v4.11.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84= +github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZMPRZwes7CROmyNKgQzC3XPs6L/G2EJLHddWejkmf4= github.com/fastly/go-utils v0.0.0-20180712184237-d95a45783239/go.mod h1:Gdwt2ce0yfBxPvZrHkprdPPTTS3N5rwmLE8T22KBXlw= github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= +github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/flowstack/go-jsonschema v0.1.1/go.mod h1:yL7fNggx1o8rm9RlgXv7hTBWxdBM0rVwpMwimd3F3N0= github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= +github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= +github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI= +github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= github.com/fsouza/fake-gcs-server v1.7.0/go.mod h1:5XIRs4YvwNbNoz+1JF8j6KLAyDh7RHGAyAK3EP2EsNk= github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= github.com/garyburd/redigo v1.6.0 h1:0VruCpn7yAIIu7pWVClQC8wxCJEcG3nyzpMSHKi1PQc= github.com/garyburd/redigo v1.6.0/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= +github.com/getkin/kin-openapi v0.76.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg= +github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ= github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= @@ -277,12 +348,13 @@ github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= github.com/go-logr/logr v0.3.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= -github.com/go-logr/logr v0.4.0 h1:K7/B1jt6fIBQVd4Owv2MqGQClcgf0R266+7C/QjRcLc= -github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= +github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= +github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/zapr v0.1.0/go.mod h1:tabnROwaDl0UNxkVeFRbY8bwB37GwRv0P8lg6aAiEnk= github.com/go-logr/zapr v0.2.0/go.mod h1:qhKdvif7YF5GI9NWEpyxTSSBdGmzkNguibrdCNVPunU= -github.com/go-logr/zapr v0.4.0 h1:uc1uML3hRYL9/ZZPdgHS/n8Nzo+eaYL/Efxkkamf7OM= -github.com/go-logr/zapr v0.4.0/go.mod h1:tabnROwaDl0UNxkVeFRbY8bwB37GwRv0P8lg6aAiEnk= +github.com/go-logr/zapr v1.2.0 h1:n4JnPI1T3Qq1SFEi/F8rwLrZERp2bso19PJZDB9dayk= +github.com/go-logr/zapr v1.2.0/go.mod h1:Qa4Bsj2Vb+FAVeAKsLD8RLQ+YRJB8YDmOAKxaBQf7Ro= github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI= github.com/go-openapi/analysis v0.17.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= github.com/go-openapi/analysis v0.18.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= @@ -296,11 +368,15 @@ github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwds github.com/go-openapi/jsonpointer v0.18.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= +github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= github.com/go-openapi/jsonreference v0.18.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= +github.com/go-openapi/jsonreference v0.19.5 h1:1WJP/wi4OjB4iV8KVbH73rQaoialJrqv8gitZLxGLtM= +github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg= github.com/go-openapi/loads v0.17.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= github.com/go-openapi/loads v0.18.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= github.com/go-openapi/loads v0.19.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= @@ -315,7 +391,6 @@ github.com/go-openapi/spec v0.18.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsd github.com/go-openapi/spec v0.19.2/go.mod h1:sCxk3jxKgioEJikev4fgkNmwS+3kuYdJtcsZsD5zxMY= github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= github.com/go-openapi/spec v0.19.4/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= -github.com/go-openapi/spec v0.19.5/go.mod h1:Hm2Jr4jv8G1ciIAo+frC/Ft+rR2kQDh8JHKHb3gWUSk= github.com/go-openapi/strfmt v0.17.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= github.com/go-openapi/strfmt v0.18.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= github.com/go-openapi/strfmt v0.19.0/go.mod h1:+uW+93UVvGGq2qGaZxdDeJqSAqBqBdl+ZPMF/cC8nDY= @@ -325,6 +400,8 @@ github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/ github.com/go-openapi/swag v0.18.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.14 h1:gm3vOOXfiuw5i9p5N9xJvfjvuofpyvLA9Wr6QfK5Fng= +github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4= github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2KDnRCRMUi7GTA= github.com/go-openapi/validate v0.19.5/go.mod h1:8DJv2CVJQ6kGNpFW6eV9N3JviE1C85nY1c2z52x1Gk4= @@ -333,7 +410,6 @@ github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+ github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= -github.com/gobuffalo/flect v0.1.5/go.mod h1:W3K3X9ksuZfir8f/LrfVtWmCDQFfayuylOJ7sz/Fj80= github.com/gobuffalo/flect v0.2.0/go.mod h1:W3K3X9ksuZfir8f/LrfVtWmCDQFfayuylOJ7sz/Fj80= github.com/gobuffalo/flect v0.2.1 h1:GPoRjEN0QObosV4XwuoWvSd5uSiL0N3e91/xqyY4crQ= github.com/gobuffalo/flect v0.2.1/go.mod h1:vmkQwuZYhN5Pc4ljYQZzP+1sq+NEkK+lh20jmEmX3jc= @@ -341,6 +417,7 @@ github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJA github.com/goccy/go-yaml v1.8.1/go.mod h1:wS4gNoLalDSJxo/SpngzPQ2BN4uuZVLCmbM4S3vd4+Y= github.com/gocql/gocql v0.0.0-20190301043612-f6df8288f9b4/go.mod h1:4Fw1eo5iaEhDUs8XyuhSVCVy52Jq3L+/3GJgYkwc+/0= github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofrs/flock v0.7.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= github.com/gofrs/uuid v3.3.0+incompatible h1:8K4tyRfvU1CYPgJsveYFQMhpFd/wXNM7iK6rR7UHz84= github.com/gofrs/uuid v3.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= @@ -349,23 +426,30 @@ github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69 github.com/golang-migrate/migrate/v4 v4.6.2 h1:LDDOHo/q1W5UDj6PbkxdCv7lv9yunyZHXvxuwDkGo3k= github.com/golang-migrate/migrate/v4 v4.6.2/go.mod h1:JYi6reN3+Z734VZ0akNuyOJNcrg45ZL7LDBMW3WGJL0= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY= 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.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/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.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= 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= @@ -375,25 +459,39 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golangplus/bytes v0.0.0-20160111154220-45c989fe5450/go.mod h1:Bk6SMAONeMXrxql8uvOKuAZSu8aM5RUGv+1C6IJaEho= github.com/golangplus/fmt v0.0.0-20150411045040-2a5d6d7d2995/go.mod h1:lJgMEyOkYFkPcDKwRXegd+iM6E7matEszMG5HhwytU8= github.com/golangplus/testing v0.0.0-20180327235837-af21d9c3145e/go.mod h1:0AA//k/eakGydO4jKRoRL2j92ZKSzTgj9tclaCrvXHk= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= +github.com/google/cel-go v0.10.1/go.mod h1:U7ayypeSkw23szu4GaQTPJGx66c20mx8JklMSxrmI1w= +github.com/google/cel-spec v0.6.0/go.mod h1:Nwjgxy5CbjlPrtCWjeDjUyKMl8w41YBYGjsyDdqk0xA= +github.com/google/gnostic v0.5.7-v3refs/go.mod h1:73MKFl6jIHelAJNaBGFzt3SPtZULs9dYrGFt8OiIsHQ= +github.com/google/gnostic v0.6.9 h1:ZK/5VhkoX835RikCHpSUJV9a+S3e1zLh59YnyWeBW+0= +github.com/google/gnostic v0.6.9/go.mod h1:Nm8234We1lq6iB9OmlgNv3nH91XLLVZHCDayfA3xq+E= 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/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.4.1/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.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.3/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 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= @@ -401,11 +499,24 @@ github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/ github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -413,13 +524,16 @@ github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= +github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= +github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM= +github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM= github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= github.com/googleapis/gnostic v0.1.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= github.com/googleapis/gnostic v0.3.1/go.mod h1:on+2t9HRStVgn95RSsFWFz+6Q0Snyqv1awfrALZdbtU= github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU= -github.com/googleapis/gnostic v0.5.5 h1:9fHAtK0uDfpveeqqo1hkEZJcFvYXAiCN3UutL8F9xHw= -github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA= +github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= @@ -428,8 +542,9 @@ github.com/gorilla/handlers v1.4.2 h1:0QniY0USkHQ1RGCLfKxeNHK9bkDHGRYGNDFBCS+YAR github.com/gorilla/handlers v1.4.2/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.7.1/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= -github.com/gorilla/mux v1.7.2 h1:zoNxOV7WjqXptQOVngLmcSQgXmgk4NMz1HibBchjl/I= github.com/gorilla/mux v1.7.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= +github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= @@ -437,9 +552,11 @@ github.com/gosuri/uitable v0.0.4/go.mod h1:tKR86bXuXPZazfOTG1FIzvjIdXzd0mo4Vtn16 github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/grpc-ecosystem/grpc-health-probe v0.3.2/go.mod h1:izVOQ4RWbjUR6lm4nn+VLJyQ+FyaiGmprEYgI04Gs7U= github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= @@ -459,8 +576,8 @@ github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/b github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= @@ -470,11 +587,11 @@ github.com/hokaccha/go-prettyjson v0.0.0-20190818114111-108c894c2c0e/go.mod h1:p github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huandu/xstrings v1.2.0/go.mod h1:DvyZB1rfVYsBIigL8HwpZgxHwXozlTgGqn63UyNX5k4= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.7/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= -github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.10/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= @@ -486,6 +603,8 @@ github.com/itchyny/go-flags v1.5.0/go.mod h1:lenkYuCobuxLBAd/HGFE4LRoW8D3B6iXRQf github.com/itchyny/gojq v0.11.0/go.mod h1:my6D2qN2Sm6qa+/5GsPDUZlCWGR+U8Qsa9he76sudv0= github.com/jackc/fake v0.0.0-20150926172116-812a484cc733/go.mod h1:WrMFNQdiFJ80sQsxDoMokWK1W5TQtxBFNpzWTD84ibQ= github.com/jackc/pgx v3.2.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I= +github.com/jaegertracing/jaeger-operator v1.36.0 h1:dtzmxvtO4ipR85W0/x8sxLNL2NnAip5OLmVvpK3yFNE= +github.com/jaegertracing/jaeger-operator v1.36.0/go.mod h1:PU9SDt8Krj/hZ4KqlsGNHfsbjt3bnrF+Cm4ztQeGdjs= github.com/jehiah/go-strftime v0.0.0-20171201141054-1d33003b3869/go.mod h1:cJ6Cj7dQo+O6GJNiMx+Pa94qKj+TG8ONdKHgMNIyyag= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= @@ -493,14 +612,18 @@ github.com/jmespath/go-jmespath v0.0.0-20160803190731-bd40a432e4c7/go.mod h1:Nht github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/joefitzgerald/rainbow-reporter v0.1.0/go.mod h1:481CNgqmVHQZzdIbN52CupLJyoVwB10FQ/IQlF1pdL8= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.11 h1:uVUAXhF2To8cbw/3xN3pxj6kk7TYKs98NIrTqPlMWAQ= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= @@ -514,9 +637,11 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= @@ -532,12 +657,16 @@ github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9 github.com/lithammer/dedent v1.1.0/go.mod h1:jrXYCQtgg0nJiN+StA2KgR7w6CiQNv9Fd/Z9BP0jIOc= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo= +github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= +github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA= +github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= @@ -574,24 +703,29 @@ github.com/mitchellh/hashstructure v1.0.0/go.mod h1:QjSHrPWS+BGUVBYkbTZWEnOh3G1D github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f/go.mod h1:OkQIRizQZAeMln+1tSwduZz7+Af5oFlKirV/MSYes2A= github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= github.com/moby/term v0.0.0-20200312100748-672ec06f55cd/go.mod h1:DdlQx2hp0Ss5/fLikoLlEeIYiATotOjgB//nb973jeo= -github.com/moby/term v0.0.0-20201216013528-df9cb8a40635/go.mod h1:FBS0z0QWA44HXygs7VXDUOGoN/1TV3RuWkLO04am3wc= +github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6/go.mod h1:E2VnQOmVuvZB6UYnnDB0qG5Nq/1tD9acaOpo6xmt0Kw= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180320133207-05fbef0ca5da/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +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/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +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/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= @@ -613,9 +747,11 @@ github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+ github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/ginkgo v1.14.1/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= -github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= -github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= +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.1.4 h1:GNapqRSid3zijZ9H77KrgVG4/8KqiyRsxcSxe+7ApXY= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= @@ -625,8 +761,8 @@ github.com/onsi/gomega v1.8.1/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoT github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.10.2/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.14.0 h1:ep6kpPVwmr/nTbklSx2nrLNSIO62DoYAhnPNIMhK8gI= -github.com/onsi/gomega v1.14.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+tEHG0= +github.com/onsi/gomega v1.19.0 h1:4ieX6qQjPP/BfC3mpsAtIGGlxTWPeA3Inl/7DtXw1tw= +github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v1.0.0-rc1 h1:WzifXhOVOEOuFYOJAW6aQqW0TooG2iki3E3Ii+WN7gQ= @@ -644,6 +780,9 @@ github.com/openshift/api v0.0.0-20200326152221-912866ddb162/go.mod h1:RKMJ5CBnlj github.com/openshift/api v0.0.0-20200331152225-585af27e34fd/go.mod h1:RKMJ5CBnljLfnej+BJ/xnOWc3kZDvJUaIAEq2oKSPtE= github.com/openshift/build-machinery-go v0.0.0-20200211121458-5e3d6e570160/go.mod h1:1CkcsT3aVebzRBzVTSbiKSkJMsC/CASqxesfqEMfJEc= github.com/openshift/client-go v0.0.0-20200326155132-2a6cd50aedd0/go.mod h1:uUQ4LClRO+fg5MF/P6QxjMCb1C9f7Oh4RKepftDnEJE= +github.com/openshift/elasticsearch-operator v0.0.0-20220708171007-a87102296ded h1:TJJaeg/XIFV0Vr25vjAZISU/kMr5QUKk3vBLXLhmRQE= +github.com/openshift/elasticsearch-operator v0.0.0-20220708171007-a87102296ded/go.mod h1:6dxhWPY3Wr/0b0eGrFpV7gcyeS+ne48Mo9OQ9dxrLNI= +github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= github.com/operator-framework/api v0.3.7-0.20200602203552-431198de9fc2/go.mod h1:Xbje9x0SHmh0nihE21kpesB38vk3cyxnE6JdDS8Jo1Q= github.com/operator-framework/api v0.3.20/go.mod h1:Xbje9x0SHmh0nihE21kpesB38vk3cyxnE6JdDS8Jo1Q= @@ -663,6 +802,10 @@ github.com/pbnjay/strptime v0.0.0-20140226051138-5c05b0d668c9/go.mod h1:6Hr+C/ol github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.6.0/go.mod h1:5N711Q9dKgbdkxHL+MEfF31hpT7l0S0s/t2kKREewys= +github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= +github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/pelletier/go-toml/v2 v2.0.1 h1:8e3L2cCQzLFi2CR4g7vGFuFxX7Jl1kKX8gW+iV0GUKU= +github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2 h1:JhzVVoYvbOACxoUmOs6V/G4D5nPVUW73rKvXxP4XUJc= github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= @@ -673,6 +816,8 @@ github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pkg/errors v0.9.0/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/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= +github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -687,8 +832,9 @@ github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQ github.com/prometheus/client_golang v1.2.1/go.mod h1:XMU6Z2MjaRKVu/dC1qupJI9SiNkDYzz3xecMgSW/F+U= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_golang v1.11.1 h1:+4eQaD7vAZ6DsfsxB15hbE0odUjGI5ARs9yskGu1v4s= -github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= +github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= +github.com/prometheus/client_golang v1.12.2 h1:51L9cDoUHVrXx4zWYlcLQIZ+d+VXHgqnYKkIuq4g/34= +github.com/prometheus/client_golang v1.12.2/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= @@ -704,8 +850,9 @@ github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y8 github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= -github.com/prometheus/common v0.26.0 h1:iMAkS2TDoNWnKM+Kopnx/8tnEStIfpYA0ur0xQzzhMQ= github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= +github.com/prometheus/common v0.32.1 h1:hWIdL3N2HoUx3B8j3YN9mWor0qhY/NlEKZEaXxuIRh4= +github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= @@ -714,18 +861,21 @@ github.com/prometheus/procfs v0.0.0-20190522114515-bc1a522cf7b1/go.mod h1:TjEm7z github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= -github.com/prometheus/procfs v0.0.11/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= -github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU= +github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/sclevine/spec v1.2.0/go.mod h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24q7p+U= @@ -738,25 +888,37 @@ github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= -github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= +github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= +github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= +github.com/spf13/afero v1.8.2 h1:xehSyVa0YnHWsJ49JFljMpg1HX19V6NDZ1fkm1Xznbo= +github.com/spf13/afero v1.8.2/go.mod h1:CtAatgMJh6bJEIs48Ay/FOnkljP3WeGUG0MC1RfAqwo= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= +github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= github.com/spf13/cobra v0.0.6/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= github.com/spf13/cobra v0.0.7/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= -github.com/spf13/cobra v1.1.1 h1:KfztREH0tPxJJ+geloSLaAkaPkr4ki2Er5quFV1TDo4= github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI= +github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo= +github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g= +github.com/spf13/cobra v1.5.0 h1:X+jTBEBqF0bHN+9cSMgmfuvv2VHJ9ezmFNf9Y/XstYU= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= +github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.1-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= @@ -766,6 +928,8 @@ github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= +github.com/spf13/viper v1.12.0 h1:CZ7eSOd3kZoaYDLbXnmzgQI5RlciuXBMA+18HwHRfZQ= +github.com/spf13/viper v1.12.0/go.mod h1:b6COn30jlNxbm/V2IqWiNWkJ+vZNiMNksliPCiuKtSI= github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -777,15 +941,19 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P github.com/stretchr/testify v1.5.0/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= 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.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +github.com/subosito/gotenv v1.3.0 h1:mjC+YW8QpAdXibNi+vNWgzmgBH4+5l5dCXv8cNysBLI= +github.com/subosito/gotenv v1.3.0/go.mod h1:YzJjq/33h7nrwdY+iHMhEOEEbW0ovIz0tB6t6PwAXzs= github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/tebeka/strftime v0.1.3/go.mod h1:7wJm3dZlpr4l/oVK0t1HYIc4rMzQ2XJlOMIUJUJH6XQ= github.com/tidwall/pretty v0.0.0-20180105212114-65a9db5fad51/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= @@ -798,11 +966,16 @@ github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2 github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonschema v0.0.0-20180618132009-1d523034197f/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs= github.com/xeipuuv/gojsonschema v1.1.0/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs= +github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xlab/handysort v0.0.0-20150421192137-fb3537ed64a1/go.mod h1:QcJo0QPSfTONNIgpN5RA8prR7fF8nkF6cTWTcNerRO8= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/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= +github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs= github.com/yvasiyarov/go-metrics v0.0.0-20150112132944-c25f46c4b940 h1:p7OofyZ509h8DmPLh8Hn+EIIZm/xYhdZHJ9GnXHdr6U= github.com/yvasiyarov/go-metrics v0.0.0-20150112132944-c25f46c4b940/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs= @@ -816,10 +989,21 @@ gitlab.com/nyarla/go-crypt v0.0.0-20160106005555-d9a5dc2b789b/go.mod h1:T3BPAOm2 go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.4/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= -go.etcd.io/bbolt v1.3.5 h1:XAzx9gjCb0Rxj7EoqcClPD1d5ZBxZJk0jbuoPHenBt0= go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= +go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU= +go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4= go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= go.etcd.io/etcd v0.5.0-alpha.5.0.20200910180754-dd1b699fc489/go.mod h1:yVHk9ub3CSBatqGNg7GRmsnfLWtoW60w4eDYfh7vHDg= +go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= +go.etcd.io/etcd/api/v3 v3.5.1/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= +go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= +go.etcd.io/etcd/client/pkg/v3 v3.5.1/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= +go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= +go.etcd.io/etcd/client/v3 v3.5.0/go.mod h1:AIKXXVX/DQXtfTEqBryiLTUXwON+GuvO6Z7lLS/oTh0= +go.etcd.io/etcd/client/v3 v3.5.1/go.mod h1:OnjH4M8OnAotwaB2l9bVgZzRFKru7/ZMoS46OtKyd3Q= +go.etcd.io/etcd/pkg/v3 v3.5.0/go.mod h1:UzJGatBQ1lXChBkQF0AuAtkRQMYnHubxAEYIrC3MSsE= +go.etcd.io/etcd/raft/v3 v3.5.0/go.mod h1:UFOHSIvO/nKwd4lhkwabrTD3cqW5yVyYYf/KlD00Szc= +go.etcd.io/etcd/server/v3 v3.5.0/go.mod h1:3Ah5ruV+M+7RZr0+Y/5mNLwC+eQlni+mQmOVdCRJoS4= go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= go.mongodb.org/mongo-driver v1.1.0/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= go.mongodb.org/mongo-driver v1.1.1/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= @@ -828,15 +1012,31 @@ go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.3 h1:8sGtKOrtQqkN1bp2AtX+misvLIlOmsEsNd+9NIcPEm8= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= +go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M= +go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= +go.opentelemetry.io/contrib v0.20.0/go.mod h1:G/EtFaa6qaN7+LxqfIAT3GiZa7Wv5DTBUzl5H4LY0Kc= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.20.0/go.mod h1:oVGt1LRbBOBq1A5BQLlUg9UaU/54aiHw8cgjV3aWZ/E= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.20.0/go.mod h1:2AboqHi0CiIZU0qwhtUfCYD1GeUzvvIXWNkhDt7ZMG4= +go.opentelemetry.io/otel v0.20.0/go.mod h1:Y3ugLH2oa81t5QO+Lty+zXf8zC9L26ax4Nzoxm/dooo= +go.opentelemetry.io/otel/exporters/otlp v0.20.0/go.mod h1:YIieizyaN77rtLJra0buKiNBOm9XQfkPEKBeuhoMwAM= +go.opentelemetry.io/otel/metric v0.20.0/go.mod h1:598I5tYlH1vzBjn+BTuhzTCSb/9debfNp6R3s7Pr1eU= +go.opentelemetry.io/otel/oteltest v0.20.0/go.mod h1:L7bgKf9ZB7qCwT9Up7i9/pn0PWIa9FqQ2IQ8LoxiGnw= +go.opentelemetry.io/otel/sdk v0.20.0/go.mod h1:g/IcepuwNsoiX5Byy2nNV0ySUF1em498m7hBWC279Yc= +go.opentelemetry.io/otel/sdk/export/metric v0.20.0/go.mod h1:h7RBNMsDJ5pmI1zExLi+bJK+Dr8NQCh0qGhm1KDnNlE= +go.opentelemetry.io/otel/sdk/metric v0.20.0/go.mod h1:knxiS8Xd4E/N+ZqKmUPf3gTTZ4/0TjTXukfxjzSTpHE= +go.opentelemetry.io/otel/trace v0.20.0/go.mod h1:6GjCW8zgDjwGHGa6GkyeB8+/5vjT16gUEi0Nf1iBdgw= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/goleak v1.1.10 h1:z+mqJhf6ss6BSfSM671tgKyZBFPTTJM+HLxnhPC3wu0= go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= +go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= +go.uber.org/goleak v1.1.12 h1:gZAh5/EyT/HQwlpkCy6wTpqfH9H8Lz8zbm3dZh+OyzA= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= @@ -845,8 +1045,10 @@ go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9E go.uber.org/zap v1.8.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= -go.uber.org/zap v1.18.1 h1:CSUJ2mjFszzEWt4CdKISEuChVIXGBn3lAPwkRGyVrc4= -go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= +go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= +go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= +go.uber.org/zap v1.19.1 h1:ue41HOKd1vGURxrmeKIgELGb3jPW9DMUDGtsinblHwI= +go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -867,7 +1069,10 @@ golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -891,8 +1096,9 @@ golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= @@ -901,7 +1107,10 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= 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.3.1-0.20200828183125-ce943fd02449/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.1/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.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= golang.org/x/mod v0.7.0 h1:LapD9S96VoQRhi/GrNTqeBJFrUjs5UHCAtTlgwA5oZA= golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -942,31 +1151,70 @@ golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20210224082022-3d97a244fca7/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= -golang.org/x/net v0.0.0-20211209124913-491a49abca63 h1:iocB37TsdFuN6IBRZ+ry36wrkoV51/tl5vOWqkcPGvY= -golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210825183410-e898025ed96a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d h1:TzXSXBo42m9gQenoE3b9BGiEpg5IG2JkU5FkPIawgtw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5 h1:OSnWWcOd/CtWQC2cYSBgbTSJv3ciqd8r54ySIW2y3RE= +golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/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-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/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-20201207232520-09787c993a3a h1:DcqTD9SDLc+1P/r1EmRBwnVsrOwW+kk2vWf9n+1sGhs= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1019,28 +1267,63 @@ golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201112073958-5cba982894dd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f h1:v4INt8xihDGvnrfjMDVXGxw9wrfxYyCjk0KbXjhR55s= -golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= +golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d h1:SZxvLBoTP5yHO3Frd4z4vrF+DBX9vMVanchswa69toE= -golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0 h1:n2a8QNdAb0sZNpU9R1ALUXBbY+w51fCQDN+7EdxNBsY= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1048,17 +1331,19 @@ golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3 golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.8 h1:nAL+RVCQ9uMn3vJZbV+MRnydTJFPf8qqY42YiA6MrqY= -golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac h1:7zkz7BUtwNFFqcowJ+RIgu2MaV/MapERkDIy+mwPyjs= -golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 h1:vVKdlvoWBphwdxWKrFZEuM0kGgGLxUOYcY4U/2Vjg44= +golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -1106,21 +1391,42 @@ golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapK golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= golang.org/x/tools v0.0.0-20200403190813-44a64ad78b9b/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200616133436-c1934b75d054/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200616195046-dc31b401abb5/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= +golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= -golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU= +golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.10-0.20220218145154-897bd77cd717/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gomodules.xyz/jsonpatch/v2 v2.0.1/go.mod h1:IhYNNY4jnS53ZnfE4PAmpKtDpTCj1JFXc+3mwe7XcUU= gomodules.xyz/jsonpatch/v2 v2.1.0/go.mod h1:IhYNNY4jnS53ZnfE4PAmpKtDpTCj1JFXc+3mwe7XcUU= gomodules.xyz/jsonpatch/v2 v2.2.0 h1:4pT439QV83L+G9FkcCriY6EkpcK6r6bK+A5FBUMI7qY= @@ -1140,7 +1446,33 @@ google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsb google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= +google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= +google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= +google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= +google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= +google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= +google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= +google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= +google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= +google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= +google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= +google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= +google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo= +google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g= +google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA= +google.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8= +google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRRyDs= +google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -1171,12 +1503,70 @@ google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvx google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= google.golang.org/genproto v0.0.0-20200701001935-0939c5918c31/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a h1:pOwg4OoaRYScjmR4LlLgdtnyoHYTSAVhhqe5uPdpII8= +google.golang.org/genproto v0.0.0-20201102152239-715cce707fb0/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= +google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= +google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= +google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220107163113-42d7afdf6368/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= +google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220413183235-5e96e2839df9/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220519153652-3a47de7e79bd h1:e0TwkXOdbnH/1x5rc5MZ/VYyiZ4v+RdVfrGMqEwT68I= +google.golang.org/genproto v0.0.0-20220519153652-3a47de7e79bd/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= @@ -1190,9 +1580,31 @@ google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQ google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.30.0 h1:M5a8xTlYTxwMn5ZFkwhRabsygDY5G8TYLyQDBxJNAxE= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= +google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= +google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.48.0 h1:rQOsyJ/8+ufEDJd/Gdsz7HG220Mh9HAhFHRGnIjda0w= +google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= google.golang.org/grpc/cmd/protoc-gen-go-grpc v0.0.0-20200709232328-d8193ee9cc3e/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= +google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= 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= @@ -1204,8 +1616,10 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -1224,6 +1638,8 @@ gopkg.in/imdario/mergo.v0 v0.3.7/go.mod h1:9qPP6AGrlC1G2PTNXko614FwGZvorN7MiBU0E gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.66.4 h1:SsAcf+mM7mRZo2nJNGt8mZCjG8ZRaNGMURJw7BsIST4= +gopkg.in/ini.v1 v1.66.4/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= gopkg.in/op/go-logging.v1 v1.0.0-20160211212156-b2cb9fa56473/go.mod h1:N1eN2tsCx0Ydtgjl4cqmbRCsY4/+z4cYDeqwZTk6zog= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= @@ -1233,6 +1649,7 @@ gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWD gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -1245,8 +1662,9 @@ gopkg.in/yaml.v3 v3.0.0-20191120175047-4206685974f2/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/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= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8= @@ -1258,71 +1676,65 @@ honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= k8s.io/api v0.17.2/go.mod h1:BS9fjjLc4CMuqfSO8vgbHPKMt5+SF0ET6u/RVDihTo4= k8s.io/api v0.18.0/go.mod h1:q2HRQkfDzHMBZL9l/y9rH63PkQl4vae0xRT+8prbrK8= k8s.io/api v0.18.2/go.mod h1:SJCWI7OLzhZSvbY7U8zwNl9UA4o1fizoug34OV/2r78= -k8s.io/api v0.18.6/go.mod h1:eeyxr+cwCjMdLAmr2W3RyDI0VvTawSg/3RFFBEnmZGI= k8s.io/api v0.18.9/go.mod h1:9u/h6sUh6FxfErv7QqetX1EB3yBMIYOBXzdcf0Gf0rc= k8s.io/api v0.20.1/go.mod h1:KqwcCVogGxQY3nBlRpwt+wpAMF/KjaCc7RpywacvqUo= -k8s.io/api v0.20.5/go.mod h1:FQjAceXnVaWDeov2YUWhOb6Yt+5UjErkp6UO3nczO1Y= -k8s.io/api v0.21.3 h1:cblWILbLO8ar+Fj6xdDGr603HRsf8Wu9E9rngJeprZQ= -k8s.io/api v0.21.3/go.mod h1:hUgeYHUbBp23Ue4qdX9tR8/ANi/g3ehylAqDn9NWVOg= +k8s.io/api v0.24.2/go.mod h1:AHqbSkTm6YrQ0ObxjO3Pmp/ubFF/KuM7jU+3khoBsOg= +k8s.io/api v0.24.3 h1:tt55QEmKd6L2k5DP6G/ZzdMQKvG5ro4H4teClqm0sTY= +k8s.io/api v0.24.3/go.mod h1:elGR/XSZrS7z7cSZPzVWaycpJuGIw57j9b95/1PdJNI= k8s.io/apiextensions-apiserver v0.17.2/go.mod h1:4KdMpjkEjjDI2pPfBA15OscyNldHWdBCfsWMDWAmSTs= k8s.io/apiextensions-apiserver v0.18.2/go.mod h1:q3faSnRGmYimiocj6cHQ1I3WpLqmDgJFlKL37fC4ZvY= -k8s.io/apiextensions-apiserver v0.18.6/go.mod h1:lv89S7fUysXjLZO7ke783xOwVTm6lKizADfvUM/SS/M= k8s.io/apiextensions-apiserver v0.18.9/go.mod h1:JagmAhU0TVENzgUZqHJsjCSDh7YuV5o6g01G1Fwh7zI= k8s.io/apiextensions-apiserver v0.20.1/go.mod h1:ntnrZV+6a3dB504qwC5PN/Yg9PBiDNt1EVqbW2kORVk= -k8s.io/apiextensions-apiserver v0.21.3 h1:+B6biyUWpqt41kz5x6peIsljlsuwvNAp/oFax/j2/aY= -k8s.io/apiextensions-apiserver v0.21.3/go.mod h1:kl6dap3Gd45+21Jnh6utCx8Z2xxLm8LGDkprcd+KbsE= +k8s.io/apiextensions-apiserver v0.24.2 h1:/4NEQHKlEz1MlaK/wHT5KMKC9UKYz6NZz6JE6ov4G6k= +k8s.io/apiextensions-apiserver v0.24.2/go.mod h1:e5t2GMFVngUEHUd0wuCJzw8YDwZoqZfJiGOW6mm2hLQ= k8s.io/apimachinery v0.17.0/go.mod h1:b9qmWdKlLuU9EBh+06BtLcSf/Mu89rWL33naRxs1uZg= k8s.io/apimachinery v0.17.2/go.mod h1:b9qmWdKlLuU9EBh+06BtLcSf/Mu89rWL33naRxs1uZg= k8s.io/apimachinery v0.18.0/go.mod h1:9SnR/e11v5IbyPCGbvJViimtJ0SwHG4nfZFjU77ftcA= k8s.io/apimachinery v0.18.2/go.mod h1:9SnR/e11v5IbyPCGbvJViimtJ0SwHG4nfZFjU77ftcA= -k8s.io/apimachinery v0.18.6/go.mod h1:OaXp26zu/5J7p0f92ASynJa1pZo06YlV9fG7BoWbCko= k8s.io/apimachinery v0.18.9/go.mod h1:PF5taHbXgTEJLU+xMypMmYTXTWPJ5LaW8bfsisxnEXk= k8s.io/apimachinery v0.20.1/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= -k8s.io/apimachinery v0.20.5/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= -k8s.io/apimachinery v0.21.3/go.mod h1:H/IM+5vH9kZRNJ4l3x/fXP/5bOPJaVP/guptnZPeCFI= -k8s.io/apimachinery v0.21.14 h1:tC5klgLnEkSqcS4qJdKP+Cmm8gVdaY9Hu31+ozRgv6E= -k8s.io/apimachinery v0.21.14/go.mod h1:NI5S3z6+ZZ6Da3whzPF+MnJCjU1NyLuTq9WnKIj5I20= +k8s.io/apimachinery v0.24.2/go.mod h1:82Bi4sCzVBdpYjyI4jY6aHX+YCUchUIrZrXKedjd2UM= +k8s.io/apimachinery v0.24.3 h1:hrFiNSA2cBZqllakVYyH/VyEh4B581bQRmqATJSeQTg= +k8s.io/apimachinery v0.24.3/go.mod h1:82Bi4sCzVBdpYjyI4jY6aHX+YCUchUIrZrXKedjd2UM= k8s.io/apiserver v0.17.2/go.mod h1:lBmw/TtQdtxvrTk0e2cgtOxHizXI+d0mmGQURIHQZlo= k8s.io/apiserver v0.18.2/go.mod h1:Xbh066NqrZO8cbsoenCwyDJ1OSi8Ag8I2lezeHxzwzw= -k8s.io/apiserver v0.18.6/go.mod h1:Zt2XvTHuaZjBz6EFYzpp+X4hTmgWGy8AthNVnTdm3Wg= k8s.io/apiserver v0.18.9/go.mod h1:vXQzMtUCLsGg1Bh+7Jo2mZKHpHZFCZn8eTNSepcIA1M= k8s.io/apiserver v0.20.1/go.mod h1:ro5QHeQkgMS7ZGpvf4tSMx6bBOgPfE+f52KwvXfScaU= -k8s.io/apiserver v0.21.3/go.mod h1:eDPWlZG6/cCCMj/JBcEpDoK+I+6i3r9GsChYBHSbAzU= +k8s.io/apiserver v0.24.2/go.mod h1:pSuKzr3zV+L+MWqsEo0kHHYwCo77AT5qXbFXP2jbvFI= k8s.io/cli-runtime v0.17.2/go.mod h1:aa8t9ziyQdbkuizkNLAw3qe3srSyWh9zlSB7zTqRNPI= k8s.io/cli-runtime v0.18.0/go.mod h1:1eXfmBsIJosjn9LjEBUd2WVPoPAY9XGTqTFcPMIBsUQ= k8s.io/client-go v0.17.2/go.mod h1:QAzRgsa0C2xl4/eVpeVAZMvikCn8Nm81yqVx3Kk9XYI= k8s.io/client-go v0.18.0/go.mod h1:uQSYDYs4WhVZ9i6AIoEZuwUggLVEF64HOD37boKAtF8= k8s.io/client-go v0.18.2/go.mod h1:Xcm5wVGXX9HAA2JJ2sSBUn3tCJ+4SVlCbl2MNNv+CIU= -k8s.io/client-go v0.18.6/go.mod h1:/fwtGLjYMS1MaM5oi+eXhKwG+1UHidUEXRh6cNsdO0Q= k8s.io/client-go v0.18.9/go.mod h1:UjkEetDmr40P9NX0Ok3Idt08FCf2I4mIHgjFsot77uY= k8s.io/client-go v0.20.1/go.mod h1:/zcHdt1TeWSd5HoUe6elJmHSQ6uLLgp4bIJHVEuy+/Y= -k8s.io/client-go v0.20.5/go.mod h1:Ee5OOMMYvlH8FCZhDsacjMlCBwetbGZETwo1OA+e6Zw= -k8s.io/client-go v0.21.3 h1:J9nxZTOmvkInRDCzcSNQmPJbDYN/PjlxXT9Mos3HcLg= -k8s.io/client-go v0.21.3/go.mod h1:+VPhCgTsaFmGILxR/7E1N0S+ryO010QBeNCv5JwRGYU= +k8s.io/client-go v0.24.2/go.mod h1:zg4Xaoo+umDsfCWr4fCnmLEtQXyCNXCvJuSsglNcV30= +k8s.io/client-go v0.24.3 h1:Nl1840+6p4JqkFWEW2LnMKU667BUxw03REfLAVhuKQY= +k8s.io/client-go v0.24.3/go.mod h1:AAovolf5Z9bY1wIg2FZ8LPQlEdKHjLI7ZD4rw920BJw= k8s.io/code-generator v0.17.2/go.mod h1:DVmfPQgxQENqDIzVR2ddLXMH34qeszkKSdH/N+s+38s= k8s.io/code-generator v0.18.0/go.mod h1:+UHX5rSbxmR8kzS+FAv7um6dtYrZokQvjHpDSYRVkTc= k8s.io/code-generator v0.18.2/go.mod h1:+UHX5rSbxmR8kzS+FAv7um6dtYrZokQvjHpDSYRVkTc= -k8s.io/code-generator v0.18.6/go.mod h1:TgNEVx9hCyPGpdtCWA34olQYLkh3ok9ar7XfSsr8b6c= k8s.io/code-generator v0.18.9/go.mod h1:TgNEVx9hCyPGpdtCWA34olQYLkh3ok9ar7XfSsr8b6c= k8s.io/code-generator v0.20.1/go.mod h1:UsqdF+VX4PU2g46NC2JRs4gc+IfrctnwHb76RNbWHJg= -k8s.io/code-generator v0.21.3/go.mod h1:K3y0Bv9Cz2cOW2vXUrNZlFbflhuPvuadW6JdnN6gGKo= +k8s.io/code-generator v0.24.2/go.mod h1:dpVhs00hTuTdTY6jvVxvTFCk6gSMrtfRydbhZwHI15w= k8s.io/component-base v0.17.2/go.mod h1:zMPW3g5aH7cHJpKYQ/ZsGMcgbsA/VyhEugF3QT1awLs= k8s.io/component-base v0.18.0/go.mod h1:u3BCg0z1uskkzrnAKFzulmYaEpZF7XC9Pf/uFyb1v2c= k8s.io/component-base v0.18.2/go.mod h1:kqLlMuhJNHQ9lz8Z7V5bxUUtjFZnrypArGl58gmDfUM= -k8s.io/component-base v0.18.6/go.mod h1:knSVsibPR5K6EW2XOjEHik6sdU5nCvKMrzMt2D4In14= k8s.io/component-base v0.18.9/go.mod h1:tUo4qZtV8m7t/U+0DgY+fcnn4BFZ480fZdzxOkWH4zk= k8s.io/component-base v0.20.1/go.mod h1:guxkoJnNoh8LNrbtiQOlyp2Y2XFCZQmrcg2n/DeYNLk= -k8s.io/component-base v0.21.3 h1:4WuuXY3Npa+iFfi2aDRiOz+anhNvRfye0859ZgfC5Og= -k8s.io/component-base v0.21.3/go.mod h1:kkuhtfEHeZM6LkX0saqSK8PbdO7A0HigUngmhhrwfGQ= +k8s.io/component-base v0.24.2 h1:kwpQdoSfbcH+8MPN4tALtajLDfSfYxBDYlXobNWI6OU= +k8s.io/component-base v0.24.2/go.mod h1:ucHwW76dajvQ9B7+zecZAP3BVqvrHoOxm8olHEg0nmM= k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/gengo v0.0.0-20190822140433-26a664648505/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/gengo v0.0.0-20200114144118-36b2048a9120/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/gengo v0.0.0-20201113003025-83324d819ded/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= -k8s.io/gengo v0.0.0-20201214224949-b6c5ce23f027/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= +k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= +k8s.io/gengo v0.0.0-20211129171323-c02415ce4185/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= @@ -1330,17 +1742,16 @@ k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= k8s.io/klog/v2 v2.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= -k8s.io/klog/v2 v2.8.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= -k8s.io/klog/v2 v2.9.0 h1:D7HV+n1V57XeZ0m6tdRkfknthUaM06VFbWldOFh8kzM= -k8s.io/klog/v2 v2.9.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= +k8s.io/klog/v2 v2.60.1 h1:VW25q3bZx9uE3vvdL6M8ezOX79vA2Aq1nEWLqNQclHc= +k8s.io/klog/v2 v2.60.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= k8s.io/kube-aggregator v0.18.9/go.mod h1:ik5Mf6JaP2M9XbWZR/AYgXx2Nj4EDBrHyakUx7C8cdw= k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E= k8s.io/kube-openapi v0.0.0-20200121204235-bf4fb3bd569c/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E= k8s.io/kube-openapi v0.0.0-20200410145947-61e04a5be9a6/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E= k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd/go.mod h1:WOJ3KddDSol4tAGcJo0Tvi+dK12EcqSLqcWsryKMpfM= -k8s.io/kube-openapi v0.0.0-20210305001622-591a79e4bda7/go.mod h1:wXW5VT87nVfh/iLV8FpR2uDvrFyomxbtb1KivDbvPTE= -k8s.io/kube-openapi v0.0.0-20211110012726-3cc51fd1e909 h1:s77MRc/+/eQjsF89MB12JssAlsoi9mnNoaacRqibeAU= -k8s.io/kube-openapi v0.0.0-20211110012726-3cc51fd1e909/go.mod h1:wXW5VT87nVfh/iLV8FpR2uDvrFyomxbtb1KivDbvPTE= +k8s.io/kube-openapi v0.0.0-20220328201542-3ee0da9b0b42/go.mod h1:Z/45zLw8lUo4wdiUkI+v/ImEGAvu3WatcZl3lPMR4Rk= +k8s.io/kube-openapi v0.0.0-20220627174259-011e075b9cb8 h1:yEQKdMCjzAOvGeiTwG4hO/hNVNtDOuUFvMUZ0OlaIzs= +k8s.io/kube-openapi v0.0.0-20220627174259-011e075b9cb8/go.mod h1:mbJ+NSUoAhuR14N0S63bPkh8MGVSo3VYSGZtH/mfMe0= k8s.io/kubectl v0.17.2/go.mod h1:y4rfLV0n6aPmvbRCqZQjvOp3ezxsFgpqL+zF5jH/lxk= k8s.io/kubectl v0.18.0/go.mod h1:LOkWx9Z5DXMEg5KtOjHhRiC1fqJPLyCr3KtQgEolCkU= k8s.io/kubernetes v1.13.0/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk= @@ -1348,10 +1759,10 @@ k8s.io/metrics v0.17.2/go.mod h1:3TkNHET4ROd+NfzNxkjoVfQ0Ob4iZnaHmSEA4vYpwLw= k8s.io/metrics v0.18.0/go.mod h1:8aYTW18koXqjLVKL7Ds05RPMX9ipJZI3mywYvBOxXd4= k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= -k8s.io/utils v0.0.0-20200603063816-c1c6865ac451/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= -k8s.io/utils v0.0.0-20210722164352-7f3ee0f31471 h1:DnzUXII7sVg1FJ/4JX6YDRJfLNAC7idRatPwe07suiI= -k8s.io/utils v0.0.0-20210722164352-7f3ee0f31471/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9 h1:HNSDgDCrr/6Ly3WEGKZftiE7IY19Vz2GdbOCyI4qqhc= +k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw= modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk= modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k= @@ -1364,14 +1775,15 @@ rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.7/go.mod h1:PHgbrJT7lCHcxMU+mDHEm+nx46H4zuuHZkDP6icnhu0= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.14/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= -sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.19/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.30/go.mod h1:fEO7lRTdivWO2qYVCVG7dEADOMo/MLDCVr8So2g88Uw= sigs.k8s.io/controller-runtime v0.6.0/go.mod h1:CpYf5pdNY/B352A1TFLAS2JVSlnGQ5O2cftPHndTroo= -sigs.k8s.io/controller-runtime v0.6.2/go.mod h1:vhcq/rlnENJ09SIRp3EveTaZ0yqH526hjf9iJdbUJ/E= sigs.k8s.io/controller-runtime v0.8.0/go.mod h1:v9Lbj5oX443uR7GXYY46E0EE2o7k2YxQ58GxVNeXSW4= -sigs.k8s.io/controller-runtime v0.9.6 h1:EevVMlgUj4fC1NVM4+DB3iPkWkmGRNarA66neqv9Qew= -sigs.k8s.io/controller-runtime v0.9.6/go.mod h1:q6PpkM5vqQubEKUKOM6qr06oXGzOBcCby1DA9FbyZeA= +sigs.k8s.io/controller-runtime v0.12.3 h1:FCM8xeY/FI8hoAfh/V4XbbYMY20gElh9yh+A98usMio= +sigs.k8s.io/controller-runtime v0.12.3/go.mod h1:qKsk4WE6zW2Hfj0G4v10EnNB2jMG1C+NTb8h+DwCoU0= sigs.k8s.io/controller-tools v0.3.0/go.mod h1:enhtKGfxZD1GFEoMgP8Fdbu+uKQ/cq1/WGJhdVChfvI= sigs.k8s.io/controller-tools v0.4.1/go.mod h1:G9rHdZMVlBDocIxGkK3jHLWqcTMNvveypYJwrvYKjWU= +sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2 h1:kDi4JBNAsJWfz1aEXhO8Jg87JJaPNLh5tIzYHgStQ9Y= +sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2/go.mod h1:B+TnT182UBxE84DiCz4CVE26eOSDAeYCpfDnC2kdKMY= sigs.k8s.io/kind v0.7.0/go.mod h1:An/AbWHT6pA/Lm0Og8j3ukGhfJP3RiVN/IBU6Lo3zl8= sigs.k8s.io/kubebuilder v1.0.9-0.20200805184228-f7a3b65dd250 h1:1D9gplyencP89oP5a8Whr5mUYwcv308kaMNNBBw+dR8= sigs.k8s.io/kubebuilder v1.0.9-0.20200805184228-f7a3b65dd250/go.mod h1:lkExAOdnNf9BGrvi4lWHCMo1fa6xtENt/QVwDhWpK+c= @@ -1381,10 +1793,10 @@ sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06/go.mod h1 sigs.k8s.io/structured-merge-diff/v3 v3.0.0-20200116222232-67a7b8c61874/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= sigs.k8s.io/structured-merge-diff/v3 v3.0.0/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= -sigs.k8s.io/structured-merge-diff/v4 v4.1.2/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= sigs.k8s.io/structured-merge-diff/v4 v4.2.1 h1:bKCqE9GvQ5tiVHn5rfn1r+yao3aLQEaLzkkmAkf+A6Y= sigs.k8s.io/structured-merge-diff/v4 v4.2.1/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= -sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= +sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= +sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= vbom.ml/util v0.0.0-20160121211510-db5cfe13f5cc/go.mod h1:so/NYdZXCz+E3ZpW0uAoCj6uzU2+8OWDFv/HxUSs7kI= diff --git a/test/e2e/constants.go b/test/e2e/constants.go index c3c0d576..43524132 100644 --- a/test/e2e/constants.go +++ b/test/e2e/constants.go @@ -54,7 +54,7 @@ const ( OperandConfigCrName = "common-service" // OperandBindInfoCrName specifies the name of the custom resource of the OperandBindInfo - OperandBindInfoCrName = "jenkins-public-bindinfo" + OperandBindInfoCrName = "mongodb-public-bindinfo" // OperandRequestNamespace1 specifies the namespace of the OperandRequest OperandRequestNamespace1 = "ibm-cloudpak-1" diff --git a/test/e2e/e2e_suite_test.go b/test/e2e/e2e_suite_test.go index 9e378dbd..dc584276 100644 --- a/test/e2e/e2e_suite_test.go +++ b/test/e2e/e2e_suite_test.go @@ -21,7 +21,6 @@ import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" - "sigs.k8s.io/controller-runtime/pkg/envtest/printer" ) // These tests use Ginkgo (BDD-style Go testing framework). Refer to @@ -30,9 +29,8 @@ import ( func TestODLME2E(t *testing.T) { RegisterFailHandler(Fail) - RunSpecsWithDefaultAndCustomReporters(t, - "Operand Deployment Lifecycle Manager TestSuite", - []Reporter{printer.NewlineReporter{}}) + RunSpecs(t, + "Operand Deployment Lifecycle Manager TestSuite") } var _ = BeforeSuite(func(done Done) { diff --git a/test/e2e/helpers_test.go b/test/e2e/helpers_test.go index 275abbaa..65245ad3 100644 --- a/test/e2e/helpers_test.go +++ b/test/e2e/helpers_test.go @@ -295,8 +295,8 @@ func retrieveOperandConfig(obj client.Object, ns string) error { return nil } -// updateEtcdReplicas is used to update an OperandConfig instance -func updateEtcdReplicas(ns string) error { +// updateJaegerReplicas is used to update an OperandConfig instance +func updateJaegerStrategy(ns string) error { fmt.Println("--- UPDATE: OperandConfig Instance") con := &v1alpha1.OperandConfig{} if err := wait.PollImmediate(WaitForRetry, WaitForTimeout, func() (done bool, err error) { @@ -305,7 +305,7 @@ func updateEtcdReplicas(ns string) error { return false, client.IgnoreNotFound(err) } con.Spec.Services[0].Spec = map[string]runtime.RawExtension{ - "etcdCluster": {Raw: []byte(`{"size": 3}`)}, + "jaeger": {Raw: []byte(`{"strategy": "allinone"}`)}, } if err := k8sClient.Update(context.TODO(), con); err != nil { fmt.Println(" --- Waiting for OperandConfig instance stable ...") @@ -361,8 +361,8 @@ func retrieveOperandRegistry(obj client.Object, ns string) error { return nil } -// updateEtcdChannel is used to update the channel for the etcd operator -func updateEtcdChannel(ns string) error { +// updateJaegerChannel is used to update the channel for the jaeger operator +func updateJaegerChannel(ns string) error { fmt.Println("--- UPDATE: OperandRegistry Instance") reg := &v1alpha1.OperandRegistry{} if err := wait.PollImmediate(WaitForRetry, WaitForTimeout, func() (done bool, err error) { @@ -370,7 +370,7 @@ func updateEtcdChannel(ns string) error { if err != nil { return false, client.IgnoreNotFound(err) } - reg.Spec.Operators[0].Channel = "clusterwide-alpha" + reg.Spec.Operators[0].Channel = "stable" reg.Spec.Operators[0].InstallMode = "cluster" if err := k8sClient.Update(context.TODO(), reg); err != nil { fmt.Println(" --- Waiting for OperandRegistry instance stable ...") @@ -415,8 +415,8 @@ func checkNameSpaceandOperatorGroup(ns string) error { return nil } -// updateJenkinsScope is used to update the channel for the etcd operator -func updateJenkinsScope(ns string) error { +// updateMongodbScope is used to update the channel for the Mongodb operator +func updateMongodbScope(ns string) error { fmt.Println("--- UPDATE: OperandRegistry Instance") reg := &v1alpha1.OperandRegistry{} if err := wait.PollImmediate(WaitForRetry, WaitForTimeout, func() (done bool, err error) { @@ -488,7 +488,7 @@ func updateOperandBindInfo(ns string) (*v1alpha1.OperandBindInfo, error) { return false, err } secretCm := bi.Spec.Bindings["public"] - secretCm.Configmap = "jenkins-second-configmap" + secretCm.Configmap = "mongodb-second-configmap" bi.Spec.Bindings["public"] = secretCm if err := k8sClient.Update(context.TODO(), bi); err != nil { fmt.Println(" --- Waiting for OperandBindInfo instance stable ...") @@ -570,15 +570,15 @@ func retrieveSubscription(name, namespace string) (*olmv1alpha1.Subscription, er return obj, nil } -// retrieveJenkins is get a custom resource -func retrieveJenkins(name, namespace string) (*unstructured.Unstructured, error) { +// retrieveMongodb is get a custom resource +func retrieveMongodb(name, namespace string) (*unstructured.Unstructured, error) { obj := &unstructured.Unstructured{} - obj.SetGroupVersionKind(schema.GroupVersionKind{Group: "jenkins.io", Version: "v1alpha2", Kind: "Jenkins"}) + obj.SetGroupVersionKind(schema.GroupVersionKind{Group: "atlas.mongodb.com", Version: "v1", Kind: "AtlasDeployment"}) // Get subscription if err := wait.PollImmediate(WaitForRetry, WaitForTimeout, func() (done bool, err error) { if err = k8sClient.Get(context.TODO(), types.NamespacedName{Name: name, Namespace: namespace}, obj); err != nil { if errors.IsNotFound(err) { - fmt.Println(" --- Waiting for custom resource Jenkins created ...") + fmt.Println(" --- Waiting for custom resource AtlasDeployment created ...") return false, nil } return false, err @@ -590,15 +590,15 @@ func retrieveJenkins(name, namespace string) (*unstructured.Unstructured, error) return obj, nil } -// retrieveEtcd is get a custom resource -func retrieveEtcd(name, namespace string) (*unstructured.Unstructured, error) { +// retrieveJaeger is get a custom resource +func retrieveJaeger(name, namespace string) (*unstructured.Unstructured, error) { obj := &unstructured.Unstructured{} - obj.SetGroupVersionKind(schema.GroupVersionKind{Group: "etcd.database.coreos.com", Version: "v1beta2", Kind: "EtcdCluster"}) + obj.SetGroupVersionKind(schema.GroupVersionKind{Group: "jaegertracing.io", Version: "v1", Kind: "Jaeger"}) // Get subscription if err := wait.PollImmediate(WaitForRetry, WaitForTimeout, func() (done bool, err error) { if err = k8sClient.Get(context.TODO(), types.NamespacedName{Name: name, Namespace: namespace}, obj); err != nil { if errors.IsNotFound(err) { - fmt.Println(" --- Waiting for custom resource EtcdCluster created ...") + fmt.Println(" --- Waiting for custom resource Jaeger created ...") return false, nil } return false, err @@ -620,26 +620,26 @@ func newOperandConfigCR(name, namespace string) *v1alpha1.OperandConfig { Spec: v1alpha1.OperandConfigSpec{ Services: []v1alpha1.ConfigService{ { - Name: "etcd", + Name: "jaeger", Spec: map[string]runtime.RawExtension{ - "etcdCluster": {Raw: []byte(`{"size": 1}`)}, + "jaeger": {Raw: []byte(`{"strategy": "streaming"}`)}, }, }, { - Name: "jenkins", + Name: "mongodb-atlas-kubernetes", Spec: map[string]runtime.RawExtension{ - "jenkins": {Raw: []byte(`{"service":{"port": 8081}}`)}, + "atlasDeployment": {Raw: []byte(`{"deploymentSpec":{"name": "test-deployment"}}`)}, }, Resources: []v1alpha1.ConfigResource{ { - Name: "jenkins-configmap", + Name: "mongodb-configmap", APIVersion: "v1", Kind: "ConfigMap", Labels: map[string]string{ - "jenkins": "configmap", + "mongodb": "configmap", }, Annotations: map[string]string{ - "jenkins": "configmap", + "mongodb": "configmap", }, Data: &runtime.RawExtension{ Raw: []byte(`{"data": {"port": "8081"}}`), @@ -647,14 +647,14 @@ func newOperandConfigCR(name, namespace string) *v1alpha1.OperandConfig { Force: false, }, { - Name: "jenkins-second-configmap", + Name: "mongodb-second-configmap", APIVersion: "v1", Kind: "ConfigMap", Labels: map[string]string{ - "jenkins": "configmap", + "mongodb": "configmap", }, Annotations: map[string]string{ - "jenkins": "configmap", + "mongodb": "configmap", }, Data: &runtime.RawExtension{ Raw: []byte(`{"data": {"port": "8080"}}`), @@ -662,14 +662,14 @@ func newOperandConfigCR(name, namespace string) *v1alpha1.OperandConfig { Force: false, }, { - Name: "jenkins-secret", + Name: "mongodb-secret", APIVersion: "v1", Kind: "Secret", Labels: map[string]string{ - "jenkins": "secret", + "mongodb": "secret", }, Annotations: map[string]string{ - "jenkins": "secret", + "mongodb": "secret", }, Data: &runtime.RawExtension{ Raw: []byte(`{"type": "Opaque", "data": {"password": "UyFCXCpkJHpEc2I9", "username": "YWRtaW4="}}`), @@ -693,21 +693,21 @@ func newOperandRegistryCR(name, namespace, OperatorNamespace string) *v1alpha1.O Spec: v1alpha1.OperandRegistrySpec{ Operators: []v1alpha1.Operator{ { - Name: "etcd", + Name: "jaeger", Namespace: OperatorNamespace, SourceName: "community-operators", SourceNamespace: "openshift-marketplace", - PackageName: "etcd", - Channel: "singlenamespace-alpha", + PackageName: "jaeger", + Channel: "stable", Scope: v1alpha1.ScopePublic, }, { - Name: "jenkins", + Name: "mongodb-atlas-kubernetes", Namespace: OperatorNamespace, SourceName: "community-operators", SourceNamespace: "openshift-marketplace", - PackageName: "jenkins-operator", - Channel: "alpha", + PackageName: "mongodb-atlas-kubernetes", + Channel: "stable", }, }, }, @@ -724,21 +724,21 @@ func newOperandRegistryCRforKind(name, namespace, OperatorNamespace string) *v1a Spec: v1alpha1.OperandRegistrySpec{ Operators: []v1alpha1.Operator{ { - Name: "etcd", + Name: "jaeger", Namespace: OperatorNamespace, SourceName: "operatorhubio-catalog", SourceNamespace: "olm", - PackageName: "etcd", - Channel: "singlenamespace-alpha", + PackageName: "jaeger", + Channel: "stable", Scope: v1alpha1.ScopePublic, }, { - Name: "jenkins", + Name: "mongodb-atlas-kubernetes", Namespace: OperatorNamespace, SourceName: "operatorhubio-catalog", SourceNamespace: "olm", - PackageName: "jenkins-operator", - Channel: "alpha", + PackageName: "mongodb-atlas-kubernetes", + Channel: "stable", }, }, }, @@ -759,10 +759,10 @@ func newOperandRequestWithoutBindinfo(name, namespace, RegistryNamespace string) RegistryNamespace: RegistryNamespace, Operands: []v1alpha1.Operand{ { - Name: "etcd", + Name: "jaeger", }, { - Name: "jenkins", + Name: "mongodb-atlas-kubernetes", }, }, }, @@ -785,11 +785,11 @@ func newOperandRequestWithBindinfo(name, namespace, RegistryNamespace string) *v RegistryNamespace: RegistryNamespace, Operands: []v1alpha1.Operand{ { - Name: "jenkins", + Name: "mongodb-atlas-kubernetes", Bindings: map[string]v1alpha1.SecretConfigmap{ "public": { - Secret: "jenkins-secret", - Configmap: "jenkins-configmap", + Secret: "mongodb-secret", + Configmap: "mongodb-configmap", }, }, }, @@ -808,14 +808,14 @@ func newOperandBindInfoCR(name, namespace, RegistryNamespace string) *v1alpha1.O Namespace: namespace, }, Spec: v1alpha1.OperandBindInfoSpec{ - Operand: "jenkins", + Operand: "mongodb-atlas-kubernetes", Registry: OperandRegistryCrName, RegistryNamespace: RegistryNamespace, Bindings: map[string]v1alpha1.SecretConfigmap{ "public": { - Secret: "jenkins-secret", - Configmap: "jenkins-configmap", + Secret: "mongodb-secret", + Configmap: "mongodb-configmap", }, }, }, diff --git a/test/e2e/odlm_test.go b/test/e2e/odlm_test.go index 44d99254..dd0c74a8 100644 --- a/test/e2e/odlm_test.go +++ b/test/e2e/odlm_test.go @@ -67,19 +67,19 @@ var _ = Describe("Testing ODLM", func() { // Check if the subscription is created By("Check if the subscription is created") - sub, err := retrieveSubscription("etcd", OperatorNamespace) + sub, err := retrieveSubscription("jaeger", OperatorNamespace) Expect(err).ToNot(HaveOccurred()) Expect(sub).ToNot(BeNil()) // Check if the custom resource is created By("Check if the custom resource is created") - etcdCluster, err := retrieveEtcd("example", OperandRegistryNamespace) + JaegerCR, err := retrieveJaeger("my-jaeger", OperandRegistryNamespace) Expect(err).ToNot(HaveOccurred()) - Expect(etcdCluster).ToNot(BeNil()) + Expect(JaegerCR).ToNot(BeNil()) - // Update the Jenkins operator to the public scope - By("Update the Jenkins operator to the public scope") - err = updateJenkinsScope(OperandRegistryNamespace) + // Update the Mongodb operator to the public scope + By("Update the Mongodb operator to the public scope") + err = updateMongodbScope(OperandRegistryNamespace) Expect(err).ToNot(HaveOccurred()) // Check the status of the OperandRequest @@ -97,34 +97,34 @@ var _ = Describe("Testing ODLM", func() { // Check if the subscription is created By("Check if the subscription is created") - sub, err = retrieveSubscription("jenkins", OperatorNamespace) + sub, err = retrieveSubscription("mongodb-atlas-kubernetes", OperatorNamespace) Expect(err).ToNot(HaveOccurred()) Expect(sub).ToNot(BeNil()) // Check if the custom resource is created By("Check if the custom resource is created") - jenkins, err := retrieveJenkins("example", OperandRegistryNamespace) + mongodb, err := retrieveMongodb("my-atlas-deployment", OperandRegistryNamespace) Expect(err).ToNot(HaveOccurred()) - Expect(jenkins).ToNot(BeNil()) + Expect(mongodb).ToNot(BeNil()) // Check if the k8s resource is created By("Check if the k8s resource is created") - jenkinsConfigmap, err := retrieveConfigmap("jenkins-configmap", OperandRegistryNamespace) + mongodbConfigmap, err := retrieveConfigmap("mongodb-configmap", OperandRegistryNamespace) Expect(err).ToNot(HaveOccurred()) - Expect(jenkinsConfigmap).ToNot(BeNil()) + Expect(mongodbConfigmap).ToNot(BeNil()) // Update the OperandConfig By("Update the OperandConfig") Eventually(func() bool { - err = updateEtcdReplicas(OperandRegistryNamespace) + err = updateJaegerStrategy(OperandRegistryNamespace) if err != nil { return false } - etcdCluster, err := retrieveEtcd("example", OperandRegistryNamespace) + jaegerCR, err := retrieveJaeger("my-jaeger", OperandRegistryNamespace) if err != nil { return false } - if etcdCluster.Object["spec"].(map[string]interface{})["size"].(int64) != 3 { + if jaegerCR.Object["spec"].(map[string]interface{})["strategy"].(string) != "allinone" { return false } return true @@ -144,7 +144,7 @@ var _ = Describe("Testing ODLM", func() { By("Wait the OperandRegistry is running") reg, err = waitRegistryStatus(operatorv1alpha1.RegistryRunning) Expect(err).ToNot(HaveOccurred()) - Expect(len(reg.Status.OperatorsStatus["jenkins"].ReconcileRequests)).Should(Equal(1)) + Expect(len(reg.Status.OperatorsStatus["mongodb-atlas-kubernetes"].ReconcileRequests)).Should(Equal(1)) // Create the second OperandRequest instance By("Create the second OperandRequest instance") @@ -162,7 +162,7 @@ var _ = Describe("Testing ODLM", func() { By("Wait the OperandRegistry is running") reg, err = waitRegistryStatus(operatorv1alpha1.RegistryRunning) Expect(err).ToNot(HaveOccurred()) - Expect(len(reg.Status.OperatorsStatus["jenkins"].ReconcileRequests)).Should(Equal(2)) + Expect(len(reg.Status.OperatorsStatus["mongodb-atlas-kubernetes"].ReconcileRequests)).Should(Equal(2)) bi, err = waitBindInfoStatus(operatorv1alpha1.BindInfoCompleted, OperatorNamespace) Expect(err).ToNot(HaveOccurred()) @@ -170,11 +170,11 @@ var _ = Describe("Testing ODLM", func() { // Check if the secret and configmap are copied By("Check if the secret and configmap are copied") - sec, err := retrieveSecret("jenkins-secret", OperandRequestNamespace2) + sec, err := retrieveSecret("mongodb-secret", OperandRequestNamespace2) Expect(err).ToNot(HaveOccurred()) Expect(sec).ToNot(BeNil()) - cm, err := retrieveConfigmap("jenkins-configmap", OperandRequestNamespace2) + cm, err := retrieveConfigmap("mongodb-configmap", OperandRequestNamespace2) Expect(err).ToNot(HaveOccurred()) Expect(cm).ToNot(BeNil()) @@ -184,13 +184,13 @@ var _ = Describe("Testing ODLM", func() { Expect(err).ToNot(HaveOccurred()) Expect(cm).ToNot(BeNil()) - cm, err = retrieveConfigmap("jenkins-public-bindinfo-jenkins-second-configmap", OperandRequestNamespace1) + cm, err = retrieveConfigmap("mongodb-public-bindinfo-mongodb-second-configmap", OperandRequestNamespace1) Expect(err).ToNot(HaveOccurred()) Expect(cm).ToNot(BeNil()) // Delete the last operator and related operands from the first OperandRequest By("Delete the last operator and related operands from the first OperandRequest") - req1, err = absentOperandFromRequest(OperandRequestNamespace1, "jenkins") + req1, err = absentOperandFromRequest(OperandRequestNamespace1, "mongodb-atlas-kubernetes") Expect(err).ToNot(HaveOccurred()) Expect(len(req1.Spec.Requests[0].Operands)).Should(Equal(1)) @@ -202,11 +202,11 @@ var _ = Describe("Testing ODLM", func() { By("Check the status of the OperandRegistry") reg, err = waitRegistryStatus(operatorv1alpha1.RegistryRunning) Expect(err).ToNot(HaveOccurred()) - Expect(len(reg.Status.OperatorsStatus["jenkins"].ReconcileRequests)).Should(Equal(1)) + Expect(len(reg.Status.OperatorsStatus["mongodb-atlas-kubernetes"].ReconcileRequests)).Should(Equal(1)) // Add an operator into the first OperandRequest By("Add an operator into the first OperandRequest") - req1, err = presentOperandFromRequest(OperandRequestNamespace1, "jenkins") + req1, err = presentOperandFromRequest(OperandRequestNamespace1, "mongodb-atlas-kubernetes") Expect(err).ToNot(HaveOccurred()) Expect(len(req1.Spec.Requests[0].Operands)).Should(Equal(2)) @@ -217,7 +217,7 @@ var _ = Describe("Testing ODLM", func() { By("Check the status of the OperandRegistry") reg, err = waitRegistryStatus(operatorv1alpha1.RegistryRunning) Expect(err).ToNot(HaveOccurred()) - Expect(len(reg.Status.OperatorsStatus["jenkins"].ReconcileRequests)).Should(Equal(2)) + Expect(len(reg.Status.OperatorsStatus["mongodb-atlas-kubernetes"].ReconcileRequests)).Should(Equal(2)) // Delete the second OperandRequest By("Delete the second OperandRequest") @@ -227,7 +227,7 @@ var _ = Describe("Testing ODLM", func() { By("Check the status of the OperandRegistry") reg, err = waitRegistryStatus(operatorv1alpha1.RegistryRunning) Expect(err).ToNot(HaveOccurred()) - Expect(len(reg.Status.OperatorsStatus["jenkins"].ReconcileRequests)).Should(Equal(1)) + Expect(len(reg.Status.OperatorsStatus["mongodb-atlas-kubernetes"].ReconcileRequests)).Should(Equal(1)) // Delete the first OperandRequest By("Delete the first OperandRequest") @@ -236,12 +236,12 @@ var _ = Describe("Testing ODLM", func() { // Check if the k8s resource is deleted By("Check if the k8s resource is deleted") - err = waitConfigmapDeletion("jenkins-configmap", OperandRegistryNamespace) + err = waitConfigmapDeletion("mongodb-configmap", OperandRegistryNamespace) Expect(err).ToNot(HaveOccurred()) - // Update the channel of the etcd operator - By("Update the channel of the etcd operator") - err = updateEtcdChannel(OperandRegistryNamespace) + // Update the channel of the jaeger operator + By("Update the channel of the jaeger operator") + err = updateJaegerChannel(OperandRegistryNamespace) Expect(err).ToNot(HaveOccurred()) // Create the first OperandRequest @@ -258,7 +258,7 @@ var _ = Describe("Testing ODLM", func() { // Check if the subscription is created By("Check if the subscription is created") - sub, err = retrieveSubscription("etcd", "openshift-operators") + sub, err = retrieveSubscription("jaeger", "openshift-operators") Expect(err).ToNot(HaveOccurred()) Expect(sub).ToNot(BeNil()) diff --git a/test/e2e/utils_test.go b/test/e2e/utils_test.go index 8691b5c2..22f33429 100644 --- a/test/e2e/utils_test.go +++ b/test/e2e/utils_test.go @@ -19,7 +19,7 @@ package e2e import ( "strings" - etcdv1beta2 "github.com/coreos/etcd-operator/pkg/apis/etcd/v1beta2" + jaegerv1 "github.com/jaegertracing/jaeger-operator/apis/v1" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" olmv1 "github.com/operator-framework/api/pkg/operators/v1" @@ -70,7 +70,7 @@ func initSuite() { Expect(err).NotTo(HaveOccurred()) err = olmv1.AddToScheme(clientgoscheme.Scheme) Expect(err).NotTo(HaveOccurred()) - err = etcdv1beta2.AddToScheme(clientgoscheme.Scheme) + err = jaegerv1.AddToScheme(clientgoscheme.Scheme) Expect(err).NotTo(HaveOccurred()) k8sManager, err := ctrl.NewManager(cfg, ctrl.Options{ From d188f7c1dd9adf029a5d919ab444ce949d94b6b2 Mon Sep 17 00:00:00 2001 From: YuChen Shen <59578388+YCShen1010@users.noreply.github.com> Date: Fri, 19 May 2023 02:17:59 -0400 Subject: [PATCH 016/179] dolm annotation updated for nss operator (#925) Signed-off-by: YuChen --- ...erand-deployment-lifecycle-manager.clusterserviceversion.yaml | 1 + ...erand-deployment-lifecycle-manager.clusterserviceversion.yaml | 1 + 2 files changed, 2 insertions(+) diff --git a/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml b/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml index 2a976910..00d33db8 100644 --- a/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml +++ b/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml @@ -109,6 +109,7 @@ metadata: createdAt: "2020-11-12T17:05:48Z" description: The Operand Deployment Lifecycle Manager provides a Kubernetes CRD-based API to manage the lifecycle of operands. + nss.operator.ibm.com/managed-operators: ibm-odlm olm.skipRange: '>=1.2.0 <4.0.0' operators.operatorframework.io/builder: operator-sdk-v1.24.0 operators.operatorframework.io/project_layout: go.kubebuilder.io/v3 diff --git a/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml b/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml index 05a7b959..7b3d90f6 100644 --- a/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml +++ b/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml @@ -10,6 +10,7 @@ metadata: createdAt: "2020-11-12T17:05:48Z" description: The Operand Deployment Lifecycle Manager provides a Kubernetes CRD-based API to manage the lifecycle of operands. + nss.operator.ibm.com/managed-operators: ibm-odlm olm.skipRange: '>=1.2.0 <4.0.0' operators.operatorframework.io/builder: operator-sdk-v1.2.0 operators.operatorframework.io/project_layout: go.kubebuilder.io/v2 From 4eb3537ed6db26b2ae970ec0641bfaebcfa69858 Mon Sep 17 00:00:00 2001 From: Ben Luzarraga <31223504+bluzarraga@users.noreply.github.com> Date: Mon, 22 May 2023 23:36:02 -0500 Subject: [PATCH 017/179] update go to latest (#928) * update go to latest * Update go to 1.20.4 to match ltsr --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index ab1e43d2..496f4738 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # Build the manager binary -FROM golang:1.19.3 as builder +FROM golang:1.20.4 as builder ARG GOARCH WORKDIR /workspace From ed7754e7847ec22c1c11df41d4608c1a0591f726 Mon Sep 17 00:00:00 2001 From: Travis CI User Date: Tue, 23 May 2023 13:38:34 +0000 Subject: [PATCH 018/179] Trigger build with new base image --- base_images.json | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/base_images.json b/base_images.json index 49d22c4e..e3b115db 100644 --- a/base_images.json +++ b/base_images.json @@ -7,7 +7,7 @@ "destStage": "edge", "destNamespace": "build-images", "destImage": "ubi8", - "tag": "8.7-1112", + "tag": "8.8-854", "updatePackages": [] }, { @@ -18,7 +18,7 @@ "destStage": "edge", "destNamespace": "build-images", "destImage": "ubi8-minimal", - "tag": "8.7-1107", + "tag": "8.8-860", "updatePackages": [] }, { @@ -29,7 +29,7 @@ "destStage": "edge", "destNamespace": "build-images", "destImage": "ubi9-micro", - "tag": "9.1.0-17", + "tag": "9.2-5", "updatePackages": [] }, { @@ -40,21 +40,21 @@ "destStage": "edge", "destNamespace": "build-images", "destImage": "helm-operator", - "tag": "v1.28.0", + "tag": "v1.28.1", "updatePackages": [] }, { "imageType": "node", "sourceImage": "ubi8-minimal", - "sourceTag": "8.7-1107", + "sourceTag": "8.8-860", "destImage": "node-v18-ubi8-minimal", "nodeVersion": "18.16.0" }, { "imageType": "liberty", "sourceImage": "node-v18-ubi8-minimal", - "sourceTag": "18.16.0_8.7-1107", + "sourceTag": "18.16.0_8.8-860", "destImage": "liberty11-ubi8-minimal", - "libertyVersion": "23.0.0.3" + "libertyVersion": "23.0.0.4" } ] From 3d223ab4b1ea9f24f49717c2efcbe799c8d44521 Mon Sep 17 00:00:00 2001 From: Daniel Fan Date: Tue, 23 May 2023 15:29:03 -0400 Subject: [PATCH 019/179] manage complete tenant scope for subscriptions (#930) * manage complete tenant scope for subscriptions Signed-off-by: Daniel Fan * fix typo Signed-off-by: Daniel Fan --------- Signed-off-by: Daniel Fan --- .../operandconfig/operandconfig_controller.go | 4 +- .../operandrequest/reconcile_operand.go | 16 +- .../operandrequest/reconcile_operator.go | 175 +++++++++++++----- controllers/operator/manager.go | 41 ++-- 4 files changed, 154 insertions(+), 82 deletions(-) diff --git a/controllers/operandconfig/operandconfig_controller.go b/controllers/operandconfig/operandconfig_controller.go index d555b672..2c8ee798 100644 --- a/controllers/operandconfig/operandconfig_controller.go +++ b/controllers/operandconfig/operandconfig_controller.go @@ -128,9 +128,9 @@ func (r *Reconciler) updateStatus(ctx context.Context, instance *operatorv1alpha // Looking for the CSV namespace := r.GetOperatorNamespace(op.InstallMode, op.Namespace) - sub, err := r.GetSubscription(ctx, op.Name, namespace, op.PackageName) + sub, err := r.GetSubscription(ctx, op.Name, namespace, registryInstance.Namespace, op.PackageName) - if apierrors.IsNotFound(err) { + if sub == nil && err == nil { klog.V(3).Infof("There is no Subscription %s or %s in the namespace %s", op.Name, op.PackageName, namespace) continue } diff --git a/controllers/operandrequest/reconcile_operand.go b/controllers/operandrequest/reconcile_operand.go index 39756a0e..f8dc8878 100644 --- a/controllers/operandrequest/reconcile_operand.go +++ b/controllers/operandrequest/reconcile_operand.go @@ -83,14 +83,14 @@ func (r *Reconciler) reconcileOperand(ctx context.Context, requestInstance *oper // Looking for the CSV namespace := r.GetOperatorNamespace(opdRegistry.InstallMode, opdRegistry.Namespace) - sub, err := r.GetSubscription(ctx, operatorName, namespace, opdRegistry.PackageName) + sub, err := r.GetSubscription(ctx, operatorName, namespace, registryInstance.Namespace, opdRegistry.PackageName) - if err != nil { - if apierrors.IsNotFound(err) || sub == nil { - klog.Warningf("There is no Subscription %s or %s in the namespace %s", operatorName, opdRegistry.PackageName, namespace) - continue - } - merr.Add(errors.Wrapf(err, "failed to get the Subscription %s in the namespace %s", operatorName, namespace)) + if sub == nil && err == nil { + klog.Warningf("There is no Subscription %s or %s in the namespace %s and %s", operatorName, opdRegistry.PackageName, namespace, registryInstance.Namespace) + continue + + } else if err != nil { + merr.Add(errors.Wrapf(err, "failed to get the Subscription %s in the namespace %s and %s", operatorName, namespace, registryInstance.Namespace)) return merr } @@ -150,7 +150,7 @@ func (r *Reconciler) reconcileOperand(ctx context.Context, requestInstance *oper } if len(requestList) == 0 || !util.Contains(requestList, requestInstance.Namespace+"."+requestInstance.Name+"."+operand.Name+"/request") { - klog.V(2).Infof("Subscription %s in the namespace %s is NOT managed by %s/%s, Skip reconciling Operands", sub.Name, sub.Namespace, requestInstance.Namespace, requestInstance.Name) + klog.Infof("Subscription %s in the namespace %s is NOT managed by %s/%s, Skip reconciling Operands", sub.Name, sub.Namespace, requestInstance.Namespace, requestInstance.Name) requestInstance.SetMemberStatus(operand.Name, "", operatorv1alpha1.ServiceFailed, &r.Mutex) continue } diff --git a/controllers/operandrequest/reconcile_operator.go b/controllers/operandrequest/reconcile_operator.go index 8202004d..1a3832cd 100644 --- a/controllers/operandrequest/reconcile_operator.go +++ b/controllers/operandrequest/reconcile_operator.go @@ -155,23 +155,22 @@ func (r *Reconciler) reconcileSubscription(ctx context.Context, requestInstance // Check subscription if exist namespace := r.GetOperatorNamespace(opt.InstallMode, opt.Namespace) - sub, err := r.GetSubscription(ctx, opt.Name, namespace, opt.PackageName) + sub, err := r.GetSubscription(ctx, opt.Name, namespace, registryInstance.Namespace, opt.PackageName) - if err != nil { - if apierrors.IsNotFound(err) { - if opt.InstallMode == operatorv1alpha1.InstallModeNoop { - requestInstance.SetNoSuitableRegistryCondition(registryKey.String(), opt.Name+" is in maintenance status", operatorv1alpha1.ResourceTypeOperandRegistry, corev1.ConditionTrue, &r.Mutex) - requestInstance.SetMemberStatus(operand.Name, operatorv1alpha1.OperatorRunning, operatorv1alpha1.ServiceRunning, mu) - } else { - // Subscription does not exist, create a new one - if err = r.createSubscription(ctx, requestInstance, opt, registryKey); err != nil { - requestInstance.SetMemberStatus(opt.Name, operatorv1alpha1.OperatorFailed, "", mu) - return err - } - requestInstance.SetMemberStatus(opt.Name, operatorv1alpha1.OperatorInstalling, "", mu) + if sub == nil && err == nil { + if opt.InstallMode == operatorv1alpha1.InstallModeNoop { + requestInstance.SetNoSuitableRegistryCondition(registryKey.String(), opt.Name+" is in maintenance status", operatorv1alpha1.ResourceTypeOperandRegistry, corev1.ConditionTrue, &r.Mutex) + requestInstance.SetMemberStatus(operand.Name, operatorv1alpha1.OperatorRunning, operatorv1alpha1.ServiceRunning, mu) + } else { + // Subscription does not exist, create a new one + if err = r.createSubscription(ctx, requestInstance, opt, registryKey); err != nil { + requestInstance.SetMemberStatus(opt.Name, operatorv1alpha1.OperatorFailed, "", mu) + return err } - return nil + requestInstance.SetMemberStatus(opt.Name, operatorv1alpha1.OperatorInstalling, "", mu) } + return nil + } else if err != nil { return err } @@ -179,6 +178,33 @@ func (r *Reconciler) reconcileSubscription(ctx context.Context, requestInstance if _, ok := sub.Labels[constant.OpreqLabel]; ok { originalSub := sub.DeepCopy() var isMatchedChannel bool + var isInScope bool + + if sub.Namespace == opt.Namespace { + isInScope = true + } else { + var nsAnnoSlice []string + namespaceReg, _ := regexp.Compile(`^(.*)\.(.*)\.(.*)\/operatorNamespace`) + for anno, ns := range sub.Annotations { + if namespaceReg.MatchString(anno) { + nsAnnoSlice = append(nsAnnoSlice, ns) + } + } + if len(nsAnnoSlice) != 0 && !util.Contains(nsAnnoSlice, sub.Namespace) { + + if r.checkUninstallLabel(sub) { + klog.V(1).Infof("Operator %s has label operator.ibm.com/opreq-do-not-uninstall. Skip the uninstall", opt.Name) + return nil + } + + if err = r.deleteSubscription(ctx, requestInstance, sub); err != nil { + requestInstance.SetMemberStatus(opt.Name, operatorv1alpha1.OperatorFailed, "", mu) + return err + } + requestInstance.SetMemberStatus(opt.Name, operatorv1alpha1.OperatorUpdating, "", mu) + return nil + } + } // add annotations to existing Subscriptions for upgrade case if sub.Annotations == nil { @@ -187,6 +213,7 @@ func (r *Reconciler) reconcileSubscription(ctx context.Context, requestInstance sub.Annotations[registryKey.Namespace+"."+registryKey.Name+"/registry"] = "true" sub.Annotations[registryKey.Namespace+"."+registryKey.Name+"/config"] = "true" sub.Annotations[requestInstance.Namespace+"."+requestInstance.Name+"."+operand.Name+"/request"] = opt.Channel + sub.Annotations[requestInstance.Namespace+"."+requestInstance.Name+"."+operand.Name+"/operatorNamespace"] = namespace if opt.InstallMode == operatorv1alpha1.InstallModeNoop { isMatchedChannel = true @@ -239,7 +266,7 @@ func (r *Reconciler) reconcileSubscription(ctx context.Context, requestInstance requestInstance.SetMemberStatus(opt.Name, operatorv1alpha1.OperatorUpdating, "", mu) } - if !isMatchedChannel { + if !isMatchedChannel || !isInScope { requestInstance.SetNoConflictOperatorCondition(operand.Name, operatorv1alpha1.ResourceTypeSub, corev1.ConditionFalse, mu) requestInstance.SetMemberStatus(opt.Name, operatorv1alpha1.OperatorFailed, "", mu) } else { @@ -313,7 +340,44 @@ func (r *Reconciler) updateSubscription(ctx context.Context, cr *operatorv1alpha return nil } -func (r *Reconciler) deleteSubscription(ctx context.Context, operandName string, requestInstance *operatorv1alpha1.OperandRequest, registryInstance *operatorv1alpha1.OperandRegistry, configInstance *operatorv1alpha1.OperandConfig) error { +func (r *Reconciler) deleteSubscription(ctx context.Context, cr *operatorv1alpha1.OperandRequest, sub *olmv1alpha1.Subscription) error { + + klog.V(2).Infof("Deleting Subscription %s/%s ...", sub.Namespace, sub.Name) + + csv, err := r.GetClusterServiceVersion(ctx, sub) + // If can't get CSV, requeue the request + if err != nil { + return err + } + + if csv != nil { + klog.V(3).Info("Set Deleting Condition in the operandRequest") + cr.SetDeletingCondition(csv.Name, operatorv1alpha1.ResourceTypeCsv, corev1.ConditionTrue, &r.Mutex) + + klog.V(1).Infof("Deleting the ClusterServiceVersion, Namespace: %s, Name: %s", csv.Namespace, csv.Name) + if err := r.Delete(ctx, csv); err != nil { + cr.SetDeletingCondition(csv.Name, operatorv1alpha1.ResourceTypeCsv, corev1.ConditionFalse, &r.Mutex) + return err + } + } + + klog.V(2).Infof("Deleting the Subscription, Namespace: %s, Name: %s", sub.Namespace, sub.Name) + cr.SetDeletingCondition(sub.Name, operatorv1alpha1.ResourceTypeSub, corev1.ConditionTrue, &r.Mutex) + + if err := r.Delete(ctx, sub); err != nil { + if apierrors.IsNotFound(err) { + klog.Warningf("Subscription %s was not found in namespace %s", sub.Name, sub.Namespace) + } else { + cr.SetDeletingCondition(sub.Name, operatorv1alpha1.ResourceTypeSub, corev1.ConditionFalse, &r.Mutex) + return err + } + } + + klog.V(1).Infof("Subscription %s/%s is deleted", sub.Namespace, sub.Name) + return nil +} + +func (r *Reconciler) uninstallOperatorsAndOperands(ctx context.Context, operandName string, requestInstance *operatorv1alpha1.OperandRequest, registryInstance *operatorv1alpha1.OperandRegistry, configInstance *operatorv1alpha1.OperandConfig) error { op := registryInstance.GetOperator(operandName) if op == nil { klog.Warningf("Operand %s not found", operandName) @@ -321,12 +385,12 @@ func (r *Reconciler) deleteSubscription(ctx context.Context, operandName string, } namespace := r.GetOperatorNamespace(op.InstallMode, op.Namespace) - sub, err := r.GetSubscription(ctx, operandName, namespace, op.PackageName) - if apierrors.IsNotFound(err) { - klog.V(3).Infof("There is no Subscription %s or %s in the namespace %s", operandName, op.PackageName, namespace) + sub, err := r.GetSubscription(ctx, operandName, namespace, registryInstance.Namespace, op.PackageName) + if sub == nil && err == nil { + klog.V(3).Infof("There is no Subscription %s or %s in the namespace %s and %s", operandName, op.PackageName, namespace, registryInstance.Namespace) return nil } else if err != nil { - klog.Errorf("Failed to get Subscription %s or %s in the namespace %s", operandName, op.PackageName, namespace) + klog.Errorf("Failed to get Subscription %s or %s in the namespace %s and %s", operandName, op.PackageName, namespace, registryInstance.Namespace) return err } @@ -342,28 +406,35 @@ func (r *Reconciler) deleteSubscription(ctx context.Context, operandName string, return nil } - // remove request in annotation of subscription + // remove request info including channel and operator namespace in annotation of subscription reqName := requestInstance.ObjectMeta.Name reqNs := requestInstance.ObjectMeta.Namespace delete(sub.Annotations, reqNs+"."+reqName+"."+op.Name+"/request") - - var annoSlice []string - reg, _ := regexp.Compile(`^(.*)\.(.*)\.(.*)\/request`) - for anno := range sub.Annotations { - if reg.MatchString(anno) { - annoSlice = append(annoSlice, anno) + delete(sub.Annotations, reqNs+"."+reqName+"."+op.Name+"/operatorNamespace") + + uninstallOperatorOnly := false + var nsAnnoSlice []string + namespaceReg, _ := regexp.Compile(`^(.*)\.(.*)\.(.*)\/operatorNamespace`) + for anno, ns := range sub.Annotations { + if namespaceReg.MatchString(anno) { + nsAnnoSlice = append(nsAnnoSlice, ns) } } - if len(annoSlice) != 0 { - // remove the associated registry from annotation of subscription - if err = r.updateSubscription(ctx, requestInstance, sub); err != nil { - requestInstance.SetMemberStatus(op.Name, operatorv1alpha1.OperatorFailed, "", &r.Mutex) - return err - } - requestInstance.SetMemberStatus(op.Name, operatorv1alpha1.OperatorUpdating, "", &r.Mutex) + if len(nsAnnoSlice) != 0 { + // No OperandRequest is requesting operator in existing subscription's namespace, uninstall Operator only + if !util.Contains(nsAnnoSlice, sub.Namespace) { + uninstallOperatorOnly = true + } else { + // remove the associated request from annotation of subscription + if err = r.updateSubscription(ctx, requestInstance, sub); err != nil { + requestInstance.SetMemberStatus(op.Name, operatorv1alpha1.OperatorFailed, "", &r.Mutex) + return err + } + requestInstance.SetMemberStatus(op.Name, operatorv1alpha1.OperatorUpdating, "", &r.Mutex) - klog.V(1).Infof("Did not delete Subscription %s/%s which is requested by other OperandRequests", sub.Namespace, sub.Name) - return nil + klog.V(1).Infof("Did not delete Subscription %s/%s which is requested by other OperandRequests", sub.Namespace, sub.Name) + return nil + } } csv, err := r.GetClusterServiceVersion(ctx, sub) @@ -373,13 +444,15 @@ func (r *Reconciler) deleteSubscription(ctx context.Context, operandName string, } if csv != nil { - klog.V(2).Infof("Deleting all the Custom Resources for CSV, Namespace: %s, Name: %s", csv.Namespace, csv.Name) - if err := r.deleteAllCustomResource(ctx, csv, requestInstance, configInstance, operandName, configInstance.Namespace); err != nil { - return err - } - klog.V(2).Infof("Deleting all the k8s Resources for CSV, Namespace: %s, Name: %s", csv.Namespace, csv.Name) - if err := r.deleteAllK8sResource(ctx, configInstance, operandName, configInstance.Namespace); err != nil { - return err + if !uninstallOperatorOnly { + klog.V(2).Infof("Deleting all the Custom Resources for CSV, Namespace: %s, Name: %s", csv.Namespace, csv.Name) + if err := r.deleteAllCustomResource(ctx, csv, requestInstance, configInstance, operandName, configInstance.Namespace); err != nil { + return err + } + klog.V(2).Infof("Deleting all the k8s Resources for CSV, Namespace: %s, Name: %s", csv.Namespace, csv.Name) + if err := r.deleteAllK8sResource(ctx, configInstance, operandName, configInstance.Namespace); err != nil { + return err + } } if r.checkUninstallLabel(sub) { klog.V(1).Infof("Operator %s has label operator.ibm.com/opreq-do-not-uninstall. Skip the uninstall", op.Name) @@ -442,7 +515,7 @@ func (r *Reconciler) absentOperatorsAndOperands(ctx context.Context, requestInst wg.Add(1) go func() { defer wg.Done() - if err := r.deleteSubscription(ctx, fmt.Sprintf("%v", o), requestInstance, registryInstance, configInstance); err != nil { + if err := r.uninstallOperatorsAndOperands(ctx, fmt.Sprintf("%v", o), requestInstance, registryInstance, configInstance); err != nil { r.Mutex.Lock() defer r.Mutex.Unlock() merr.Add(err) @@ -465,7 +538,7 @@ func (r *Reconciler) absentOperatorsAndOperands(ctx context.Context, requestInst } func (r *Reconciler) getNeedDeletedOperands(requestInstance *operatorv1alpha1.OperandRequest) gset.Set { - klog.V(3).Info("Getting the operater need to be delete") + klog.V(3).Info("Getting the operator need to be delete") deployedOperands := gset.NewSet() for _, req := range requestInstance.Status.Members { deployedOperands.Add(req.Name) @@ -490,11 +563,6 @@ func (r *Reconciler) generateClusterObjects(o *operatorv1alpha1.Operator, regist labels := map[string]string{ constant.OpreqLabel: "true", } - annotations := map[string]string{ - registryKey.Namespace + "." + registryKey.Name + "/registry": "true", - registryKey.Namespace + "." + registryKey.Name + "/config": "true", - requestKey.Namespace + "." + requestKey.Name + "." + o.Name + "/request": o.Channel, - } klog.V(3).Info("Generating Namespace: ", o.Namespace) // Namespace Object @@ -517,6 +585,13 @@ func (r *Reconciler) generateClusterObjects(o *operatorv1alpha1.Operator, regist // The namespace is 'openshift-operators' when installMode is cluster namespace := r.GetOperatorNamespace(o.InstallMode, o.Namespace) + annotations := map[string]string{ + registryKey.Namespace + "." + registryKey.Name + "/registry": "true", + registryKey.Namespace + "." + registryKey.Name + "/config": "true", + requestKey.Namespace + "." + requestKey.Name + "." + o.Name + "/request": o.Channel, + requestKey.Namespace + "." + requestKey.Name + "." + o.Name + "/operatorNamespace": namespace, + } + // Subscription Object sub := &olmv1alpha1.Subscription{ ObjectMeta: metav1.ObjectMeta{ diff --git a/controllers/operator/manager.go b/controllers/operator/manager.go index 0ed67f13..ffcf02f2 100644 --- a/controllers/operator/manager.go +++ b/controllers/operator/manager.go @@ -305,36 +305,33 @@ func (m *ODLMOperator) ListOperandRequestsByConfig(ctx context.Context, key type } // GetSubscription gets Subscription by name and package name -func (m *ODLMOperator) GetSubscription(ctx context.Context, name, namespace, packageName string) (*olmv1alpha1.Subscription, error) { - klog.V(3).Infof("Fetch Subscription: %s/%s", namespace, name) - sub := &olmv1alpha1.Subscription{} - subKey := types.NamespacedName{ - Name: name, - Namespace: namespace, - } - err := m.Client.Get(ctx, subKey, sub) - if err == nil { - return sub, nil - } else if !apierrors.IsNotFound(err) { - return nil, err - } +func (m *ODLMOperator) GetSubscription(ctx context.Context, name, operatorNs, servicesNs, packageName string) (*olmv1alpha1.Subscription, error) { + klog.V(3).Infof("Fetch Subscription %s in operatorNamespace %s and servicesNamespace %s", name, operatorNs, servicesNs) - subList := &olmv1alpha1.SubscriptionList{} - if err := m.Client.List(ctx, subList, &client.ListOptions{ - Namespace: namespace, - }); err != nil { - return nil, err + tenantScope := make(map[string]struct{}) + for _, ns := range []string{operatorNs, servicesNs} { + tenantScope[ns] = struct{}{} } var subCandidates []olmv1alpha1.Subscription - for _, sub := range subList.Items { - if sub.Spec.Package == packageName { - subCandidates = append(subCandidates, sub) + for ns := range tenantScope { + subList := &olmv1alpha1.SubscriptionList{} + if err := m.Client.List(ctx, subList, &client.ListOptions{ + Namespace: ns, + }); err != nil { + return nil, err } + + for _, sub := range subList.Items { + if sub.Name == name || sub.Spec.Package == packageName { + subCandidates = append(subCandidates, sub) + } + } + } if len(subCandidates) == 0 { - return nil, err + return nil, nil } if len(subCandidates) > 1 { From 7231e25a0493c115687a884cc5b8d4057f833636 Mon Sep 17 00:00:00 2001 From: Ben Luzarraga <31223504+bluzarraga@users.noreply.github.com> Date: Fri, 26 May 2023 14:53:05 -0500 Subject: [PATCH 020/179] update packages for twistlock (#931) Signed-off-by: Ben Luzarraga --- go.mod | 4 ++-- go.sum | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index d2696251..b3b19887 100644 --- a/go.mod +++ b/go.mod @@ -16,7 +16,6 @@ require ( github.com/pkg/errors v0.9.1 golang.org/x/mod v0.7.0 k8s.io/api v0.24.3 - k8s.io/apiextensions-apiserver v0.24.2 k8s.io/apimachinery v0.24.3 k8s.io/client-go v0.24.3 k8s.io/klog v1.0.0 @@ -33,7 +32,7 @@ require ( github.com/blang/semver/v4 v4.0.0 // indirect github.com/cespare/xxhash/v2 v2.1.2 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/emicklei/go-restful/v3 v3.8.0 // indirect + github.com/emicklei/go-restful/v3 v3.10.0 // indirect github.com/evanphx/json-patch v4.12.0+incompatible // indirect github.com/fsnotify/fsnotify v1.5.4 // indirect github.com/go-logr/logr v1.2.3 // indirect @@ -94,6 +93,7 @@ require ( gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect + k8s.io/apiextensions-apiserver v0.24.2 // indirect k8s.io/component-base v0.24.2 // indirect k8s.io/klog/v2 v2.60.1 // indirect k8s.io/kube-openapi v0.0.0-20220627174259-011e075b9cb8 // indirect diff --git a/go.sum b/go.sum index 5a4facdb..41a67f1f 100644 --- a/go.sum +++ b/go.sum @@ -291,8 +291,8 @@ github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkg github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= -github.com/emicklei/go-restful/v3 v3.8.0 h1:eCZ8ulSerjdAiaNpF7GxXIE7ZCMo1moN1qX+S609eVw= -github.com/emicklei/go-restful/v3 v3.8.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/emicklei/go-restful/v3 v3.10.0 h1:X4gma4HM7hFm6WMeAsTfqA0GOfdNoCzBIkHGoRLGXuM= +github.com/emicklei/go-restful/v3 v3.10.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= From 3a69929e779dde6c3d165f04bd07cc728a34e7ea Mon Sep 17 00:00:00 2001 From: YuChen Shen <59578388+YCShen1010@users.noreply.github.com> Date: Thu, 22 Jun 2023 12:16:47 -0400 Subject: [PATCH 021/179] [ODLM] bump version to 4.1.0 (#939) Signed-off-by: YuChen --- Makefile | 2 +- ...eployment-lifecycle-manager.clusterserviceversion.yaml | 8 ++++---- ...eployment-lifecycle-manager.clusterserviceversion.yaml | 2 +- version/version.go | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Makefile b/Makefile index 93dafffb..d034817c 100644 --- a/Makefile +++ b/Makefile @@ -80,7 +80,7 @@ OPERATOR_IMAGE_NAME ?= odlm # Current Operator bundle image name BUNDLE_IMAGE_NAME ?= odlm-operator-bundle # Current Operator version -OPERATOR_VERSION ?= 4.0.0 +OPERATOR_VERSION ?= 4.1.0 # Kind cluster name KIND_CLUSTER_NAME ?= "odlm" diff --git a/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml b/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml index 00d33db8..ed11a537 100644 --- a/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml +++ b/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml @@ -110,7 +110,7 @@ metadata: description: The Operand Deployment Lifecycle Manager provides a Kubernetes CRD-based API to manage the lifecycle of operands. nss.operator.ibm.com/managed-operators: ibm-odlm - olm.skipRange: '>=1.2.0 <4.0.0' + olm.skipRange: '>=1.2.0 <4.1.0' operators.operatorframework.io/builder: operator-sdk-v1.24.0 operators.operatorframework.io/project_layout: go.kubebuilder.io/v3 repository: https://github.com/IBM/operand-deployment-lifecycle-manager @@ -120,7 +120,7 @@ metadata: operatorframework.io/arch.ppc64le: supported operatorframework.io/arch.s390x: supported operatorframework.io/os.linux: supported - name: operand-deployment-lifecycle-manager.v4.0.0 + name: operand-deployment-lifecycle-manager.v4.1.0 namespace: placeholder spec: apiservicedefinitions: {} @@ -667,6 +667,6 @@ spec: provider: name: IBM relatedImages: - - image: icr.io/cpopen/odlm:4.0.0 + - image: icr.io/cpopen/odlm:4.1.0 name: ODLM_IMAGE - version: 4.0.0 + version: 4.1.0 diff --git a/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml b/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml index 7b3d90f6..3cf05724 100644 --- a/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml +++ b/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml @@ -11,7 +11,7 @@ metadata: description: The Operand Deployment Lifecycle Manager provides a Kubernetes CRD-based API to manage the lifecycle of operands. nss.operator.ibm.com/managed-operators: ibm-odlm - olm.skipRange: '>=1.2.0 <4.0.0' + olm.skipRange: '>=1.2.0 <4.1.0' operators.operatorframework.io/builder: operator-sdk-v1.2.0 operators.operatorframework.io/project_layout: go.kubebuilder.io/v2 repository: https://github.com/IBM/operand-deployment-lifecycle-manager diff --git a/version/version.go b/version/version.go index d1b00d23..49d17667 100644 --- a/version/version.go +++ b/version/version.go @@ -17,5 +17,5 @@ package version var ( - Version = "4.0.0" + Version = "4.1.0" ) From d0605729506742aefa76ed6ab7082f5b8ebae695 Mon Sep 17 00:00:00 2001 From: YuChen Shen <59578388+YCShen1010@users.noreply.github.com> Date: Thu, 22 Jun 2023 15:58:50 -0400 Subject: [PATCH 022/179] "disconnected" annotation for assessment (#932) Signed-off-by: YuChen --- ...erand-deployment-lifecycle-manager.clusterserviceversion.yaml | 1 + ...erand-deployment-lifecycle-manager.clusterserviceversion.yaml | 1 + 2 files changed, 2 insertions(+) diff --git a/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml b/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml index ed11a537..39f97380 100644 --- a/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml +++ b/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml @@ -113,6 +113,7 @@ metadata: olm.skipRange: '>=1.2.0 <4.1.0' operators.operatorframework.io/builder: operator-sdk-v1.24.0 operators.operatorframework.io/project_layout: go.kubebuilder.io/v3 + operators.openshift.io/infrastructure-features: '["disconnected"]' repository: https://github.com/IBM/operand-deployment-lifecycle-manager support: IBM labels: diff --git a/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml b/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml index 3cf05724..5c23c88b 100644 --- a/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml +++ b/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml @@ -14,6 +14,7 @@ metadata: olm.skipRange: '>=1.2.0 <4.1.0' operators.operatorframework.io/builder: operator-sdk-v1.2.0 operators.operatorframework.io/project_layout: go.kubebuilder.io/v2 + operators.openshift.io/infrastructure-features: '["disconnected"]' repository: https://github.com/IBM/operand-deployment-lifecycle-manager support: IBM labels: From bef6fbe8997eeccd0100a235e8b5cbdc515e8663 Mon Sep 17 00:00:00 2001 From: YuChen Shen <59578388+YCShen1010@users.noreply.github.com> Date: Thu, 22 Jun 2023 15:58:57 -0400 Subject: [PATCH 023/179] Update ImagePullPolicy to IfNotPresent (#937) Signed-off-by: YuChen --- ...rand-deployment-lifecycle-manager.clusterserviceversion.yaml | 2 +- config/manager/manager.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml b/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml index 39f97380..9161b1e5 100644 --- a/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml +++ b/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml @@ -591,7 +591,7 @@ spec: fieldRef: fieldPath: metadata.annotations['olm.targetNamespaces'] image: icr.io/cpopen/odlm:latest - imagePullPolicy: Always + imagePullPolicy: IfNotPresent livenessProbe: failureThreshold: 10 httpGet: diff --git a/config/manager/manager.yaml b/config/manager/manager.yaml index c2c8ee48..cbe9adff 100644 --- a/config/manager/manager.yaml +++ b/config/manager/manager.yaml @@ -58,7 +58,7 @@ spec: fieldRef: fieldPath: metadata.annotations['olm.targetNamespaces'] image: icr.io/cpopen/odlm:latest - imagePullPolicy: Always + imagePullPolicy: IfNotPresent name: manager livenessProbe: httpGet: From 018bd4f360c501faf96a807c1f4abcc9c96ffd8c Mon Sep 17 00:00:00 2001 From: Travis CI User Date: Wed, 5 Jul 2023 13:57:20 +0000 Subject: [PATCH 024/179] Trigger build with new base image --- base_images.json | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/base_images.json b/base_images.json index e3b115db..c2a91ebd 100644 --- a/base_images.json +++ b/base_images.json @@ -7,7 +7,7 @@ "destStage": "edge", "destNamespace": "build-images", "destImage": "ubi8", - "tag": "8.8-854", + "tag": "8.8-1009", "updatePackages": [] }, { @@ -18,7 +18,7 @@ "destStage": "edge", "destNamespace": "build-images", "destImage": "ubi8-minimal", - "tag": "8.8-860", + "tag": "8.8-1014", "updatePackages": [] }, { @@ -29,7 +29,7 @@ "destStage": "edge", "destNamespace": "build-images", "destImage": "ubi9-micro", - "tag": "9.2-5", + "tag": "9.2-9", "updatePackages": [] }, { @@ -40,21 +40,21 @@ "destStage": "edge", "destNamespace": "build-images", "destImage": "helm-operator", - "tag": "v1.28.1", + "tag": "v1.30.0", "updatePackages": [] }, { "imageType": "node", "sourceImage": "ubi8-minimal", - "sourceTag": "8.8-860", + "sourceTag": "8.8-1014", "destImage": "node-v18-ubi8-minimal", - "nodeVersion": "18.16.0" + "nodeVersion": "18.16.1" }, { "imageType": "liberty", "sourceImage": "node-v18-ubi8-minimal", - "sourceTag": "18.16.0_8.8-860", + "sourceTag": "18.16.1_8.8-1014", "destImage": "liberty11-ubi8-minimal", - "libertyVersion": "23.0.0.4" + "libertyVersion": "23.0.0.5" } ] From e1b3bd24c57523241d80db62cf696f652da564dc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 6 Jul 2023 08:06:10 +0800 Subject: [PATCH 025/179] build(deps): bump google.golang.org/grpc from 1.48.0 to 1.53.0 (#942) Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.48.0 to 1.53.0. - [Release notes](https://github.com/grpc/grpc-go/releases) - [Commits](https://github.com/grpc/grpc-go/compare/v1.48.0...v1.53.0) --- updated-dependencies: - dependency-name: google.golang.org/grpc dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 15 ++++--- go.sum | 138 +++++++-------------------------------------------------- 2 files changed, 25 insertions(+), 128 deletions(-) diff --git a/go.mod b/go.mod index b3b19887..47bbe4ba 100644 --- a/go.mod +++ b/go.mod @@ -24,13 +24,14 @@ require ( ) require ( - cloud.google.com/go/compute v1.6.1 // indirect + cloud.google.com/go/compute v1.15.1 // indirect + cloud.google.com/go/compute/metadata v0.2.3 // indirect github.com/PuerkitoBio/purell v1.1.1 // indirect github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/blang/semver v3.5.1+incompatible // indirect github.com/blang/semver/v4 v4.0.0 // indirect - github.com/cespare/xxhash/v2 v2.1.2 // indirect + github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/emicklei/go-restful/v3 v3.10.0 // indirect github.com/evanphx/json-patch v4.12.0+incompatible // indirect @@ -46,7 +47,7 @@ require ( github.com/golang/protobuf v1.5.2 // indirect github.com/google/gnostic v0.6.9 // indirect github.com/google/gofuzz v1.1.0 // indirect - github.com/google/uuid v1.1.2 // indirect + github.com/google/uuid v1.3.0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/imdario/mergo v0.3.12 // indirect github.com/josharian/intern v1.0.0 // indirect @@ -78,16 +79,16 @@ require ( go.uber.org/multierr v1.6.0 // indirect go.uber.org/zap v1.19.1 // indirect golang.org/x/net v0.7.0 // indirect - golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5 // indirect + golang.org/x/oauth2 v0.4.0 // indirect golang.org/x/sys v0.5.0 // indirect golang.org/x/term v0.5.0 // indirect golang.org/x/text v0.7.0 // indirect golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto v0.0.0-20220519153652-3a47de7e79bd // indirect - google.golang.org/grpc v1.48.0 // indirect - google.golang.org/protobuf v1.28.0 // indirect + google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ini.v1 v1.66.4 // indirect gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect diff --git a/go.sum b/go.sum index 41a67f1f..05305d80 100644 --- a/go.sum +++ b/go.sum @@ -22,27 +22,16 @@ cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPT cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= -cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= -cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= -cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= -cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= -cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= -cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= -cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= -cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= -cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow= -cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM= -cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M= -cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s= -cloud.google.com/go/compute v1.6.1 h1:2sMmt8prCn7DPaG4Pmh0N3Inmc8cT8ae5k1M6VJ9Wqc= -cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU= +cloud.google.com/go/compute v1.15.1 h1:7UGq3QknM33pw5xATlpzeoomNxsacIVvTqTTvbfajmE= +cloud.google.com/go/compute v1.15.1/go.mod h1:bjjoF/NtFUrkD/urWfdHaKuOPDR5nWIs63rR+SXhcpA= +cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= +cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= @@ -170,8 +159,9 @@ github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054/go.mod h1:sGbDF6 github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.0/go.mod h1:dgIUBU3pDso/gPgZ1osOZ0iQf77oPR28Tjxl5dIMyVM= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5/go.mod h1:/iP1qXHoty45bqomnu2LM+VVyAEdWN+vtSHGlQgyxbw= 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= @@ -180,12 +170,7 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= github.com/cockroachdb/cockroach-go v0.0.0-20181001143604-e0a95dfd547c/go.mod h1:XGLbWH/ujMcbPbhZq52Nv6UrCghb1yGn//133kEsvDk= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= @@ -300,8 +285,6 @@ github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5y github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= -github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= -github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ= github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= @@ -442,7 +425,6 @@ github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= -github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/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= @@ -465,7 +447,6 @@ github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiu github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golangplus/bytes v0.0.0-20160111154220-45c989fe5450/go.mod h1:Bk6SMAONeMXrxql8uvOKuAZSu8aM5RUGv+1C6IJaEho= github.com/golangplus/fmt v0.0.0-20150411045040-2a5d6d7d2995/go.mod h1:lJgMEyOkYFkPcDKwRXegd+iM6E7matEszMG5HhwytU8= github.com/golangplus/testing v0.0.0-20180327235837-af21d9c3145e/go.mod h1:0AA//k/eakGydO4jKRoRL2j92ZKSzTgj9tclaCrvXHk= @@ -488,8 +469,6 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.3/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.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= @@ -501,7 +480,6 @@ github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/ github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= @@ -514,20 +492,14 @@ github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= -github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= -github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM= -github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM= github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= github.com/googleapis/gnostic v0.1.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= github.com/googleapis/gnostic v0.3.1/go.mod h1:on+2t9HRStVgn95RSsFWFz+6Q0Snyqv1awfrALZdbtU= @@ -1015,8 +987,8 @@ go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= -go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= +go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opentelemetry.io/contrib v0.20.0/go.mod h1:G/EtFaa6qaN7+LxqfIAT3GiZa7Wv5DTBUzl5H4LY0Kc= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.20.0/go.mod h1:oVGt1LRbBOBq1A5BQLlUg9UaU/54aiHw8cgjV3aWZ/E= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.20.0/go.mod h1:2AboqHi0CiIZU0qwhtUfCYD1GeUzvvIXWNkhDt7ZMG4= @@ -1169,16 +1141,12 @@ golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210825183410-e898025ed96a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -1195,14 +1163,9 @@ golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5 h1:OSnWWcOd/CtWQC2cYSBgbTSJv3ciqd8r54ySIW2y3RE= -golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.4.0 h1:NF0gk8LVPg1Ml7SSbGyySuoxdsXitj7TvgvuRxIMc/M= +golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1297,25 +1260,14 @@ golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= @@ -1416,17 +1368,13 @@ golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= -golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.10-0.20220218145154-897bd77cd717/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gomodules.xyz/jsonpatch/v2 v2.0.1/go.mod h1:IhYNNY4jnS53ZnfE4PAmpKtDpTCj1JFXc+3mwe7XcUU= gomodules.xyz/jsonpatch/v2 v2.1.0/go.mod h1:IhYNNY4jnS53ZnfE4PAmpKtDpTCj1JFXc+3mwe7XcUU= gomodules.xyz/jsonpatch/v2 v2.2.0 h1:4pT439QV83L+G9FkcCriY6EkpcK6r6bK+A5FBUMI7qY= @@ -1458,21 +1406,6 @@ google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34q google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= -google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= -google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= -google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= -google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= -google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= -google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= -google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= -google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= -google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= -google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo= -google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g= -google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA= -google.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8= -google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRRyDs= -google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -1533,40 +1466,11 @@ google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= -google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= -google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= -google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= -google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= -google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= -google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= -google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20220107163113-42d7afdf6368/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= -google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220413183235-5e96e2839df9/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220519153652-3a47de7e79bd h1:e0TwkXOdbnH/1x5rc5MZ/VYyiZ4v+RdVfrGMqEwT68I= -google.golang.org/genproto v0.0.0-20220519153652-3a47de7e79bd/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f h1:BWUVssLB0HVOSY78gIdvk1dTVYtT1y8SBWtPYuTJ/6w= +google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= @@ -1592,19 +1496,11 @@ google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAG google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= -google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= -google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= -google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc v1.48.0 h1:rQOsyJ/8+ufEDJd/Gdsz7HG220Mh9HAhFHRGnIjda0w= -google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= google.golang.org/grpc/cmd/protoc-gen-go-grpc v0.0.0-20200709232328-d8193ee9cc3e/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= -google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= 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= @@ -1618,8 +1514,8 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba 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.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw= -google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= From 63a74a00b11784ebd402642b0f10f74b117e3e20 Mon Sep 17 00:00:00 2001 From: Ben Luzarraga <31223504+bluzarraga@users.noreply.github.com> Date: Thu, 6 Jul 2023 11:29:18 -0500 Subject: [PATCH 026/179] update go for 4.1 (#943) Signed-off-by: Ben Luzarraga --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 496f4738..4755c1a1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # Build the manager binary -FROM golang:1.20.4 as builder +FROM golang:1.20.5-bullseye as builder ARG GOARCH WORKDIR /workspace From edb645eefd4fddb6bf4036eb0def3bcf10d4cd3e Mon Sep 17 00:00:00 2001 From: Allen Li <46284272+qpdpQ@users.noreply.github.com> Date: Tue, 11 Jul 2023 09:24:22 -0400 Subject: [PATCH 027/179] multiple opbi (#944) Signed-off-by: Allen Li --- .../operandbindinfo_controller.go | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/controllers/operandbindinfo/operandbindinfo_controller.go b/controllers/operandbindinfo/operandbindinfo_controller.go index 1d2cc6e9..007a38aa 100644 --- a/controllers/operandbindinfo/operandbindinfo_controller.go +++ b/controllers/operandbindinfo/operandbindinfo_controller.go @@ -290,8 +290,7 @@ func (r *Reconciler) copySecret(ctx context.Context, sourceName, targetName, sou } ensureLabelsForSecret(secret, map[string]string{ - constant.OpbiNsLabel: bindInfoInstance.Namespace, - constant.OpbiNameLabel: bindInfoInstance.Name, + bindInfoInstance.Namespace + "." + bindInfoInstance.Name + "/bindinfo": "true", constant.OpbiTypeLabel: "original", }) @@ -384,8 +383,7 @@ func (r *Reconciler) copyConfigmap(ctx context.Context, sourceName, targetName, // Set the OperandBindInfo label for the ConfigMap ensureLabelsForConfigMap(cm, map[string]string{ - constant.OpbiNsLabel: bindInfoInstance.Namespace, - constant.OpbiNameLabel: bindInfoInstance.Name, + bindInfoInstance.Namespace + "." + bindInfoInstance.Name + "/bindinfo": "true", constant.OpbiTypeLabel: "original", }) @@ -537,11 +535,15 @@ func unique(stringSlice []string) []string { func toOpbiRequest() handler.MapFunc { return func(object client.Object) []reconcile.Request { opbiInstance := []reconcile.Request{} - lables := object.GetLabels() - name, nameOk := lables[constant.OpbiNameLabel] - ns, namespaceOK := lables[constant.OpbiNsLabel] - if nameOk && namespaceOK { - opbiInstance = append(opbiInstance, reconcile.Request{NamespacedName: types.NamespacedName{Name: name, Namespace: ns}}) + labels := object.GetLabels() + reg, _ := regexp.Compile(`^(.*)\.(.*)\/bindinfo`) + for annotation := range labels { + if reg.MatchString(annotation) { + annotationSlices := strings.Split(annotation, ".") + bindinfoNamespace := annotationSlices[0] + bindinfoName := strings.Split(annotationSlices[1], "/")[0] + opbiInstance = append(opbiInstance, reconcile.Request{NamespacedName: types.NamespacedName{Name: bindinfoName, Namespace: bindinfoNamespace}}) + } } return opbiInstance } From 6450c266e85a1666399b39b8d27b974bb180196d Mon Sep 17 00:00:00 2001 From: Henry Li Date: Fri, 14 Jul 2023 13:52:24 -0400 Subject: [PATCH 028/179] updated dependapot to cover release-ltsr branch (#946) Signed-off-by: Henry Li --- .github/dependabot.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index ac4fe474..f7e93cc2 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -4,3 +4,9 @@ updates: directory: "/" schedule: interval: daily + target-branch: "master" + - package-ecosystem: docker + directory: "/" + schedule: + interval: daily + target-branch: "release-ltsr" From 3519d077cae18056dc51662acf61e7fbfa57acbf Mon Sep 17 00:00:00 2001 From: Daniel Fan Date: Thu, 20 Jul 2023 17:14:29 -0400 Subject: [PATCH 029/179] Compare updated opreq status with latest opreq (#950) Signed-off-by: Daniel Fan --- .../operandrequest/operandrequest_controller.go | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/controllers/operandrequest/operandrequest_controller.go b/controllers/operandrequest/operandrequest_controller.go index 6c5957eb..bc8c0657 100644 --- a/controllers/operandrequest/operandrequest_controller.go +++ b/controllers/operandrequest/operandrequest_controller.go @@ -77,10 +77,17 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctrl.Re // Always attempt to patch the status after each reconciliation. defer func() { - if reflect.DeepEqual(originalInstance.Status, requestInstance.Status) { + // get the latest instance from the server and check if the status has changed + existingInstance := &operatorv1alpha1.OperandRequest{} + if err := r.Client.Get(ctx, req.NamespacedName, existingInstance); err != nil { + // Error reading the latest object - requeue the request. + reconcileErr = utilerrors.NewAggregate([]error{reconcileErr, fmt.Errorf("error while get latest OperandRequest.Status from server: %v", err)}) + } + + if reflect.DeepEqual(existingInstance.Status, requestInstance.Status) { return } - if err := r.Client.Status().Patch(ctx, requestInstance, client.MergeFrom(originalInstance)); err != nil && !apierrors.IsNotFound(err) { + if err := r.Client.Status().Patch(ctx, requestInstance, client.MergeFrom(existingInstance)); err != nil && !apierrors.IsNotFound(err) { reconcileErr = utilerrors.NewAggregate([]error{reconcileErr, fmt.Errorf("error while patching OperandRequest.Status: %v", err)}) } }() From db6f7792651aed8bfb6d7ebff7f378ef3e2139a4 Mon Sep 17 00:00:00 2001 From: YuChen Shen <59578388+YCShen1010@users.noreply.github.com> Date: Thu, 10 Aug 2023 14:19:23 -0400 Subject: [PATCH 030/179] [ODLM] bump version to 4.2.0 (#959) --- Makefile | 2 +- ...eployment-lifecycle-manager.clusterserviceversion.yaml | 8 ++++---- ...eployment-lifecycle-manager.clusterserviceversion.yaml | 2 +- version/version.go | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Makefile b/Makefile index d034817c..fbd8e1b3 100644 --- a/Makefile +++ b/Makefile @@ -80,7 +80,7 @@ OPERATOR_IMAGE_NAME ?= odlm # Current Operator bundle image name BUNDLE_IMAGE_NAME ?= odlm-operator-bundle # Current Operator version -OPERATOR_VERSION ?= 4.1.0 +OPERATOR_VERSION ?= 4.2.0 # Kind cluster name KIND_CLUSTER_NAME ?= "odlm" diff --git a/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml b/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml index 9161b1e5..1d70b21a 100644 --- a/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml +++ b/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml @@ -110,7 +110,7 @@ metadata: description: The Operand Deployment Lifecycle Manager provides a Kubernetes CRD-based API to manage the lifecycle of operands. nss.operator.ibm.com/managed-operators: ibm-odlm - olm.skipRange: '>=1.2.0 <4.1.0' + olm.skipRange: '>=1.2.0 <4.2.0' operators.operatorframework.io/builder: operator-sdk-v1.24.0 operators.operatorframework.io/project_layout: go.kubebuilder.io/v3 operators.openshift.io/infrastructure-features: '["disconnected"]' @@ -121,7 +121,7 @@ metadata: operatorframework.io/arch.ppc64le: supported operatorframework.io/arch.s390x: supported operatorframework.io/os.linux: supported - name: operand-deployment-lifecycle-manager.v4.1.0 + name: operand-deployment-lifecycle-manager.v4.2.0 namespace: placeholder spec: apiservicedefinitions: {} @@ -668,6 +668,6 @@ spec: provider: name: IBM relatedImages: - - image: icr.io/cpopen/odlm:4.1.0 + - image: icr.io/cpopen/odlm:4.2.0 name: ODLM_IMAGE - version: 4.1.0 + version: 4.2.0 diff --git a/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml b/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml index 5c23c88b..5553e876 100644 --- a/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml +++ b/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml @@ -11,7 +11,7 @@ metadata: description: The Operand Deployment Lifecycle Manager provides a Kubernetes CRD-based API to manage the lifecycle of operands. nss.operator.ibm.com/managed-operators: ibm-odlm - olm.skipRange: '>=1.2.0 <4.1.0' + olm.skipRange: '>=1.2.0 <4.2.0' operators.operatorframework.io/builder: operator-sdk-v1.2.0 operators.operatorframework.io/project_layout: go.kubebuilder.io/v2 operators.openshift.io/infrastructure-features: '["disconnected"]' diff --git a/version/version.go b/version/version.go index 49d17667..23b15d7f 100644 --- a/version/version.go +++ b/version/version.go @@ -17,5 +17,5 @@ package version var ( - Version = "4.1.0" + Version = "4.2.0" ) From 93d54b098373a01fecbec318ca0846f84e7dbcd8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 11 Aug 2023 03:47:24 +0800 Subject: [PATCH 031/179] build(deps): bump golang from 1.20.5-bullseye to 1.21.0-bullseye (#957) Bumps golang from 1.20.5-bullseye to 1.21.0-bullseye. --- updated-dependencies: - dependency-name: golang dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 4755c1a1..b982948e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # Build the manager binary -FROM golang:1.20.5-bullseye as builder +FROM golang:1.21.0-bullseye as builder ARG GOARCH WORKDIR /workspace From 344b18f75044645b9254a03a0c40810074166d57 Mon Sep 17 00:00:00 2001 From: YuChen Shen <59578388+YCShen1010@users.noreply.github.com> Date: Mon, 14 Aug 2023 01:36:26 -0400 Subject: [PATCH 032/179] delete job by using background cascading deletion (#956) --- controllers/operandconfig/operandconfig_controller.go | 3 ++- controllers/operandrequest/reconcile_operand.go | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/controllers/operandconfig/operandconfig_controller.go b/controllers/operandconfig/operandconfig_controller.go index 2c8ee798..93f0dd42 100644 --- a/controllers/operandconfig/operandconfig_controller.go +++ b/controllers/operandconfig/operandconfig_controller.go @@ -27,6 +27,7 @@ import ( "github.com/mohae/deepcopy" "github.com/pkg/errors" apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/types" utilerrors "k8s.io/apimachinery/pkg/util/errors" @@ -331,7 +332,7 @@ func (r *Reconciler) deleteK8sReousce(ctx context.Context, k8sAPIVersion, k8sKin } else { if r.CheckLabel(k8sUnstruct, map[string]string{constant.OpreqLabel: "true"}) { klog.V(3).Infof("Deleting k8s resource -- Kind: %s, NamespacedName: %s/%s", k8sKind, k8sNamespace, k8sName) - k8sDeleteError := r.Delete(ctx, &k8sUnstruct) + k8sDeleteError := r.Delete(ctx, &k8sUnstruct, client.PropagationPolicy(metav1.DeletePropagationBackground)) if k8sDeleteError != nil && !apierrors.IsNotFound(k8sDeleteError) { return errors.Wrapf(k8sDeleteError, "failed to delete k8s resource -- Kind: %s, NamespacedName: %s/%s", k8sKind, k8sNamespace, k8sName) } diff --git a/controllers/operandrequest/reconcile_operand.go b/controllers/operandrequest/reconcile_operand.go index f8dc8878..cb1730be 100644 --- a/controllers/operandrequest/reconcile_operand.go +++ b/controllers/operandrequest/reconcile_operand.go @@ -33,6 +33,7 @@ import ( authorizationv1 "k8s.io/api/authorization/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/meta" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" runtime "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" @@ -40,6 +41,7 @@ import ( "k8s.io/apimachinery/pkg/util/wait" "k8s.io/client-go/discovery" "k8s.io/klog" + "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" operatorv1alpha1 "github.com/IBM/operand-deployment-lifecycle-manager/api/v1alpha1" @@ -1086,7 +1088,7 @@ func (r *Reconciler) deleteK8sResource(ctx context.Context, existingK8sRes unstr } else { if r.CheckLabel(k8sResShouldBeDeleted, map[string]string{constant.OpreqLabel: "true"}) && !r.CheckLabel(k8sResShouldBeDeleted, map[string]string{constant.NotUninstallLabel: "true"}) { klog.V(3).Infof("Deleting k8s resource: %s from kind: %s", name, kind) - err := r.Delete(ctx, &k8sResShouldBeDeleted) + err := r.Delete(ctx, &k8sResShouldBeDeleted, client.PropagationPolicy(metav1.DeletePropagationBackground)) if err != nil && !apierrors.IsNotFound(err) { return errors.Wrapf(err, "failed to delete k8s resource -- Kind: %s, NamespacedName: %s/%s", kind, namespace, name) } From 769d5526c1b0c1b23e8ebc0635d25f9ccadd505f Mon Sep 17 00:00:00 2001 From: Travis CI User Date: Mon, 14 Aug 2023 17:40:58 +0000 Subject: [PATCH 033/179] Trigger build with new base image --- base_images.json | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/base_images.json b/base_images.json index c2a91ebd..50e1ca84 100644 --- a/base_images.json +++ b/base_images.json @@ -7,7 +7,7 @@ "destStage": "edge", "destNamespace": "build-images", "destImage": "ubi8", - "tag": "8.8-1009", + "tag": "8.8-1032", "updatePackages": [] }, { @@ -18,7 +18,7 @@ "destStage": "edge", "destNamespace": "build-images", "destImage": "ubi8-minimal", - "tag": "8.8-1014", + "tag": "8.8-1037", "updatePackages": [] }, { @@ -29,7 +29,7 @@ "destStage": "edge", "destNamespace": "build-images", "destImage": "ubi9-micro", - "tag": "9.2-9", + "tag": "9.2-13", "updatePackages": [] }, { @@ -40,21 +40,21 @@ "destStage": "edge", "destNamespace": "build-images", "destImage": "helm-operator", - "tag": "v1.30.0", + "tag": "v1.31.0", "updatePackages": [] }, { "imageType": "node", "sourceImage": "ubi8-minimal", - "sourceTag": "8.8-1014", + "sourceTag": "8.8-1037", "destImage": "node-v18-ubi8-minimal", - "nodeVersion": "18.16.1" + "nodeVersion": "18.17.1" }, { "imageType": "liberty", "sourceImage": "node-v18-ubi8-minimal", - "sourceTag": "18.16.1_8.8-1014", + "sourceTag": "18.17.1_8.8-1037", "destImage": "liberty11-ubi8-minimal", - "libertyVersion": "23.0.0.5" + "libertyVersion": "23.0.0.7" } ] From 20e243140df1d4d34314ea1a130782eaa674c7f6 Mon Sep 17 00:00:00 2001 From: YuChen Shen <59578388+YCShen1010@users.noreply.github.com> Date: Wed, 16 Aug 2023 00:11:27 -0400 Subject: [PATCH 034/179] [4.2] Sort Catalogsource by priority in ODLM (#955) * Sort Catalogsource by priority in ODLM * skip when catalogsource get read error --------- Co-authored-by: Daniel Fan --- ...fecycle-manager.clusterserviceversion.yaml | 9 ++++++++ config/rbac/role.yaml | 12 +++++++++- config/rbac/role_binding.yaml | 13 +++++++++++ controllers/operator/manager.go | 23 +++++++++++-------- 4 files changed, 47 insertions(+), 10 deletions(-) diff --git a/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml b/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml index 1d70b21a..3af3b36a 100644 --- a/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml +++ b/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml @@ -539,6 +539,15 @@ spec: mediatype: image/png install: spec: + clusterPermissions: + - rules: + - apiGroups: + - operators.coreos.com + resources: + - catalogsources + verbs: + - get + serviceAccountName: operand-deployment-lifecycle-manager deployments: - label: app.kubernetes.io/instance: operand-deployment-lifecycle-manager diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml index 98a17f84..0281f208 100644 --- a/config/rbac/role.yaml +++ b/config/rbac/role.yaml @@ -1,4 +1,14 @@ - +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: operand-deployment-lifecycle-manager +rules: +- apiGroups: + - operators.coreos.com + resources: + - catalogsources + verbs: + - get --- apiVersion: rbac.authorization.k8s.io/v1 kind: Role diff --git a/config/rbac/role_binding.yaml b/config/rbac/role_binding.yaml index c24c70c9..1b48546b 100644 --- a/config/rbac/role_binding.yaml +++ b/config/rbac/role_binding.yaml @@ -1,4 +1,17 @@ apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: operand-deployment-lifecycle-manager +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: operand-deployment-lifecycle-manager +subjects: +- kind: ServiceAccount + name: operand-deployment-lifecycle-manager + namespace: system +--- +apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: operand-deployment-lifecycle-manager diff --git a/controllers/operator/manager.go b/controllers/operator/manager.go index ffcf02f2..f4e38e40 100644 --- a/controllers/operator/manager.go +++ b/controllers/operator/manager.go @@ -107,6 +107,7 @@ type CatalogSource struct { Namespace string OpNamespace string RegistryNamespace string + Priority int } type sortableCatalogSource []CatalogSource @@ -114,14 +115,7 @@ type sortableCatalogSource []CatalogSource func (s sortableCatalogSource) Len() int { return len(s) } func (s sortableCatalogSource) Swap(i, j int) { s[i], s[j] = s[j], s[i] } func (s sortableCatalogSource) Less(i, j int) bool { - // Check if the catalogsource is in the same namespace as OperandRegistry - inRegistryNsI, inRegistryNsJ := s[i].Namespace == s[i].RegistryNamespace, s[j].Namespace == s[j].RegistryNamespace - if inRegistryNsI && !inRegistryNsJ { - return true - } - if !inRegistryNsI && inRegistryNsJ { - return false - } + // Check if the catalogsource is in the same namespace as operator inOpNsI, inOpNsJ := s[i].Namespace == s[i].OpNamespace, s[j].Namespace == s[j].OpNamespace if inOpNsI && !inOpNsJ { @@ -130,6 +124,12 @@ func (s sortableCatalogSource) Less(i, j int) bool { if !inOpNsI && inOpNsJ { return false } + // Compare catalogsource priorities first, higher priority comes first + iPriority, jPriority := s[i].Priority, s[j].Priority + klog.V(2).Infof("iPriority: %v, jPriority: %v", iPriority, jPriority) + if iPriority != jPriority { + return iPriority > jPriority + } // If their namespaces are the same, then compare the name of the catalogsource if s[i].Namespace == s[j].Namespace { return s[i].Name < s[j].Name @@ -164,7 +164,12 @@ func (m *ODLMOperator) GetCatalogSourceFromPackage(ctx context.Context, packageN if !channelCheck(channel, pm.Status.Channels) || (excludedCatalogSources != nil && util.Contains(excludedCatalogSources, pm.Status.CatalogSource)) { continue } - catalogSourceCandidate = append(catalogSourceCandidate, CatalogSource{Name: pm.Status.CatalogSource, Namespace: pm.Status.CatalogSourceNamespace, OpNamespace: namespace, RegistryNamespace: registryNs}) + catalogsource := &olmv1alpha1.CatalogSource{} + if err := m.Reader.Get(ctx, types.NamespacedName{Name: pm.Status.CatalogSource, Namespace: pm.Status.CatalogSourceNamespace}, catalogsource); err != nil { + klog.Warning(err) + continue + } + catalogSourceCandidate = append(catalogSourceCandidate, CatalogSource{Name: pm.Status.CatalogSource, Namespace: pm.Status.CatalogSourceNamespace, OpNamespace: namespace, RegistryNamespace: registryNs, Priority: catalogsource.Spec.Priority}) } if len(catalogSourceCandidate) == 0 { klog.Errorf("Not found PackageManifest %s in the namespace %s has channel %s", packageName, namespace, channel) From 701aa4d08892c0d61a1c0d2223d67e943dbce02a Mon Sep 17 00:00:00 2001 From: Travis CI User Date: Tue, 22 Aug 2023 20:31:52 +0000 Subject: [PATCH 035/179] Trigger build with new base image --- base_images.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base_images.json b/base_images.json index 50e1ca84..42a66810 100644 --- a/base_images.json +++ b/base_images.json @@ -55,6 +55,6 @@ "sourceImage": "node-v18-ubi8-minimal", "sourceTag": "18.17.1_8.8-1037", "destImage": "liberty11-ubi8-minimal", - "libertyVersion": "23.0.0.7" + "libertyVersion": "23.0.0.8" } ] From b5dcb6a82747ca407bc728953eb04605cc29dc43 Mon Sep 17 00:00:00 2001 From: YuChen Shen <59578388+YCShen1010@users.noreply.github.com> Date: Fri, 25 Aug 2023 15:51:35 -0400 Subject: [PATCH 036/179] handle operator namespace could be optional in OperandRegistry (#963) * fix odlm permission issue due to missing opt ns Signed-off-by: YuChen * notfound error condition added Signed-off-by: YuChen --------- Signed-off-by: YuChen --- controllers/operandrequest/operandrequest_controller.go | 4 ++-- controllers/operator/manager.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/controllers/operandrequest/operandrequest_controller.go b/controllers/operandrequest/operandrequest_controller.go index bc8c0657..2c52b9f3 100644 --- a/controllers/operandrequest/operandrequest_controller.go +++ b/controllers/operandrequest/operandrequest_controller.go @@ -79,9 +79,9 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctrl.Re defer func() { // get the latest instance from the server and check if the status has changed existingInstance := &operatorv1alpha1.OperandRequest{} - if err := r.Client.Get(ctx, req.NamespacedName, existingInstance); err != nil { + if err := r.Client.Get(ctx, req.NamespacedName, existingInstance); err != nil && !apierrors.IsNotFound(err) { // Error reading the latest object - requeue the request. - reconcileErr = utilerrors.NewAggregate([]error{reconcileErr, fmt.Errorf("error while get latest OperandRequest.Status from server: %v", err)}) + reconcileErr = utilerrors.NewAggregate([]error{reconcileErr, fmt.Errorf("c from server: %v", err)}) } if reflect.DeepEqual(existingInstance.Status, requestInstance.Status) { diff --git a/controllers/operator/manager.go b/controllers/operator/manager.go index f4e38e40..4530ee4f 100644 --- a/controllers/operator/manager.go +++ b/controllers/operator/manager.go @@ -87,7 +87,7 @@ func (m *ODLMOperator) GetOperandRegistry(ctx context.Context, key types.Namespa reg.Spec.Operators[i].Namespace = key.Namespace } if o.SourceName == "" || o.SourceNamespace == "" { - catalogSourceName, catalogSourceNs, err := m.GetCatalogSourceFromPackage(ctx, o.PackageName, o.Namespace, o.Channel, key.Namespace, excludedCatalogSources) + catalogSourceName, catalogSourceNs, err := m.GetCatalogSourceFromPackage(ctx, o.PackageName, reg.Spec.Operators[i].Namespace, o.Channel, key.Namespace, excludedCatalogSources) if err != nil { return nil, err } From 363c5e70d6db2c1c25c6b5d57e279a7f32970d90 Mon Sep 17 00:00:00 2001 From: YuChen Shen <59578388+YCShen1010@users.noreply.github.com> Date: Tue, 29 Aug 2023 12:17:39 -0400 Subject: [PATCH 037/179] ODLM support concurrently reconciling multiple resources (#965) * ODLM supportConcurrent Reconciling Signed-off-by: YuChen * reconcile multiple other resources Signed-off-by: YuChen --------- Signed-off-by: YuChen --- .../operandbindinfo_controller.go | 6 ++++++ .../operandconfig/operandconfig_controller.go | 5 +++++ .../operandregistry_controller.go | 5 +++++ .../operandrequest/operandrequest_controller.go | 5 +++++ controllers/operator/manager.go | 16 +++++++++------- 5 files changed, 30 insertions(+), 7 deletions(-) diff --git a/controllers/operandbindinfo/operandbindinfo_controller.go b/controllers/operandbindinfo/operandbindinfo_controller.go index 007a38aa..fc796a9c 100644 --- a/controllers/operandbindinfo/operandbindinfo_controller.go +++ b/controllers/operandbindinfo/operandbindinfo_controller.go @@ -36,6 +36,7 @@ import ( ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/builder" "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" "sigs.k8s.io/controller-runtime/pkg/event" "sigs.k8s.io/controller-runtime/pkg/handler" @@ -740,7 +741,12 @@ func (r *Reconciler) SetupWithManager(mgr ctrl.Manager) error { }, } + options := controller.Options{ + MaxConcurrentReconciles: r.MaxConcurrentReconciles, // Set the desired value for max concurrent reconciles. + } + return ctrl.NewControllerManagedBy(mgr). + WithOptions(options). For(&operatorv1alpha1.OperandBindInfo{}). Watches( &source.Kind{Type: &corev1.ConfigMap{}}, diff --git a/controllers/operandconfig/operandconfig_controller.go b/controllers/operandconfig/operandconfig_controller.go index 93f0dd42..fd7825f2 100644 --- a/controllers/operandconfig/operandconfig_controller.go +++ b/controllers/operandconfig/operandconfig_controller.go @@ -36,6 +36,7 @@ import ( ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/builder" "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller" "sigs.k8s.io/controller-runtime/pkg/event" "sigs.k8s.io/controller-runtime/pkg/handler" "sigs.k8s.io/controller-runtime/pkg/predicate" @@ -398,7 +399,11 @@ func (r *Reconciler) getRequestToConfigMapper(ctx context.Context) handler.MapFu // SetupWithManager adds OperandConfig controller to the manager. func (r *Reconciler) SetupWithManager(mgr ctrl.Manager) error { ctx := context.Background() + options := controller.Options{ + MaxConcurrentReconciles: r.MaxConcurrentReconciles, // Set the desired value for max concurrent reconciles. + } return ctrl.NewControllerManagedBy(mgr). + WithOptions(options). For(&operatorv1alpha1.OperandConfig{}, builder.WithPredicates(predicate.GenerationChangedPredicate{})). Watches(&source.Kind{Type: &operatorv1alpha1.OperandRequest{}}, handler.EnqueueRequestsFromMapFunc(r.getRequestToConfigMapper(ctx)), builder.WithPredicates(predicate.Funcs{ CreateFunc: func(e event.CreateEvent) bool { diff --git a/controllers/operandregistry/operandregistry_controller.go b/controllers/operandregistry/operandregistry_controller.go index 44137df4..b1bc9197 100644 --- a/controllers/operandregistry/operandregistry_controller.go +++ b/controllers/operandregistry/operandregistry_controller.go @@ -27,6 +27,7 @@ import ( ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/builder" "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller" "sigs.k8s.io/controller-runtime/pkg/event" "sigs.k8s.io/controller-runtime/pkg/handler" "sigs.k8s.io/controller-runtime/pkg/predicate" @@ -114,7 +115,11 @@ func (r *Reconciler) updateStatus(ctx context.Context, instance *operatorv1alpha // SetupWithManager adds OperandRegistry controller to the manager. func (r *Reconciler) SetupWithManager(mgr ctrl.Manager) error { + options := controller.Options{ + MaxConcurrentReconciles: r.MaxConcurrentReconciles, // Set the desired value for max concurrent reconciles. + } return ctrl.NewControllerManagedBy(mgr). + WithOptions(options). For(&operatorv1alpha1.OperandRegistry{}, builder.WithPredicates(predicate.GenerationChangedPredicate{})). Watches(&source.Kind{Type: &operatorv1alpha1.OperandRequest{}}, handler.EnqueueRequestsFromMapFunc(func(a client.Object) []reconcile.Request { or := a.(*operatorv1alpha1.OperandRequest) diff --git a/controllers/operandrequest/operandrequest_controller.go b/controllers/operandrequest/operandrequest_controller.go index 2c52b9f3..36741ccf 100644 --- a/controllers/operandrequest/operandrequest_controller.go +++ b/controllers/operandrequest/operandrequest_controller.go @@ -38,6 +38,7 @@ import ( ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/builder" "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller" "sigs.k8s.io/controller-runtime/pkg/event" "sigs.k8s.io/controller-runtime/pkg/handler" "sigs.k8s.io/controller-runtime/pkg/predicate" @@ -300,7 +301,11 @@ func (r *Reconciler) getConfigToRequestMapper() handler.MapFunc { // SetupWithManager adds OperandRequest controller to the manager. func (r *Reconciler) SetupWithManager(mgr ctrl.Manager) error { + options := controller.Options{ + MaxConcurrentReconciles: r.MaxConcurrentReconciles, // Set the desired value for max concurrent reconciles. + } return ctrl.NewControllerManagedBy(mgr). + WithOptions(options). For(&operatorv1alpha1.OperandRequest{}, builder.WithPredicates(predicate.GenerationChangedPredicate{})). Watches(&source.Kind{Type: &olmv1alpha1.Subscription{}}, handler.EnqueueRequestsFromMapFunc(r.getSubToRequestMapper()), builder.WithPredicates(predicate.Funcs{ UpdateFunc: func(e event.UpdateEvent) bool { diff --git a/controllers/operator/manager.go b/controllers/operator/manager.go index 4530ee4f..abe302f3 100644 --- a/controllers/operator/manager.go +++ b/controllers/operator/manager.go @@ -45,18 +45,20 @@ type ODLMOperator struct { client.Client client.Reader *rest.Config - Recorder record.EventRecorder - Scheme *runtime.Scheme + Recorder record.EventRecorder + Scheme *runtime.Scheme + MaxConcurrentReconciles int } // NewODLMOperator is the method to initialize an Operator struct func NewODLMOperator(mgr manager.Manager, name string) *ODLMOperator { return &ODLMOperator{ - Client: mgr.GetClient(), - Reader: mgr.GetAPIReader(), - Config: mgr.GetConfig(), - Recorder: mgr.GetEventRecorderFor(name), - Scheme: mgr.GetScheme(), + Client: mgr.GetClient(), + Reader: mgr.GetAPIReader(), + Config: mgr.GetConfig(), + Recorder: mgr.GetEventRecorderFor(name), + Scheme: mgr.GetScheme(), + MaxConcurrentReconciles: 5, } } From 18a0c6041c83f48d7cffe7c9598c77281333342f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 7 Sep 2023 21:07:47 +0800 Subject: [PATCH 038/179] build(deps): bump golang from 1.21.0-bullseye to 1.21.1-bullseye (#966) Bumps golang from 1.21.0-bullseye to 1.21.1-bullseye. --- updated-dependencies: - dependency-name: golang dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index b982948e..7e7c186a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # Build the manager binary -FROM golang:1.21.0-bullseye as builder +FROM golang:1.21.1-bullseye as builder ARG GOARCH WORKDIR /workspace From e9760db3de81f90ad037ba619cbf4a97df647135 Mon Sep 17 00:00:00 2001 From: Daniel Fan Date: Thu, 7 Sep 2023 13:17:46 -0400 Subject: [PATCH 039/179] Add OperandBindinfo example into alm-example (#968) * Add OperandBindinfo example into alm-example for validation Signed-off-by: Daniel Fan * Update error msg Signed-off-by: Daniel Fan --------- Signed-off-by: Daniel Fan --- api/v1alpha1/operandbindinfo_types.go | 3 ++- api/v1alpha1/operandconfig_types.go | 3 ++- api/v1alpha1/operandregistry_types.go | 3 ++- api/v1alpha1/operandrequest_types.go | 3 ++- ...fecycle-manager.clusterserviceversion.yaml | 23 +++++++++++++++++++ .../operator.ibm.com_operandbindinfos.yaml | 1 + .../operator.ibm.com_operandconfigs.yaml | 1 + .../operator.ibm.com_operandregistries.yaml | 1 + .../operator.ibm.com_operandbindinfos.yaml | 1 + .../operator.ibm.com_operandconfigs.yaml | 1 + .../operator.ibm.com_operandregistries.yaml | 1 + config/samples/kustomization.yaml | 1 + .../operator_v1alpha1_operandbindinfo.yaml | 16 +++++++++++++ .../operandrequest_controller.go | 2 +- 14 files changed, 55 insertions(+), 5 deletions(-) create mode 100644 config/samples/operator_v1alpha1_operandbindinfo.yaml diff --git a/api/v1alpha1/operandbindinfo_types.go b/api/v1alpha1/operandbindinfo_types.go index c481c4d5..54f812aa 100644 --- a/api/v1alpha1/operandbindinfo_types.go +++ b/api/v1alpha1/operandbindinfo_types.go @@ -95,7 +95,8 @@ type OperandBindInfo struct { metav1.ObjectMeta `json:"metadata,omitempty"` // +kubebuilder:pruning:PreserveUnknownFields - Spec OperandBindInfoSpec `json:"spec,omitempty"` + Spec OperandBindInfoSpec `json:"spec,omitempty"` + // +kubebuilder:pruning:PreserveUnknownFields Status OperandBindInfoStatus `json:"status,omitempty"` } diff --git a/api/v1alpha1/operandconfig_types.go b/api/v1alpha1/operandconfig_types.go index 0232f147..8fad0874 100644 --- a/api/v1alpha1/operandconfig_types.go +++ b/api/v1alpha1/operandconfig_types.go @@ -102,7 +102,8 @@ type OperandConfig struct { metav1.ObjectMeta `json:"metadata,omitempty"` // +kubebuilder:pruning:PreserveUnknownFields - Spec OperandConfigSpec `json:"spec,omitempty"` + Spec OperandConfigSpec `json:"spec,omitempty"` + // +kubebuilder:pruning:PreserveUnknownFields Status OperandConfigStatus `json:"status,omitempty"` } diff --git a/api/v1alpha1/operandregistry_types.go b/api/v1alpha1/operandregistry_types.go index 3eef90cc..6daf2ec0 100644 --- a/api/v1alpha1/operandregistry_types.go +++ b/api/v1alpha1/operandregistry_types.go @@ -151,7 +151,8 @@ type OperandRegistry struct { metav1.ObjectMeta `json:"metadata,omitempty"` // +kubebuilder:pruning:PreserveUnknownFields - Spec OperandRegistrySpec `json:"spec,omitempty"` + Spec OperandRegistrySpec `json:"spec,omitempty"` + // +kubebuilder:pruning:PreserveUnknownFields Status OperandRegistryStatus `json:"status,omitempty"` } diff --git a/api/v1alpha1/operandrequest_types.go b/api/v1alpha1/operandrequest_types.go index b2634365..d27a3bcb 100644 --- a/api/v1alpha1/operandrequest_types.go +++ b/api/v1alpha1/operandrequest_types.go @@ -251,7 +251,8 @@ type OperandRequest struct { metav1.ObjectMeta `json:"metadata,omitempty"` // +kubebuilder:pruning:PreserveUnknownFields - Spec OperandRequestSpec `json:"spec,omitempty"` + Spec OperandRequestSpec `json:"spec,omitempty"` + // +kubebuilder:pruning:PreserveUnknownFields Status OperandRequestStatus `json:"status,omitempty"` } diff --git a/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml b/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml index 3af3b36a..587cd882 100644 --- a/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml +++ b/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml @@ -4,6 +4,29 @@ metadata: annotations: alm-examples: |- [ + { + "apiVersion": "operator.ibm.com/v1alpha1", + "kind": "OperandBindInfo", + "metadata": { + "labels": { + "app.kubernetes.io/instance": "operand-deployment-lifecycle-manager", + "app.kubernetes.io/managed-by": "operand-deployment-lifecycle-manager", + "app.kubernetes.io/name": "operand-deployment-lifecycle-manager" + }, + "name": "example-service" + }, + "spec": { + "bindings": { + "public": { + "configmap": "mongodb-configmap", + "secret": "mongodb-secret" + } + }, + "description": "Binding information that should be accessible to MongoDB adopters", + "operand": "mongodb-atlas-kubernetes", + "registry": "example-service" + } + }, { "apiVersion": "operator.ibm.com/v1alpha1", "kind": "OperandConfig", diff --git a/bundle/manifests/operator.ibm.com_operandbindinfos.yaml b/bundle/manifests/operator.ibm.com_operandbindinfos.yaml index 18b7184f..5bc28cb6 100644 --- a/bundle/manifests/operator.ibm.com_operandbindinfos.yaml +++ b/bundle/manifests/operator.ibm.com_operandbindinfos.yaml @@ -100,6 +100,7 @@ spec: type: string type: array type: object + x-kubernetes-preserve-unknown-fields: true type: object served: true storage: true diff --git a/bundle/manifests/operator.ibm.com_operandconfigs.yaml b/bundle/manifests/operator.ibm.com_operandconfigs.yaml index 03a8acbd..e3bf82e4 100644 --- a/bundle/manifests/operator.ibm.com_operandconfigs.yaml +++ b/bundle/manifests/operator.ibm.com_operandconfigs.yaml @@ -143,6 +143,7 @@ spec: description: ServiceStatus defines all the status of a operator. type: object type: object + x-kubernetes-preserve-unknown-fields: true type: object served: true storage: true diff --git a/bundle/manifests/operator.ibm.com_operandregistries.yaml b/bundle/manifests/operator.ibm.com_operandregistries.yaml index 6cd0ce3f..2fad66fb 100644 --- a/bundle/manifests/operator.ibm.com_operandregistries.yaml +++ b/bundle/manifests/operator.ibm.com_operandregistries.yaml @@ -2197,6 +2197,7 @@ spec: OperandRegistry. type: string type: object + x-kubernetes-preserve-unknown-fields: true type: object served: true storage: true diff --git a/config/crd/bases/operator.ibm.com_operandbindinfos.yaml b/config/crd/bases/operator.ibm.com_operandbindinfos.yaml index 603d7116..efceddf8 100644 --- a/config/crd/bases/operator.ibm.com_operandbindinfos.yaml +++ b/config/crd/bases/operator.ibm.com_operandbindinfos.yaml @@ -98,6 +98,7 @@ spec: type: string type: array type: object + x-kubernetes-preserve-unknown-fields: true type: object served: true storage: true diff --git a/config/crd/bases/operator.ibm.com_operandconfigs.yaml b/config/crd/bases/operator.ibm.com_operandconfigs.yaml index ca778d1b..08a903e7 100644 --- a/config/crd/bases/operator.ibm.com_operandconfigs.yaml +++ b/config/crd/bases/operator.ibm.com_operandconfigs.yaml @@ -141,6 +141,7 @@ spec: description: ServiceStatus defines all the status of a operator. type: object type: object + x-kubernetes-preserve-unknown-fields: true type: object served: true storage: true diff --git a/config/crd/bases/operator.ibm.com_operandregistries.yaml b/config/crd/bases/operator.ibm.com_operandregistries.yaml index ff43caec..cbef8a2b 100644 --- a/config/crd/bases/operator.ibm.com_operandregistries.yaml +++ b/config/crd/bases/operator.ibm.com_operandregistries.yaml @@ -2195,6 +2195,7 @@ spec: OperandRegistry. type: string type: object + x-kubernetes-preserve-unknown-fields: true type: object served: true storage: true diff --git a/config/samples/kustomization.yaml b/config/samples/kustomization.yaml index c32ed67f..c488daf4 100644 --- a/config/samples/kustomization.yaml +++ b/config/samples/kustomization.yaml @@ -3,3 +3,4 @@ resources: - operator_v1alpha1_operandrequest.yaml - operator_v1alpha1_operandregistry.yaml - operator_v1alpha1_operandconfig.yaml +- operator_v1alpha1_operandbindinfo.yaml diff --git a/config/samples/operator_v1alpha1_operandbindinfo.yaml b/config/samples/operator_v1alpha1_operandbindinfo.yaml new file mode 100644 index 00000000..5b1c634b --- /dev/null +++ b/config/samples/operator_v1alpha1_operandbindinfo.yaml @@ -0,0 +1,16 @@ +apiVersion: operator.ibm.com/v1alpha1 +kind: OperandBindInfo +metadata: + labels: + app.kubernetes.io/instance: "operand-deployment-lifecycle-manager" + app.kubernetes.io/managed-by: "operand-deployment-lifecycle-manager" + app.kubernetes.io/name: "operand-deployment-lifecycle-manager" + name: example-service +spec: + bindings: + public: + secret: mongodb-secret + configmap: mongodb-configmap + description: Binding information that should be accessible to MongoDB adopters + operand: mongodb-atlas-kubernetes + registry: example-service diff --git a/controllers/operandrequest/operandrequest_controller.go b/controllers/operandrequest/operandrequest_controller.go index 36741ccf..5a52fcb8 100644 --- a/controllers/operandrequest/operandrequest_controller.go +++ b/controllers/operandrequest/operandrequest_controller.go @@ -82,7 +82,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctrl.Re existingInstance := &operatorv1alpha1.OperandRequest{} if err := r.Client.Get(ctx, req.NamespacedName, existingInstance); err != nil && !apierrors.IsNotFound(err) { // Error reading the latest object - requeue the request. - reconcileErr = utilerrors.NewAggregate([]error{reconcileErr, fmt.Errorf("c from server: %v", err)}) + reconcileErr = utilerrors.NewAggregate([]error{reconcileErr, fmt.Errorf("error while get latest OperandRequest.Status from server: %v", err)}) } if reflect.DeepEqual(existingInstance.Status, requestInstance.Status) { From c2b30dfba742f1f080abbfe3627802a34f4855c4 Mon Sep 17 00:00:00 2001 From: Ben Luzarraga <31223504+bluzarraga@users.noreply.github.com> Date: Mon, 11 Sep 2023 10:28:51 -0500 Subject: [PATCH 040/179] update packages for security vulnerabilities (#969) Signed-off-by: Ben Luzarraga --- go.mod | 24 ++++++++++++------------ go.sum | 47 ++++++++++++++++++++++++----------------------- 2 files changed, 36 insertions(+), 35 deletions(-) diff --git a/go.mod b/go.mod index 47bbe4ba..e9797cad 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( github.com/operator-framework/api v0.6.2 github.com/operator-framework/operator-lifecycle-manager v0.17.0 github.com/pkg/errors v0.9.1 - golang.org/x/mod v0.7.0 + golang.org/x/mod v0.8.0 k8s.io/api v0.24.3 k8s.io/apimachinery v0.24.3 k8s.io/client-go v0.24.3 @@ -24,7 +24,7 @@ require ( ) require ( - cloud.google.com/go/compute v1.15.1 // indirect + cloud.google.com/go/compute v1.19.1 // indirect cloud.google.com/go/compute/metadata v0.2.3 // indirect github.com/PuerkitoBio/purell v1.1.1 // indirect github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect @@ -44,7 +44,7 @@ require ( github.com/gobuffalo/flect v0.2.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect - github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/protobuf v1.5.3 // indirect github.com/google/gnostic v0.6.9 // indirect github.com/google/gofuzz v1.1.0 // indirect github.com/google/uuid v1.3.0 // indirect @@ -68,7 +68,7 @@ require ( github.com/prometheus/client_model v0.2.0 // indirect github.com/prometheus/common v0.32.1 // indirect github.com/prometheus/procfs v0.7.3 // indirect - github.com/sirupsen/logrus v1.9.0 // indirect + github.com/sirupsen/logrus v1.9.3 // indirect github.com/spf13/afero v1.8.2 // indirect github.com/spf13/cast v1.5.0 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect @@ -78,17 +78,17 @@ require ( go.uber.org/atomic v1.7.0 // indirect go.uber.org/multierr v1.6.0 // indirect go.uber.org/zap v1.19.1 // indirect - golang.org/x/net v0.7.0 // indirect - golang.org/x/oauth2 v0.4.0 // indirect - golang.org/x/sys v0.5.0 // indirect - golang.org/x/term v0.5.0 // indirect - golang.org/x/text v0.7.0 // indirect + golang.org/x/net v0.9.0 // indirect + golang.org/x/oauth2 v0.7.0 // indirect + golang.org/x/sys v0.7.0 // indirect + golang.org/x/term v0.7.0 // indirect + golang.org/x/text v0.9.0 // indirect golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f // indirect - google.golang.org/grpc v1.53.0 // indirect - google.golang.org/protobuf v1.28.1 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19 // indirect + google.golang.org/grpc v1.57.0 // indirect + google.golang.org/protobuf v1.30.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ini.v1 v1.66.4 // indirect gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect diff --git a/go.sum b/go.sum index 05305d80..5e99f9df 100644 --- a/go.sum +++ b/go.sum @@ -28,8 +28,8 @@ cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvf cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/compute v1.15.1 h1:7UGq3QknM33pw5xATlpzeoomNxsacIVvTqTTvbfajmE= -cloud.google.com/go/compute v1.15.1/go.mod h1:bjjoF/NtFUrkD/urWfdHaKuOPDR5nWIs63rR+SXhcpA= +cloud.google.com/go/compute v1.19.1 h1:am86mquDUgjGNWxiGn+5PGLbmgiWXlE/yNWpIpNvuXY= +cloud.google.com/go/compute v1.19.1/go.mod h1:6ylj3a05WF8leseCdIf77NK0g1ey+nj5IKd5/kvShxE= cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= @@ -442,8 +442,9 @@ github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= -github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= @@ -862,8 +863,8 @@ github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6Mwd github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= -github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= @@ -1083,8 +1084,8 @@ golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/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.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= -golang.org/x/mod v0.7.0 h1:LapD9S96VoQRhi/GrNTqeBJFrUjs5UHCAtTlgwA5oZA= -golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1147,8 +1148,8 @@ golang.org/x/net v0.0.0-20210825183410-e898025ed96a/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g= -golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM= +golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1164,8 +1165,8 @@ golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.4.0 h1:NF0gk8LVPg1Ml7SSbGyySuoxdsXitj7TvgvuRxIMc/M= -golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec= +golang.org/x/oauth2 v0.7.0 h1:qe6s0zUXlPX80/dITx3440hWZ7GwMwgDDyrSGTPJG/g= +golang.org/x/oauth2 v0.7.0/go.mod h1:hPLQkd9LyjfXTiRohC/41GhcFqxisoUQ99sCUOHO9x4= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1270,12 +1271,12 @@ golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU= +golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 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.5.0 h1:n2a8QNdAb0sZNpU9R1ALUXBbY+w51fCQDN+7EdxNBsY= -golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.7.0 h1:BEvjmm5fURWqcfbSKTdpkDXYBrUS1c0m8agp14W48vQ= +golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1286,8 +1287,8 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= -golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -1469,8 +1470,8 @@ google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaE google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= google.golang.org/genproto v0.0.0-20220107163113-42d7afdf6368/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f h1:BWUVssLB0HVOSY78gIdvk1dTVYtT1y8SBWtPYuTJ/6w= -google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19 h1:0nDDozoAU19Qb2HwhXadU8OcsiO/09cnTqhUtq2MEOM= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= @@ -1498,8 +1499,8 @@ google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAG google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= -google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/grpc v1.57.0 h1:kfzNeI/klCGD2YPMUlaGNT3pxvYfga7smW3Vth8Zsiw= +google.golang.org/grpc v1.57.0/go.mod h1:Sd+9RMTACXwmub0zcNY2c4arhtrbBYD1AUHI/dt16Mo= google.golang.org/grpc/cmd/protoc-gen-go-grpc v0.0.0-20200709232328-d8193ee9cc3e/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= 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= @@ -1514,8 +1515,8 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba 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.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= -google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= +google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= From d259717af3186501bff882e5626c1a4108bf1cb4 Mon Sep 17 00:00:00 2001 From: Allen Li <46284272+qpdpQ@users.noreply.github.com> Date: Mon, 11 Sep 2023 11:20:50 -0600 Subject: [PATCH 041/179] add ephemeral-storage request to container (#961) Signed-off-by: Allen Li --- ...erand-deployment-lifecycle-manager.clusterserviceversion.yaml | 1 + config/manager/manager.yaml | 1 + 2 files changed, 2 insertions(+) diff --git a/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml b/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml index 587cd882..d015b1a6 100644 --- a/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml +++ b/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml @@ -648,6 +648,7 @@ spec: requests: cpu: 200m memory: 200Mi + ephemeral-storage: 256Mi securityContext: allowPrivilegeEscalation: false capabilities: diff --git a/config/manager/manager.yaml b/config/manager/manager.yaml index cbe9adff..1ddf67b9 100644 --- a/config/manager/manager.yaml +++ b/config/manager/manager.yaml @@ -83,6 +83,7 @@ spec: requests: cpu: 200m memory: 200Mi + ephemeral-storage: 256Mi securityContext: allowPrivilegeEscalation: false capabilities: From cd3b1617a9882fbe35b01238efaf596526aeafc3 Mon Sep 17 00:00:00 2001 From: Daniel Fan Date: Mon, 25 Sep 2023 11:01:02 -0400 Subject: [PATCH 042/179] Bump ODLM to v4.3 version (#971) Signed-off-by: Daniel Fan --- Makefile | 4 ++-- bundle.Dockerfile | 4 ++-- ...eployment-lifecycle-manager.clusterserviceversion.yaml | 8 ++++---- bundle/metadata/annotations.yaml | 4 ++-- ...eployment-lifecycle-manager.clusterserviceversion.yaml | 2 +- version/version.go | 2 +- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Makefile b/Makefile index fbd8e1b3..6ab0cf74 100644 --- a/Makefile +++ b/Makefile @@ -80,7 +80,7 @@ OPERATOR_IMAGE_NAME ?= odlm # Current Operator bundle image name BUNDLE_IMAGE_NAME ?= odlm-operator-bundle # Current Operator version -OPERATOR_VERSION ?= 4.2.0 +OPERATOR_VERSION ?= 4.3.0 # Kind cluster name KIND_CLUSTER_NAME ?= "odlm" @@ -194,7 +194,7 @@ bundle-manifests: generate-all: manifests kustomize operator-sdk ## Generate bundle manifests, metadata and package manifests $(OPERATOR_SDK) generate kustomize manifests -q - - make bundle-manifests CHANNELS=v4.0 DEFAULT_CHANNEL=v4.0 + - make bundle-manifests CHANNELS=v4.3 DEFAULT_CHANNEL=v4.3 ##@ Test diff --git a/bundle.Dockerfile b/bundle.Dockerfile index 253be295..2d6f5863 100644 --- a/bundle.Dockerfile +++ b/bundle.Dockerfile @@ -5,8 +5,8 @@ LABEL operators.operatorframework.io.bundle.mediatype.v1=registry+v1 LABEL operators.operatorframework.io.bundle.manifests.v1=manifests/ LABEL operators.operatorframework.io.bundle.metadata.v1=metadata/ LABEL operators.operatorframework.io.bundle.package.v1=ibm-odlm -LABEL operators.operatorframework.io.bundle.channels.v1=v4.0 -LABEL operators.operatorframework.io.bundle.channel.default.v1=v4.0 +LABEL operators.operatorframework.io.bundle.channels.v1=v4.3 +LABEL operators.operatorframework.io.bundle.channel.default.v1=v4.3 LABEL operators.operatorframework.io.metrics.builder=operator-sdk-v1.24.0 LABEL operators.operatorframework.io.metrics.mediatype.v1=metrics+v1 LABEL operators.operatorframework.io.metrics.project_layout=go.kubebuilder.io/v3 diff --git a/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml b/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml index d015b1a6..5dfe2941 100644 --- a/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml +++ b/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml @@ -133,7 +133,7 @@ metadata: description: The Operand Deployment Lifecycle Manager provides a Kubernetes CRD-based API to manage the lifecycle of operands. nss.operator.ibm.com/managed-operators: ibm-odlm - olm.skipRange: '>=1.2.0 <4.2.0' + olm.skipRange: '>=1.2.0 <4.3.0' operators.operatorframework.io/builder: operator-sdk-v1.24.0 operators.operatorframework.io/project_layout: go.kubebuilder.io/v3 operators.openshift.io/infrastructure-features: '["disconnected"]' @@ -144,7 +144,7 @@ metadata: operatorframework.io/arch.ppc64le: supported operatorframework.io/arch.s390x: supported operatorframework.io/os.linux: supported - name: operand-deployment-lifecycle-manager.v4.2.0 + name: operand-deployment-lifecycle-manager.v4.3.0 namespace: placeholder spec: apiservicedefinitions: {} @@ -701,6 +701,6 @@ spec: provider: name: IBM relatedImages: - - image: icr.io/cpopen/odlm:4.2.0 + - image: icr.io/cpopen/odlm:4.3.0 name: ODLM_IMAGE - version: 4.2.0 + version: 4.3.0 diff --git a/bundle/metadata/annotations.yaml b/bundle/metadata/annotations.yaml index f5b73652..7e3726d5 100644 --- a/bundle/metadata/annotations.yaml +++ b/bundle/metadata/annotations.yaml @@ -4,8 +4,8 @@ annotations: operators.operatorframework.io.bundle.manifests.v1: manifests/ operators.operatorframework.io.bundle.metadata.v1: metadata/ operators.operatorframework.io.bundle.package.v1: ibm-odlm - operators.operatorframework.io.bundle.channels.v1: v4.0 - operators.operatorframework.io.bundle.channel.default.v1: v4.0 + operators.operatorframework.io.bundle.channels.v1: v4.3 + operators.operatorframework.io.bundle.channel.default.v1: v4.3 operators.operatorframework.io.metrics.builder: operator-sdk-v1.24.0 operators.operatorframework.io.metrics.mediatype.v1: metrics+v1 operators.operatorframework.io.metrics.project_layout: go.kubebuilder.io/v3 diff --git a/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml b/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml index 5553e876..33bab37f 100644 --- a/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml +++ b/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml @@ -11,7 +11,7 @@ metadata: description: The Operand Deployment Lifecycle Manager provides a Kubernetes CRD-based API to manage the lifecycle of operands. nss.operator.ibm.com/managed-operators: ibm-odlm - olm.skipRange: '>=1.2.0 <4.2.0' + olm.skipRange: '>=1.2.0 <4.3.0' operators.operatorframework.io/builder: operator-sdk-v1.2.0 operators.operatorframework.io/project_layout: go.kubebuilder.io/v2 operators.openshift.io/infrastructure-features: '["disconnected"]' diff --git a/version/version.go b/version/version.go index 23b15d7f..d494af85 100644 --- a/version/version.go +++ b/version/version.go @@ -17,5 +17,5 @@ package version var ( - Version = "4.2.0" + Version = "4.3.0" ) From c3c42f103cb4f4af259b569274031e2986c1e1db Mon Sep 17 00:00:00 2001 From: Daniel Fan Date: Thu, 28 Sep 2023 13:00:07 -0400 Subject: [PATCH 043/179] revert ODLM back to 4.2.1 and channel v4.2 (#972) Signed-off-by: Daniel Fan --- Makefile | 4 ++-- bundle.Dockerfile | 4 ++-- ...eployment-lifecycle-manager.clusterserviceversion.yaml | 8 ++++---- bundle/metadata/annotations.yaml | 4 ++-- ...eployment-lifecycle-manager.clusterserviceversion.yaml | 2 +- version/version.go | 2 +- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Makefile b/Makefile index 6ab0cf74..c9dab00d 100644 --- a/Makefile +++ b/Makefile @@ -80,7 +80,7 @@ OPERATOR_IMAGE_NAME ?= odlm # Current Operator bundle image name BUNDLE_IMAGE_NAME ?= odlm-operator-bundle # Current Operator version -OPERATOR_VERSION ?= 4.3.0 +OPERATOR_VERSION ?= 4.2.1 # Kind cluster name KIND_CLUSTER_NAME ?= "odlm" @@ -194,7 +194,7 @@ bundle-manifests: generate-all: manifests kustomize operator-sdk ## Generate bundle manifests, metadata and package manifests $(OPERATOR_SDK) generate kustomize manifests -q - - make bundle-manifests CHANNELS=v4.3 DEFAULT_CHANNEL=v4.3 + - make bundle-manifests CHANNELS=v4.2 DEFAULT_CHANNEL=v4.2 ##@ Test diff --git a/bundle.Dockerfile b/bundle.Dockerfile index 2d6f5863..b5cf0768 100644 --- a/bundle.Dockerfile +++ b/bundle.Dockerfile @@ -5,8 +5,8 @@ LABEL operators.operatorframework.io.bundle.mediatype.v1=registry+v1 LABEL operators.operatorframework.io.bundle.manifests.v1=manifests/ LABEL operators.operatorframework.io.bundle.metadata.v1=metadata/ LABEL operators.operatorframework.io.bundle.package.v1=ibm-odlm -LABEL operators.operatorframework.io.bundle.channels.v1=v4.3 -LABEL operators.operatorframework.io.bundle.channel.default.v1=v4.3 +LABEL operators.operatorframework.io.bundle.channels.v1=v4.2 +LABEL operators.operatorframework.io.bundle.channel.default.v1=v4.2 LABEL operators.operatorframework.io.metrics.builder=operator-sdk-v1.24.0 LABEL operators.operatorframework.io.metrics.mediatype.v1=metrics+v1 LABEL operators.operatorframework.io.metrics.project_layout=go.kubebuilder.io/v3 diff --git a/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml b/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml index 5dfe2941..84040423 100644 --- a/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml +++ b/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml @@ -133,7 +133,7 @@ metadata: description: The Operand Deployment Lifecycle Manager provides a Kubernetes CRD-based API to manage the lifecycle of operands. nss.operator.ibm.com/managed-operators: ibm-odlm - olm.skipRange: '>=1.2.0 <4.3.0' + olm.skipRange: '>=1.2.0 <4.2.1' operators.operatorframework.io/builder: operator-sdk-v1.24.0 operators.operatorframework.io/project_layout: go.kubebuilder.io/v3 operators.openshift.io/infrastructure-features: '["disconnected"]' @@ -144,7 +144,7 @@ metadata: operatorframework.io/arch.ppc64le: supported operatorframework.io/arch.s390x: supported operatorframework.io/os.linux: supported - name: operand-deployment-lifecycle-manager.v4.3.0 + name: operand-deployment-lifecycle-manager.v4.2.1 namespace: placeholder spec: apiservicedefinitions: {} @@ -701,6 +701,6 @@ spec: provider: name: IBM relatedImages: - - image: icr.io/cpopen/odlm:4.3.0 + - image: icr.io/cpopen/odlm:4.2.1 name: ODLM_IMAGE - version: 4.3.0 + version: 4.2.1 diff --git a/bundle/metadata/annotations.yaml b/bundle/metadata/annotations.yaml index 7e3726d5..b322c19f 100644 --- a/bundle/metadata/annotations.yaml +++ b/bundle/metadata/annotations.yaml @@ -4,8 +4,8 @@ annotations: operators.operatorframework.io.bundle.manifests.v1: manifests/ operators.operatorframework.io.bundle.metadata.v1: metadata/ operators.operatorframework.io.bundle.package.v1: ibm-odlm - operators.operatorframework.io.bundle.channels.v1: v4.3 - operators.operatorframework.io.bundle.channel.default.v1: v4.3 + operators.operatorframework.io.bundle.channels.v1: v4.2 + operators.operatorframework.io.bundle.channel.default.v1: v4.2 operators.operatorframework.io.metrics.builder: operator-sdk-v1.24.0 operators.operatorframework.io.metrics.mediatype.v1: metrics+v1 operators.operatorframework.io.metrics.project_layout: go.kubebuilder.io/v3 diff --git a/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml b/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml index 33bab37f..2b580600 100644 --- a/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml +++ b/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml @@ -11,7 +11,7 @@ metadata: description: The Operand Deployment Lifecycle Manager provides a Kubernetes CRD-based API to manage the lifecycle of operands. nss.operator.ibm.com/managed-operators: ibm-odlm - olm.skipRange: '>=1.2.0 <4.3.0' + olm.skipRange: '>=1.2.0 <4.2.1' operators.operatorframework.io/builder: operator-sdk-v1.2.0 operators.operatorframework.io/project_layout: go.kubebuilder.io/v2 operators.openshift.io/infrastructure-features: '["disconnected"]' diff --git a/version/version.go b/version/version.go index d494af85..2d5c3966 100644 --- a/version/version.go +++ b/version/version.go @@ -17,5 +17,5 @@ package version var ( - Version = "4.3.0" + Version = "4.2.1" ) From 98f085fe230e2b2862d76a67aea7e25c835351c8 Mon Sep 17 00:00:00 2001 From: Piotr Godowski Date: Thu, 28 Sep 2023 20:18:40 +0200 Subject: [PATCH 044/179] Add the common label to operand Pod (#970) * Add the common label to operand Pod Resolves https://github.ibm.com/IBMPrivateCloud/roadmap/issues/59790 * remove spaces in labels --------- Co-authored-by: Piotr Godowski --- ...rand-deployment-lifecycle-manager.clusterserviceversion.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml b/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml index 84040423..a0f81435 100644 --- a/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml +++ b/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml @@ -576,6 +576,7 @@ spec: app.kubernetes.io/instance: operand-deployment-lifecycle-manager app.kubernetes.io/managed-by: operand-deployment-lifecycle-manager app.kubernetes.io/name: operand-deployment-lifecycle-manager + productName: IBM_Cloud_Platform_Common_Services name: operand-deployment-lifecycle-manager spec: replicas: 1 @@ -593,6 +594,7 @@ spec: app.kubernetes.io/instance: operand-deployment-lifecycle-manager app.kubernetes.io/managed-by: operand-deployment-lifecycle-manager app.kubernetes.io/name: operand-deployment-lifecycle-manager + productName: IBM_Cloud_Platform_Common_Services intent: projected-odlm name: operand-deployment-lifecycle-manager spec: From a2f87381b87af16f705a79d5afe8d3bf6b4b1af6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 7 Oct 2023 01:45:11 +0800 Subject: [PATCH 045/179] build(deps): bump golang from 1.21.1-bullseye to 1.21.2-bullseye (#974) Bumps golang from 1.21.1-bullseye to 1.21.2-bullseye. --- updated-dependencies: - dependency-name: golang dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 7e7c186a..a901bc95 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # Build the manager binary -FROM golang:1.21.1-bullseye as builder +FROM golang:1.21.2-bullseye as builder ARG GOARCH WORKDIR /workspace From cf27df71cc104337ee44b5513c7572a93a3b73e8 Mon Sep 17 00:00:00 2001 From: Travis CI User Date: Wed, 11 Oct 2023 20:26:07 +0000 Subject: [PATCH 046/179] Trigger build with new base image --- base_images.json | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/base_images.json b/base_images.json index 42a66810..66871f9f 100644 --- a/base_images.json +++ b/base_images.json @@ -7,7 +7,7 @@ "destStage": "edge", "destNamespace": "build-images", "destImage": "ubi8", - "tag": "8.8-1032", + "tag": "8.8-1067.1696517599", "updatePackages": [] }, { @@ -18,7 +18,7 @@ "destStage": "edge", "destNamespace": "build-images", "destImage": "ubi8-minimal", - "tag": "8.8-1037", + "tag": "8.8-1072.1696517598", "updatePackages": [] }, { @@ -29,7 +29,7 @@ "destStage": "edge", "destNamespace": "build-images", "destImage": "ubi9-micro", - "tag": "9.2-13", + "tag": "9.2-15.1696515526", "updatePackages": [] }, { @@ -40,21 +40,21 @@ "destStage": "edge", "destNamespace": "build-images", "destImage": "helm-operator", - "tag": "v1.31.0", + "tag": "v1.32.0", "updatePackages": [] }, { "imageType": "node", "sourceImage": "ubi8-minimal", - "sourceTag": "8.8-1037", + "sourceTag": "8.8-1072.1696517598", "destImage": "node-v18-ubi8-minimal", - "nodeVersion": "18.17.1" + "nodeVersion": "18.18.1" }, { "imageType": "liberty", "sourceImage": "node-v18-ubi8-minimal", - "sourceTag": "18.17.1_8.8-1037", + "sourceTag": "18.18.1_8.8-1072.1696517598", "destImage": "liberty11-ubi8-minimal", - "libertyVersion": "23.0.0.8" + "libertyVersion": "23.0.0.9" } ] From 32e93aed1e0b86cd959e5d6efa86a847fd385d4d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 13 Oct 2023 00:36:36 +0800 Subject: [PATCH 047/179] build(deps): bump golang.org/x/net from 0.9.0 to 0.17.0 (#979) Bumps [golang.org/x/net](https://github.com/golang/net) from 0.9.0 to 0.17.0. - [Commits](https://github.com/golang/net/compare/v0.9.0...v0.17.0) --- updated-dependencies: - dependency-name: golang.org/x/net dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 8 ++++---- go.sum | 16 ++++++++-------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/go.mod b/go.mod index e9797cad..18e6eef3 100644 --- a/go.mod +++ b/go.mod @@ -78,11 +78,11 @@ require ( go.uber.org/atomic v1.7.0 // indirect go.uber.org/multierr v1.6.0 // indirect go.uber.org/zap v1.19.1 // indirect - golang.org/x/net v0.9.0 // indirect + golang.org/x/net v0.17.0 // indirect golang.org/x/oauth2 v0.7.0 // indirect - golang.org/x/sys v0.7.0 // indirect - golang.org/x/term v0.7.0 // indirect - golang.org/x/text v0.9.0 // indirect + golang.org/x/sys v0.13.0 // indirect + golang.org/x/term v0.13.0 // indirect + golang.org/x/text v0.13.0 // indirect golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect google.golang.org/appengine v1.6.7 // indirect diff --git a/go.sum b/go.sum index 5e99f9df..1988aba9 100644 --- a/go.sum +++ b/go.sum @@ -1148,8 +1148,8 @@ golang.org/x/net v0.0.0-20210825183410-e898025ed96a/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM= -golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= +golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= +golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1271,12 +1271,12 @@ golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU= -golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= +golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 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.7.0 h1:BEvjmm5fURWqcfbSKTdpkDXYBrUS1c0m8agp14W48vQ= -golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= +golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek= +golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1287,8 +1287,8 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= -golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= From 688c56de010810a9576e7cdd908f3f6553fbfc4a Mon Sep 17 00:00:00 2001 From: YuChen Shen <59578388+YCShen1010@users.noreply.github.com> Date: Fri, 13 Oct 2023 16:38:37 -0400 Subject: [PATCH 048/179] list out basic permission need by ODLM (#980) Signed-off-by: YuChen --- ...fecycle-manager.clusterserviceversion.yaml | 45 ++++++++++++++++++- ...fecycle-manager.clusterserviceversion.yaml | 2 +- config/rbac/role.yaml | 41 +++++++++++++++++ 3 files changed, 85 insertions(+), 3 deletions(-) diff --git a/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml b/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml index a0f81435..1eda0f1e 100644 --- a/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml +++ b/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml @@ -134,9 +134,9 @@ metadata: API to manage the lifecycle of operands. nss.operator.ibm.com/managed-operators: ibm-odlm olm.skipRange: '>=1.2.0 <4.2.1' + operators.openshift.io/infrastructure-features: '["disconnected"]' operators.operatorframework.io/builder: operator-sdk-v1.24.0 operators.operatorframework.io/project_layout: go.kubebuilder.io/v3 - operators.openshift.io/infrastructure-features: '["disconnected"]' repository: https://github.com/IBM/operand-deployment-lifecycle-manager support: IBM labels: @@ -649,8 +649,8 @@ spec: memory: 512Mi requests: cpu: 200m - memory: 200Mi ephemeral-storage: 256Mi + memory: 200Mi securityContext: allowPrivilegeEscalation: false capabilities: @@ -676,6 +676,47 @@ spec: - patch - update - watch + - apiGroups: + - operator.ibm.com + resources: + - operandconfigs + - operandregistries + - operandrequests + - operandbindinfos + verbs: + - create + - delete + - get + - list + - patch + - update + - watch + - apiGroups: + - "" + resources: + - configmaps + - secrets + - services + verbs: + - create + - delete + - get + - list + - patch + - update + - watch + - apiGroups: + - route.openshift.io + resources: + - routes + verbs: + - create + - delete + - get + - list + - patch + - update + - watch serviceAccountName: operand-deployment-lifecycle-manager strategy: deployment installModes: diff --git a/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml b/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml index 2b580600..fa0dd58b 100644 --- a/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml +++ b/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml @@ -12,9 +12,9 @@ metadata: API to manage the lifecycle of operands. nss.operator.ibm.com/managed-operators: ibm-odlm olm.skipRange: '>=1.2.0 <4.2.1' + operators.openshift.io/infrastructure-features: '["disconnected"]' operators.operatorframework.io/builder: operator-sdk-v1.2.0 operators.operatorframework.io/project_layout: go.kubebuilder.io/v2 - operators.openshift.io/infrastructure-features: '["disconnected"]' repository: https://github.com/IBM/operand-deployment-lifecycle-manager support: IBM labels: diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml index 0281f208..52a722da 100644 --- a/config/rbac/role.yaml +++ b/config/rbac/role.yaml @@ -28,3 +28,44 @@ rules: - patch - update - watch +- verbs: + - create + - delete + - get + - list + - patch + - update + - watch + apiGroups: + - operator.ibm.com + resources: + - operandconfigs + - operandregistries + - operandrequests + - operandbindinfos +- verbs: + - create + - delete + - get + - list + - patch + - update + - watch + apiGroups: + - '' + resources: + - configmaps + - secrets + - services +- verbs: + - create + - delete + - get + - list + - patch + - update + - watch + apiGroups: + - route.openshift.io + resources: + - routes From ffcfedcbca389dc71f0c6f90c5f3279b4827dd3b Mon Sep 17 00:00:00 2001 From: Daniel Fan Date: Mon, 16 Oct 2023 17:44:40 -0400 Subject: [PATCH 049/179] Add additional explicitly listed permission (#981) Signed-off-by: Daniel Fan --- ...fecycle-manager.clusterserviceversion.yaml | 32 ++++++++++++++++++- config/manager/manager.yaml | 2 ++ config/rbac/role.yaml | 30 +++++++++++++++++ 3 files changed, 63 insertions(+), 1 deletion(-) diff --git a/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml b/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml index 1eda0f1e..2761fa34 100644 --- a/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml +++ b/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml @@ -594,9 +594,9 @@ spec: app.kubernetes.io/instance: operand-deployment-lifecycle-manager app.kubernetes.io/managed-by: operand-deployment-lifecycle-manager app.kubernetes.io/name: operand-deployment-lifecycle-manager - productName: IBM_Cloud_Platform_Common_Services intent: projected-odlm name: operand-deployment-lifecycle-manager + productName: IBM_Cloud_Platform_Common_Services spec: affinity: nodeAffinity: @@ -680,9 +680,13 @@ spec: - operator.ibm.com resources: - operandconfigs + - operandconfigs/status - operandregistries + - operandregistries/status - operandrequests + - operandrequests/status - operandbindinfos + - operandbindinfos/status verbs: - create - delete @@ -697,6 +701,7 @@ spec: - configmaps - secrets - services + - namespaces verbs: - create - delete @@ -717,6 +722,31 @@ spec: - patch - update - watch + - apiGroups: + - operators.coreos.com + resources: + - operatorgroups + - installplans + verbs: + - create + - delete + - get + - list + - patch + - update + - watch + - apiGroups: + - k8s.keycloak.org + resources: + - keycloaks + verbs: + - create + - delete + - get + - list + - patch + - update + - watch serviceAccountName: operand-deployment-lifecycle-manager strategy: deployment installModes: diff --git a/config/manager/manager.yaml b/config/manager/manager.yaml index 1ddf67b9..2262f521 100644 --- a/config/manager/manager.yaml +++ b/config/manager/manager.yaml @@ -10,6 +10,7 @@ metadata: app.kubernetes.io/instance: "operand-deployment-lifecycle-manager" app.kubernetes.io/managed-by: "operand-deployment-lifecycle-manager" app.kubernetes.io/name: "operand-deployment-lifecycle-manager" + productName: IBM_Cloud_Platform_Common_Services name: operand-deployment-lifecycle-manager namespace: system spec: @@ -24,6 +25,7 @@ spec: app.kubernetes.io/instance: operand-deployment-lifecycle-manager app.kubernetes.io/managed-by: "operand-deployment-lifecycle-manager" app.kubernetes.io/name: "operand-deployment-lifecycle-manager" + productName: IBM_Cloud_Platform_Common_Services intent: projected-odlm annotations: productName: "IBM Cloud Platform Common Services" diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml index 52a722da..3fabbee9 100644 --- a/config/rbac/role.yaml +++ b/config/rbac/role.yaml @@ -40,9 +40,13 @@ rules: - operator.ibm.com resources: - operandconfigs + - operandconfigs/status - operandregistries + - operandregistries/status - operandrequests + - operandrequests/status - operandbindinfos + - operandbindinfos/status - verbs: - create - delete @@ -57,6 +61,7 @@ rules: - configmaps - secrets - services + - namespaces - verbs: - create - delete @@ -69,3 +74,28 @@ rules: - route.openshift.io resources: - routes +- verbs: + - create + - delete + - get + - list + - patch + - update + - watch + apiGroups: + - operators.coreos.com + resources: + - operatorgroups + - installplans +- verbs: + - create + - delete + - get + - list + - patch + - update + - watch + apiGroups: + - k8s.keycloak.org + resources: + - keycloaks From 7720714fb02e112a2f34b69c87f478f2d16556b7 Mon Sep 17 00:00:00 2001 From: Travis CI User Date: Wed, 18 Oct 2023 17:02:26 +0000 Subject: [PATCH 050/179] Trigger build with new base image --- base_images.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/base_images.json b/base_images.json index 66871f9f..b92f0a64 100644 --- a/base_images.json +++ b/base_images.json @@ -48,13 +48,13 @@ "sourceImage": "ubi8-minimal", "sourceTag": "8.8-1072.1696517598", "destImage": "node-v18-ubi8-minimal", - "nodeVersion": "18.18.1" + "nodeVersion": "18.18.2" }, { "imageType": "liberty", "sourceImage": "node-v18-ubi8-minimal", - "sourceTag": "18.18.1_8.8-1072.1696517598", + "sourceTag": "18.18.2_8.8-1072.1696517598", "destImage": "liberty11-ubi8-minimal", - "libertyVersion": "23.0.0.9" + "libertyVersion": "23.0.0.10" } ] From a85192d471c77573072c6e150ec50fddf4446d96 Mon Sep 17 00:00:00 2001 From: YuChen Shen <59578388+YCShen1010@users.noreply.github.com> Date: Thu, 19 Oct 2023 15:50:42 -0400 Subject: [PATCH 051/179] add finalizers permission (#985) Signed-off-by: YuChen --- ...nd-deployment-lifecycle-manager.clusterserviceversion.yaml | 4 ++++ config/rbac/role.yaml | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml b/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml index 2761fa34..b411e306 100644 --- a/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml +++ b/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml @@ -681,12 +681,16 @@ spec: resources: - operandconfigs - operandconfigs/status + - operandconfigs/finalizers - operandregistries - operandregistries/status + - operandregistries/finalizers - operandrequests - operandrequests/status + - operandrequests/finalizers - operandbindinfos - operandbindinfos/status + - operandbindinfos/finalizers verbs: - create - delete diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml index 3fabbee9..3ae85fa3 100644 --- a/config/rbac/role.yaml +++ b/config/rbac/role.yaml @@ -41,12 +41,16 @@ rules: resources: - operandconfigs - operandconfigs/status + - operandconfigs/finalizers - operandregistries - operandregistries/status + - operandregistries/finalizers - operandrequests - operandrequests/status + - operandrequests/finalizers - operandbindinfos - operandbindinfos/status + - operandbindinfos/finalizers - verbs: - create - delete From f8c7ca17fda3f47ab3159424f25386b78d6aea81 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 20 Oct 2023 22:07:40 +0800 Subject: [PATCH 052/179] build(deps): bump golang from 1.21.2-bullseye to 1.21.3-bullseye (#977) Bumps golang from 1.21.2-bullseye to 1.21.3-bullseye. --- updated-dependencies: - dependency-name: golang dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index a901bc95..0464784b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # Build the manager binary -FROM golang:1.21.2-bullseye as builder +FROM golang:1.21.3-bullseye as builder ARG GOARCH WORKDIR /workspace From 41c5f2da5986230abb78485a54aa75574d41080a Mon Sep 17 00:00:00 2001 From: Daniel Fan Date: Fri, 20 Oct 2023 14:10:41 -0400 Subject: [PATCH 053/179] set OwnerReference for resources created by OperandRequest (#983) * set OwnerReference for resources created by OperandRequest Signed-off-by: Daniel Fan * fix lint issue Signed-off-by: Daniel Fan --------- Signed-off-by: Daniel Fan --- .../operandrequest/reconcile_operand.go | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/controllers/operandrequest/reconcile_operand.go b/controllers/operandrequest/reconcile_operand.go index cb1730be..cb445db3 100644 --- a/controllers/operandrequest/reconcile_operand.go +++ b/controllers/operandrequest/reconcile_operand.go @@ -384,7 +384,7 @@ func (r *Reconciler) reconcileCRwithRequest(ctx context.Context, requestInstance crFromRequest.SetAPIVersion(operand.APIVersion) crFromRequest.SetKind(operand.Kind) // Set the OperandRequest as the controller of the CR from request - if err := controllerutil.SetControllerReference(requestInstance, &crFromRequest, r.Scheme); err != nil { + if err := controllerutil.SetOwnerReference(requestInstance, &crFromRequest, r.Scheme); err != nil { merr.Add(errors.Wrapf(err, "failed to set ownerReference for custom resource %s/%s", requestKey.Namespace, name)) } @@ -405,7 +405,7 @@ func (r *Reconciler) reconcileCRwithRequest(ctx context.Context, requestInstance if r.CheckLabel(crFromRequest, map[string]string{constant.OpreqLabel: "true"}) { // Update or Delete Custom resource klog.V(3).Info("Found existing custom resource: " + operand.Kind) - if err := r.updateCustomResource(ctx, crFromRequest, requestKey.Namespace, operand.Kind, operand.Spec.Raw, map[string]interface{}{}); err != nil { + if err := r.updateCustomResource(ctx, crFromRequest, requestKey.Namespace, operand.Kind, operand.Spec.Raw, map[string]interface{}{}, requestInstance); err != nil { return err } statusSpec, err := r.getOperandStatus(crFromRequest) @@ -632,7 +632,7 @@ func (r *Reconciler) createCustomResource(ctx context.Context, crTemplate unstru r.EnsureLabel(crTemplate, map[string]string{constant.OpreqLabel: "true"}) - // Creat the CR + // Create the CR crerr := r.Create(ctx, &crTemplate) if crerr != nil && !apierrors.IsAlreadyExists(crerr) { return errors.Wrap(crerr, "failed to create custom resource") @@ -667,7 +667,7 @@ func (r *Reconciler) existingCustomResource(ctx context.Context, existingCR unst return nil } -func (r *Reconciler) updateCustomResource(ctx context.Context, existingCR unstructured.Unstructured, namespace, crName string, crConfig []byte, configFromALM map[string]interface{}) error { +func (r *Reconciler) updateCustomResource(ctx context.Context, existingCR unstructured.Unstructured, namespace, crName string, crConfig []byte, configFromALM map[string]interface{}, owners ...metav1.Object) error { kind := existingCR.GetKind() apiversion := existingCR.GetAPIVersion() @@ -695,6 +695,14 @@ func (r *Reconciler) updateCustomResource(ctx context.Context, existingCR unstru return true, nil } + forceUpdate := false + for _, owner := range owners { + if err := controllerutil.SetOwnerReference(owner, &existingCR, r.Scheme); err != nil { + return false, errors.Wrapf(err, "failed to set ownerReference for custom resource %s/%s", existingCR.GetNamespace(), existingCR.GetName()) + } + forceUpdate = true + } + configFromALMRaw, err := json.Marshal(configFromALM) if err != nil { klog.Error(err) @@ -721,7 +729,7 @@ func (r *Reconciler) updateCustomResource(ctx context.Context, existingCR unstru CRgeneration := existingCR.GetGeneration() - if reflect.DeepEqual(existingCR.Object["spec"], updatedCRSpec) { + if reflect.DeepEqual(existingCR.Object["spec"], updatedCRSpec) && !forceUpdate { return true, nil } From 975178bd03a0e34263b8a129d3869fe5b2a6f576 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 26 Oct 2023 23:18:46 +0800 Subject: [PATCH 054/179] build(deps): bump google.golang.org/grpc from 1.57.0 to 1.57.1 (#987) Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.57.0 to 1.57.1. - [Release notes](https://github.com/grpc/grpc-go/releases) - [Commits](https://github.com/grpc/grpc-go/compare/v1.57.0...v1.57.1) --- updated-dependencies: - dependency-name: google.golang.org/grpc dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 18e6eef3..acfd297c 100644 --- a/go.mod +++ b/go.mod @@ -87,7 +87,7 @@ require ( gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19 // indirect - google.golang.org/grpc v1.57.0 // indirect + google.golang.org/grpc v1.57.1 // indirect google.golang.org/protobuf v1.30.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ini.v1 v1.66.4 // indirect diff --git a/go.sum b/go.sum index 1988aba9..d6ac5795 100644 --- a/go.sum +++ b/go.sum @@ -1499,8 +1499,8 @@ google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAG google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.57.0 h1:kfzNeI/klCGD2YPMUlaGNT3pxvYfga7smW3Vth8Zsiw= -google.golang.org/grpc v1.57.0/go.mod h1:Sd+9RMTACXwmub0zcNY2c4arhtrbBYD1AUHI/dt16Mo= +google.golang.org/grpc v1.57.1 h1:upNTNqv0ES+2ZOOqACwVtS3Il8M12/+Hz41RCPzAjQg= +google.golang.org/grpc v1.57.1/go.mod h1:Sd+9RMTACXwmub0zcNY2c4arhtrbBYD1AUHI/dt16Mo= google.golang.org/grpc/cmd/protoc-gen-go-grpc v0.0.0-20200709232328-d8193ee9cc3e/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= 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= From 9b77e0670313be749267f4a1f18e2c616d09b9d3 Mon Sep 17 00:00:00 2001 From: Travis CI User Date: Tue, 31 Oct 2023 18:16:05 +0000 Subject: [PATCH 055/179] Trigger build with new base image --- base_images.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/base_images.json b/base_images.json index b92f0a64..0038c5ad 100644 --- a/base_images.json +++ b/base_images.json @@ -7,7 +7,7 @@ "destStage": "edge", "destNamespace": "build-images", "destImage": "ubi8", - "tag": "8.8-1067.1696517599", + "tag": "8.8-1067.1698056881", "updatePackages": [] }, { @@ -18,7 +18,7 @@ "destStage": "edge", "destNamespace": "build-images", "destImage": "ubi8-minimal", - "tag": "8.8-1072.1696517598", + "tag": "8.8-1072.1697626218", "updatePackages": [] }, { @@ -46,14 +46,14 @@ { "imageType": "node", "sourceImage": "ubi8-minimal", - "sourceTag": "8.8-1072.1696517598", + "sourceTag": "8.8-1072.1697626218", "destImage": "node-v18-ubi8-minimal", "nodeVersion": "18.18.2" }, { "imageType": "liberty", "sourceImage": "node-v18-ubi8-minimal", - "sourceTag": "18.18.2_8.8-1072.1696517598", + "sourceTag": "18.18.2_8.8-1072.1697626218", "destImage": "liberty11-ubi8-minimal", "libertyVersion": "23.0.0.10" } From e6f4ba31f3b21c4c219b3f904f345dab6f3e2699 Mon Sep 17 00:00:00 2001 From: Henry Li Date: Tue, 31 Oct 2023 15:00:50 -0400 Subject: [PATCH 056/179] updated Makefile to generate proper CSV (#988) * fixed make manifests for OperandConfig CRD - to have preserve unknown fields for ConfigService.spec Signed-off-by: Henry H Li * regenerated deepcopy Signed-off-by: Henry H Li * added make kustomize Signed-off-by: Henry H Li * added make run-bundle and make cleanup-bundle - updated related make targets for generating proper bundle CSV - yq automatically added indentation to CSV downgraded operator sdk version to v1.29.0 - because hitting same issue as cs-operator https://github.com/operator-framework/operator-sdk/issues/6584 Signed-off-by: Henry H Li * changed tests to use ExtensionWithMarker type Signed-off-by: Henry H Li --------- Signed-off-by: Henry H Li --- Makefile | 37 +- api/v1alpha1/operandconfig_types.go | 7 +- api/v1alpha1/zz_generated.deepcopy.go | 82 ++- bundle.Dockerfile | 2 +- ...fecycle-manager.clusterserviceversion.yaml | 549 +++++++++--------- bundle/metadata/annotations.yaml | 3 +- common/Makefile.common.mk | 4 - ...fecycle-manager.clusterserviceversion.yaml | 2 +- controllers/testutil/test_util.go | 12 +- test/e2e/helpers_test.go | 17 +- 10 files changed, 413 insertions(+), 302 deletions(-) diff --git a/Makefile b/Makefile index c9dab00d..0813c1f8 100644 --- a/Makefile +++ b/Makefile @@ -18,6 +18,8 @@ KUBECTL ?= $(shell which kubectl) OPERATOR_SDK ?= $(shell which operator-sdk) OPM ?= $(shell which opm) +KUSTOMIZE ?= $(shell which kustomize) +KUSTOMIZE_VERSION=v3.8.7 ENVCRDS_DIR=$(shell pwd)/testcrds @@ -33,7 +35,9 @@ VERSION ?= $(shell git describe --exact-match 2> /dev/null || \ RELEASE_VERSION ?= $(shell cat ./version/version.go | grep "Version =" | awk '{ print $$3}' | tr -d '"') LATEST_VERSION ?= latest OPERATOR_SDK_VERSION=v1.24.0 -YQ_VERSION=v4.3.1 +YQ_VERSION=v4.17.2 +DEFAULT_CHANNEL ?= v$(shell cat ./version/version.go | grep "Version =" | awk '{ print $$3}' | tr -d '"' | cut -d '.' -f1,2) +CHANNELS ?= $(DEFAULT_CHANNEL) LOCAL_OS := $(shell uname) ifeq ($(LOCAL_OS),Linux) @@ -134,6 +138,19 @@ else YQ=$(shell which yq) endif +kustomize: ## Install kustomize +ifeq (, $(shell which kustomize 2>/dev/null)) + @{ \ + set -e ;\ + mkdir -p bin ;\ + echo "Downloading kustomize ...";\ + curl -sSLo - https://github.com/kubernetes-sigs/kustomize/releases/download/kustomize/$(KUSTOMIZE_VERSION)/kustomize_$(KUSTOMIZE_VERSION)_$(LOCAL_OS)_$(LOCAL_ARCH).tar.gz | tar xzf - -C bin/ ;\ + } +KUSTOMIZE=$(realpath ./bin/kustomize) +else +KUSTOMIZE=$(shell which kustomize) +endif + operator-sdk: ifneq ($(shell operator-sdk version | cut -d ',' -f1 | cut -d ':' -f2 | tr -d '"' | xargs | cut -d '.' -f1), v1) @{ \ @@ -191,6 +208,10 @@ bundle-manifests: $(KUSTOMIZE) build config/manifests | $(OPERATOR_SDK) generate bundle \ -q --overwrite --version $(OPERATOR_VERSION) $(BUNDLE_METADATA_OPTS) $(OPERATOR_SDK) bundle validate ./bundle + $(YQ) eval-all -i '.spec.relatedImages = load("config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml").spec.relatedImages' bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml + # Need to replace fields this way to avoid changing PROJECT name and CSV file name, which may or may not impact CICD automation + $(YQ) e -i '.annotations["operators.operatorframework.io.bundle.package.v1"] = "ibm-odlm"' bundle/metadata/annotations.yaml + sed -i'' s/operand-deployment-lifecycle-manager/ibm-odlm/ bundle.Dockerfile generate-all: manifests kustomize operator-sdk ## Generate bundle manifests, metadata and package manifests $(OPERATOR_SDK) generate kustomize manifests -q @@ -245,8 +266,8 @@ build-operator-image: $(CONFIG_DOCKER_TARGET) ## Build the operator image. --build-arg GOARCH=$(LOCAL_ARCH) -f Dockerfile . build-operator-dev-image: ## Build the operator dev image. - @echo "Building the $(OPERATOR_IMAGE_NAME) docker image..." - @docker build -t $(OPERATOR_IMAGE_NAME):$(VERSION) \ + @echo "Building the $(DEV_REGISTRY)/$(OPERATOR_IMAGE_NAME) docker image..." + @docker build -t $(DEV_REGISTRY)/$(OPERATOR_IMAGE_NAME):$(VERSION) \ --build-arg VCS_REF=$(VCS_REF) --build-arg VCS_URL=$(VCS_URL) \ --build-arg GOARCH=$(LOCAL_ARCH) -f Dockerfile . @@ -260,7 +281,6 @@ build-test-operator-image: $(CONFIG_DOCKER_TARGET) ## Build the operator test im build-push-dev-image: build-operator-dev-image ## Build and push the operator dev images. @echo "Pushing the $(DEV_REGISTRY)/$(OPERATOR_IMAGE_NAME):$(VERSION) docker image to $(DEV_REGISTRY)..." - @docker tag $(OPERATOR_IMAGE_NAME):$(VERSION) $(DEV_REGISTRY)/$(OPERATOR_IMAGE_NAME):$(VERSION) @docker push $(DEV_REGISTRY)/$(OPERATOR_IMAGE_NAME):$(VERSION) build-push-image: $(CONFIG_DOCKER_TARGET) build-operator-image ## Build and push the operator images. @@ -269,12 +289,9 @@ build-push-image: $(CONFIG_DOCKER_TARGET) build-operator-image ## Build and pus @docker push $(ARTIFACTORYA_REGISTRY)/$(OPERATOR_IMAGE_NAME)-$(LOCAL_ARCH):$(VERSION) build-push-bundle-image: yq - @cp -f bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml /tmp/operand-deployment-lifecycle-manager.clusterserviceversion.yaml - $(YQ) eval -i 'del(.spec.replaces)' bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml @docker build -f bundle.Dockerfile -t $(QUAY_REGISTRY)/$(BUNDLE_IMAGE_NAME)-$(LOCAL_ARCH):$(VERSION) . @echo "Pushing the $(BUNDLE_IMAGE_NAME) docker image for $(LOCAL_ARCH)..." @docker push $(QUAY_REGISTRY)/$(BUNDLE_IMAGE_NAME)-$(LOCAL_ARCH):$(VERSION) - @mv /tmp/operand-deployment-lifecycle-manager.clusterserviceversion.yaml bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml build-catalog-source: @opm -u docker index add --bundles $(QUAY_REGISTRY)/$(BUNDLE_IMAGE_NAME)-$(LOCAL_ARCH):$(VERSION) --tag $(QUAY_REGISTRY)/$(OPERATOR_IMAGE_NAME)-catalog:$(VERSION) @@ -285,6 +302,12 @@ build-catalog: build-push-bundle-image build-catalog-source multiarch-image: $(CONFIG_DOCKER_TARGET) ## Generate multiarch images for operator image. @MAX_PULLING_RETRY=20 RETRY_INTERVAL=30 common/scripts/multiarch_image.sh $(ARTIFACTORYA_REGISTRY) $(OPERATOR_IMAGE_NAME) $(VERSION) $(RELEASE_VERSION) +run-bundle: + $(OPERATOR_SDK) run bundle $(QUAY_REGISTRY)/$(BUNDLE_IMAGE_NAME)-$(LOCAL_ARCH):$(VERSION) --install-mode OwnNamespace + +cleanup-bundle: + $(OPERATOR_SDK) cleanup ibm-odlm + ##@ Help help: ## Display this help @echo "Usage:\n make \033[36m\033[0m" diff --git a/api/v1alpha1/operandconfig_types.go b/api/v1alpha1/operandconfig_types.go index 8fad0874..3c124ed5 100644 --- a/api/v1alpha1/operandconfig_types.go +++ b/api/v1alpha1/operandconfig_types.go @@ -31,12 +31,17 @@ type OperandConfigSpec struct { Services []ConfigService `json:"services,omitempty"` } +// +kubebuilder:pruning:PreserveUnknownFields +type ExtensionWithMarker struct { + runtime.RawExtension `json:",inline"` +} + // ConfigService defines the configuration of the service. type ConfigService struct { // Name is the subscription name. Name string `json:"name"` // Spec is the configuration map of custom resource. - Spec map[string]runtime.RawExtension `json:"spec,omitempty"` + Spec map[string]ExtensionWithMarker `json:"spec,omitempty"` // State is a flag to enable or disable service. State string `json:"state,omitempty"` // Resources is used to specify the kubernetes resources that are needed for the service. diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index ad04906b..2e108765 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -80,7 +80,7 @@ func (in *ConfigService) DeepCopyInto(out *ConfigService) { *out = *in if in.Spec != nil { in, out := &in.Spec, &out.Spec - *out = make(map[string]runtime.RawExtension, len(*in)) + *out = make(map[string]ExtensionWithMarker, len(*in)) for key, val := range *in { (*out)[key] = *val.DeepCopy() } @@ -126,6 +126,22 @@ func (in *CrStatus) DeepCopy() *CrStatus { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ExtensionWithMarker) DeepCopyInto(out *ExtensionWithMarker) { + *out = *in + in.RawExtension.DeepCopyInto(&out.RawExtension) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExtensionWithMarker. +func (in *ExtensionWithMarker) DeepCopy() *ExtensionWithMarker { + if in == nil { + return nil + } + out := new(ExtensionWithMarker) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *MemberPhase) DeepCopyInto(out *MemberPhase) { *out = *in @@ -612,6 +628,13 @@ func (in *OperandRequestStatus) DeepCopyInto(out *OperandRequestStatus) { (*in)[i].DeepCopyInto(&(*out)[i]) } } + if in.Services != nil { + in, out := &in.Services, &out.Services + *out = make([]ServiceStatus, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OperandRequestStatus. @@ -624,6 +647,26 @@ func (in *OperandRequestStatus) DeepCopy() *OperandRequestStatus { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *OperandStatus) DeepCopyInto(out *OperandStatus) { + *out = *in + if in.ManagedResources != nil { + in, out := &in.ManagedResources, &out.ManagedResources + *out = make([]ResourceStatus, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OperandStatus. +func (in *OperandStatus) DeepCopy() *OperandStatus { + if in == nil { + return nil + } + out := new(OperandStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Operator) DeepCopyInto(out *Operator) { *out = *in @@ -706,6 +749,21 @@ func (in *Request) DeepCopy() *Request { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ResourceStatus) DeepCopyInto(out *ResourceStatus) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceStatus. +func (in *ResourceStatus) DeepCopy() *ResourceStatus { + if in == nil { + return nil + } + out := new(ResourceStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *SecretConfigmap) DeepCopyInto(out *SecretConfigmap) { *out = *in @@ -720,3 +778,25 @@ func (in *SecretConfigmap) DeepCopy() *SecretConfigmap { in.DeepCopyInto(out) return out } + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ServiceStatus) DeepCopyInto(out *ServiceStatus) { + *out = *in + if in.Resources != nil { + in, out := &in.Resources, &out.Resources + *out = make([]OperandStatus, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServiceStatus. +func (in *ServiceStatus) DeepCopy() *ServiceStatus { + if in == nil { + return nil + } + out := new(ServiceStatus) + in.DeepCopyInto(out) + return out +} diff --git a/bundle.Dockerfile b/bundle.Dockerfile index b5cf0768..c12c2221 100644 --- a/bundle.Dockerfile +++ b/bundle.Dockerfile @@ -7,7 +7,7 @@ LABEL operators.operatorframework.io.bundle.metadata.v1=metadata/ LABEL operators.operatorframework.io.bundle.package.v1=ibm-odlm LABEL operators.operatorframework.io.bundle.channels.v1=v4.2 LABEL operators.operatorframework.io.bundle.channel.default.v1=v4.2 -LABEL operators.operatorframework.io.metrics.builder=operator-sdk-v1.24.0 +LABEL operators.operatorframework.io.metrics.builder=operator-sdk-v1.29.0 LABEL operators.operatorframework.io.metrics.mediatype.v1=metrics+v1 LABEL operators.operatorframework.io.metrics.project_layout=go.kubebuilder.io/v3 diff --git a/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml b/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml index b411e306..507a8262 100644 --- a/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml +++ b/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml @@ -129,13 +129,12 @@ metadata: categories: Developer Tools, Monitoring, Logging & Tracing, Security certified: "false" containerImage: icr.io/cpopen/odlm:latest - createdAt: "2020-11-12T17:05:48Z" - description: The Operand Deployment Lifecycle Manager provides a Kubernetes CRD-based - API to manage the lifecycle of operands. + createdAt: "2023-10-30T14:30:29Z" + description: The Operand Deployment Lifecycle Manager provides a Kubernetes CRD-based API to manage the lifecycle of operands. nss.operator.ibm.com/managed-operators: ibm-odlm olm.skipRange: '>=1.2.0 <4.2.1' operators.openshift.io/infrastructure-features: '["disconnected"]' - operators.operatorframework.io/builder: operator-sdk-v1.24.0 + operators.operatorframework.io/builder: operator-sdk-v1.29.0 operators.operatorframework.io/project_layout: go.kubebuilder.io/v3 repository: https://github.com/IBM/operand-deployment-lifecycle-manager support: IBM @@ -150,72 +149,72 @@ spec: apiservicedefinitions: {} customresourcedefinitions: owned: - - description: OperandBindInfo is the Schema for the operandbindinfoes API. Documentation For additional details regarding install parameters check https://ibm.biz/icpfs39install. License By installing this product you accept the license terms https://ibm.biz/icpfs39license - displayName: OperandBindInfo - kind: OperandBindInfo - name: operandbindinfos.operator.ibm.com - statusDescriptors: - - description: Phase describes the overall phase of OperandBindInfo. - displayName: Phase - path: phase - x-descriptors: - - urn:alm:descriptor:io.kubernetes.phase - version: v1alpha1 - - description: OperandConfig is the Schema for the operandconfigs API. Documentation For additional details regarding install parameters check https://ibm.biz/icpfs39install. License By installing this product you accept the license terms https://ibm.biz/icpfs39license - displayName: OperandConfig - kind: OperandConfig - name: operandconfigs.operator.ibm.com - specDescriptors: - - description: Services is a list of configuration of service. - displayName: Operand Services Config List - path: services - statusDescriptors: - - description: Phase describes the overall phase of operands in the OperandConfig. - displayName: Phase - path: phase - x-descriptors: - - urn:alm:descriptor:io.kubernetes.phase - version: v1alpha1 - - description: OperandRegistry is the Schema for the operandregistries API. Documentation For additional details regarding install parameters check https://ibm.biz/icpfs39install. License By installing this product you accept the license terms https://ibm.biz/icpfs39license - displayName: OperandRegistry - kind: OperandRegistry - name: operandregistries.operator.ibm.com - specDescriptors: - - description: Operators is a list of operator OLM definition. - displayName: Operators Registry List - path: operators - statusDescriptors: - - description: Conditions represents the current state of the Request Service. - displayName: Conditions - path: conditions - x-descriptors: - - urn:alm:descriptor:io.kubernetes.conditions - - description: Phase describes the overall phase of operators in the OperandRegistry. - displayName: Phase - path: phase - x-descriptors: - - urn:alm:descriptor:io.kubernetes.phase - version: v1alpha1 - - description: OperandRequest is the Schema for the operandrequests API. Documentation For additional details regarding install parameters check https://ibm.biz/icpfs39install. License By installing this product you accept the license terms https://ibm.biz/icpfs39license - displayName: OperandRequest - kind: OperandRequest - name: operandrequests.operator.ibm.com - specDescriptors: - - description: Requests defines a list of operands installation. - displayName: Operators Request List - path: requests - statusDescriptors: - - description: Conditions represents the current state of the Request Service. - displayName: Conditions - path: conditions - x-descriptors: - - urn:alm:descriptor:io.kubernetes.conditions - - description: Phase is the cluster running phase. - displayName: Phase - path: phase - x-descriptors: - - urn:alm:descriptor:io.kubernetes.phase - version: v1alpha1 + - description: OperandBindInfo is the Schema for the operandbindinfoes API. Documentation For additional details regarding install parameters check https://ibm.biz/icpfs39install. License By installing this product you accept the license terms https://ibm.biz/icpfs39license + displayName: OperandBindInfo + kind: OperandBindInfo + name: operandbindinfos.operator.ibm.com + statusDescriptors: + - description: Phase describes the overall phase of OperandBindInfo. + displayName: Phase + path: phase + x-descriptors: + - urn:alm:descriptor:io.kubernetes.phase + version: v1alpha1 + - description: OperandConfig is the Schema for the operandconfigs API. Documentation For additional details regarding install parameters check https://ibm.biz/icpfs39install. License By installing this product you accept the license terms https://ibm.biz/icpfs39license + displayName: OperandConfig + kind: OperandConfig + name: operandconfigs.operator.ibm.com + specDescriptors: + - description: Services is a list of configuration of service. + displayName: Operand Services Config List + path: services + statusDescriptors: + - description: Phase describes the overall phase of operands in the OperandConfig. + displayName: Phase + path: phase + x-descriptors: + - urn:alm:descriptor:io.kubernetes.phase + version: v1alpha1 + - description: OperandRegistry is the Schema for the operandregistries API. Documentation For additional details regarding install parameters check https://ibm.biz/icpfs39install. License By installing this product you accept the license terms https://ibm.biz/icpfs39license + displayName: OperandRegistry + kind: OperandRegistry + name: operandregistries.operator.ibm.com + specDescriptors: + - description: Operators is a list of operator OLM definition. + displayName: Operators Registry List + path: operators + statusDescriptors: + - description: Conditions represents the current state of the Request Service. + displayName: Conditions + path: conditions + x-descriptors: + - urn:alm:descriptor:io.kubernetes.conditions + - description: Phase describes the overall phase of operators in the OperandRegistry. + displayName: Phase + path: phase + x-descriptors: + - urn:alm:descriptor:io.kubernetes.phase + version: v1alpha1 + - description: OperandRequest is the Schema for the operandrequests API. Documentation For additional details regarding install parameters check https://ibm.biz/icpfs39install. License By installing this product you accept the license terms https://ibm.biz/icpfs39license + displayName: OperandRequest + kind: OperandRequest + name: operandrequests.operator.ibm.com + specDescriptors: + - description: Requests defines a list of operands installation. + displayName: Operators Request List + path: requests + statusDescriptors: + - description: Conditions represents the current state of the Request Service. + displayName: Conditions + path: conditions + x-descriptors: + - urn:alm:descriptor:io.kubernetes.conditions + - description: Phase is the cluster running phase. + displayName: Phase + path: phase + x-descriptors: + - urn:alm:descriptor:io.kubernetes.phase + version: v1alpha1 description: |- # Introduction @@ -558,226 +557,226 @@ spec: The Operand Deployment Lifecycle Manager supports running under the OpenShift Container Platform default restricted security context constraints. displayName: Operand Deployment Lifecycle Manager icon: - - base64data: iVBORw0KGgoAAAANSUhEUgAAAK8AAACvCAMAAAC8TH5HAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAB1UExURQAAAJGS77CC4pCS75yM64uV8pSQ7puA85OV87OB4auF5Hyd+H2c936b9n6b94Ca9n+b9n+b9n+b9qOJ56SI55yM6qSI536b96aH5q2D45mN64OZ9ZWQ7oyU8XWg+6uG5oqg/p6L6m+k/ZuY+3mr/6qQ9LqM80D8C0oAAAAbdFJOUwA67R4KKxMBBP6ak6vZgVtJxG5ot+hQ7YDVkwC2C58AAAuSSURBVHja7ZyJerK8EoCDCSTKjoiIS13of/+XeGYm4NLKrvj1OYxt7aa8TiazJZGxSSaZZJJJJvmcSCn/Eq7Cz79DLJk0rb+kXdM9nz0m/4p2mZufz3lAZvEn1HsGye2J9128h7/Gezj8Nd7D3+I9/xu8SjWHrS76bfN8A+NsYxjowCvbPN+QSGB6kWi6QHteyQLPfx+wYsH2eHSthgu05lXMy/PceRcwxtnjdnts4mjLq5hBceVdcVsya71FMeov0JIXMuQwR+DoXX5EMgf0uz2GrDYbb8mrmE+4Z/NdvDCApN+jX3uFdrySqfW70wzFbFLwWtVNkXa8ONlIvfx9Dk0xSyvYq0NpxasYJ9o8emcUVCw6EjGvuUpLXgfVm9cP1fAZp1yyCKeGBf8pB96g9jUZ57c6s1vIIAUfjXqY9eFg1yiuKJnOECzeW+TJm0+rxRGGWfcP7/dld8bZwqcp/dJqIs9hrJIJ/JD2abV5j1StfJn1/pofo/Kx0ae1KfAO7/Vld7anfVpf28M5kKPDc9kYLRW4RDhIwYV/PozVUAF39Qre3BmrvsM04nisjHHyJlUjZEOefuBj8UIA81zHfGJ84BYeHAP9LKseP1r5LNnvOlHeXJgqRZbUPzT97PHvBVb48VCX09W54du2u3ZJwjD0It/gqmCue/yoolm4b7tQjmohh7cGAWzHC8x/qOFOZmBG4bbERDkQrVYyiGP7iPwPLGrgsAofYbePonEJ2CHxAuvjxEjLvfUj7J1BaP0irY3i888SA63l3alWgwKjbXueZztOSBoucOE33huIZdsWHChXRds72O069PyHhSEBDiOynbAEBiGreCGJKoa5zT8GVBzt4QNgXc+wbq4YvW+hSMkDYNa4EYihWqlYtmouSsYTo4XvgWezHKDcI+7xuPbMMp7JH0GEfhZGRMDIG5FRtLG1IGCNvTp/d9nFZhMx/DXYH/cgSBv6SscM+Tyf0P450Lw+iCmbOGAMonOeO/XlMyTjgAsfmWAN9Y53RFy0hDAovXBDSBFBVAIHDdUJ2lre3J6AVG9Hcln5NQyKCUcrd390g5/BtjpNR2KNGwTVpRDSmk6et6jwCv0ScVhpxopxl3DBIjzVjrYk5gVuEPAaw7UP+aFV+0ex5Aq8y/hTYhiE/UXjhibrlBUisUm8hmHwqujuH3IqQLA/0dT+Af8Q34hT8du3QXlR4nrdkxhJ0554nwAXhpvj+hLUo2u/zWoJM1aXy70ZP8e97APWJ+WGbN1AXNP8tedAasM96PLu4Ik2jhpHZLkqgdGM5TNjuKzNnhkiUmneH8CSCe9wpXV429HDlCu7GcV9JwemWoEbWr3rGZx2iMs5F4+T3S1p89DoYGvkUeLCKC67m+uBsVwVuGpI+QVohGtZ6rHrU+Cu/UaP/ps4KY3iWhlipwNwd4Arh1WLCIy4lpA/2yiF4XZ9ehgMuaRgt7r6FMWiC9DuL64YWtyCrQKuEOLe1iJsG+eO2W8eo+POdrvVtdULrgG0Dbg76xW1uCDcm5GCguzDAeNlz0qPqgfzGunJeAl4aOug6KYQ7l2WhI7DZEMqZ7L5a1uBZWTQF3/QVHvmUosOBX0ZVkbfkgNtDYCbDcDVsIKbQYCJBCY/gak7FHQh+bqiX7LwsnuYfr1gqUTCUsPWgsWdF1H2I1/ZoYBMSLs3o3/blyke+FRiEPE9c1Huq9dpV60GWQNmvybSIrCnee0SGIlDJzJfVzwrttTq7bfkUNCSzV71a19pScNOGHrmi9pWV/Uue6lXYpEcBFfgslSOPG0MBTASc/YK3455PEqvyYY5r0G4AeH6gWHqSCyVxQ2s9ksJw9B/ATBYVUy8fdRL6ZhhlPo1HpIyHelM38OmCuA6oWvzwTah69DTbiW6qxdMCdPdAIGLbrC8lyIimxHRgrhQcA+cdoqluxXc0u7qhcTGNBAYeKkB9CTASfJjVuTo7mvoRsO676Ci+LRanVbd91YgLggp2GI1/kpRq7MAXnuDjBhC8Qpkl3UepwIXgblseDQq2XBcUK8bru0hGgbni7ynzrMNs1xOuJDmNQMAsfAI2B0CjOaAvKuuK2aES8C8XU8Sn98H9SKw12/SwfwVzNyArOLOL1lxEpO37/lKFujlpW3UfTSZwpxaQCkXb+JVd3OAAg1xrQ4vFGzC0MDrbuvLSGtRiSVYuonjeNU5MxMWAVudZzct1azdLmUXzGZLV7BCySxG6Zrq4MsFXqv79A7WiLu1OwwLFgElr7VA3LQjLtZnCCx7+KNo7a4BuG3lhRmKWXQ0LME40Gbxsqt6BQH3arExZ+viCl67Ib1rGHFLQPIQL7JFnHTjRfUCb68whR1mXM3dttpjcWvIAS6uNCRxlmVxxypeCVJw3wjl0/LzmrfaVG4kBgFT6ge57wJ4M7OTfmlNS4j+McpB4G2rTfBGkhAwp2UcWfB2cw/FFogBKQvxrhtTLMnMZYJiFG4eeLM0zVLRg3dIzmJvAbfRgiXjS81rXfeBLIE3TTuVQneZeH8Fb4HXFQ0rcGKJcsNFXsRdduYdViSQBQNy0LCilaSIu+R3TeqP8KKLQAXXzjgw3hR5l3erFvoldOOVr9Cv5eK6v1tzXch0UZfLNGEPvGQi3fU7tMi1m45PgCtb4Nin974Lftmd9yUtJZ94q/NgUG9KvA9rWOjgwKATMTqv3mpcbcDgQxaLRbpYyp+89/5tLMF98GTAVZsP4LfpAuXRYnALBwof+0AxejR0EVVpO4ARbvpz96D1GV7FvNoJB4lNDLiQOKofIQSTicQcnzeq5ZUsxTpi8ctQJeVrJmNj8wbEWxHhYNxjXff8UiT1vww1Oq9R59Dgz1gGb5Kff5a62jA/4tD222Ml75J4zd+8uglmfcQB76s2nktsM2w2z8p2yamWG90eTNrd9ly/ALnAtlP8LO5a1FdSo9sv7h3cVvGqGHkXT9Sr+3ZcjO4faNNYUMErkHf2tIeuqBNhjc0bHXEDoVHBa20qeRm1liw1Mq9H29z68Ard+hs7f0BzWD/3S8g7q+TV3RohR8VVLqq34pgR2G8NL9O8alx3Rrvy7Cr3q2LkXTyPClrBY55JgPqCthFGVbxsgbxxRd2jxKCGTS/zpelW0beD8pB4NxVhVw7t2HSvj0m9lfUx5A/zzWw2q0yPHzYHjWEOuDXvWLnhAtL1Gah3XrWsImkL/WjAkoX7au+r00bQ7my+qFr4ekETpFvyUGsOKOAgZrNNZaE2InCx9XF/qVmFQwNGBVevs42n31K9+5oqFxw0GURc22UayXjBenHrY1Z7UJ/FpOCkRsFjWe+SNsLuef2xCm0QMfvwe60pxnGf5v7iNTR/xWZWb8GjWcOFgBtK3FLBM+uTCpatd5aigue1Pngs4yVcp8VphmT+YYuQGIhxm/Fu37w+j0mPBk4+BIy4ett8q52lGJTneJsbHwHGwx/FQYp2Q6wtogCWH8DNLtdt0S1Pi6RICx8JG1nFCluOV9yWLgrrjAI4HfVQNtYu5emw9ri0EyZGWpCNORYxvVuAGZeHgLIuEVZB5UnAqGLryfsLvDx31Gfa6czSSW+D7XRFVZgEyizlRfEm3yJFSaiM+HQ5Ee5ll3SNVgCczkvi+SJ5c+PMMtIV0BLu6RL32P8Lry8pcVHJcZoYlniDcCNJ49Xp+/uk5QK20PP0kLWYP8qsg2zuvl/VyAlQS1bQ7SnjfQ814O7WeF4jX/P/5l//fT2V77svePeNd/gFNam/FN/eZPd9io0B/ojOwMWVsA8/wO1RZvc/nOgTbqfi7okAfDbUe+KDjcVsPq9X81eJPK/g/So476kfWUG1S6vjmcIqYpGkGwT7r4t8FfffdIP7ajmdNlnC2Qto2fWNtixjudRr4a+VLF0uTa4vJF8XKuXbg/Hr33TjffKn3gp/kkkmmWSSSSaZZJJJJplkkkkmmWSS/yf5H6HANgUotAMHAAAAAElFTkSuQmCC - mediatype: image/png + - base64data: iVBORw0KGgoAAAANSUhEUgAAAK8AAACvCAMAAAC8TH5HAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAB1UExURQAAAJGS77CC4pCS75yM64uV8pSQ7puA85OV87OB4auF5Hyd+H2c936b9n6b94Ca9n+b9n+b9n+b9qOJ56SI55yM6qSI536b96aH5q2D45mN64OZ9ZWQ7oyU8XWg+6uG5oqg/p6L6m+k/ZuY+3mr/6qQ9LqM80D8C0oAAAAbdFJOUwA67R4KKxMBBP6ak6vZgVtJxG5ot+hQ7YDVkwC2C58AAAuSSURBVHja7ZyJerK8EoCDCSTKjoiIS13of/+XeGYm4NLKrvj1OYxt7aa8TiazJZGxSSaZZJJJJvmcSCn/Eq7Cz79DLJk0rb+kXdM9nz0m/4p2mZufz3lAZvEn1HsGye2J9128h7/Gezj8Nd7D3+I9/xu8SjWHrS76bfN8A+NsYxjowCvbPN+QSGB6kWi6QHteyQLPfx+wYsH2eHSthgu05lXMy/PceRcwxtnjdnts4mjLq5hBceVdcVsya71FMeov0JIXMuQwR+DoXX5EMgf0uz2GrDYbb8mrmE+4Z/NdvDCApN+jX3uFdrySqfW70wzFbFLwWtVNkXa8ONlIvfx9Dk0xSyvYq0NpxasYJ9o8emcUVCw6EjGvuUpLXgfVm9cP1fAZp1yyCKeGBf8pB96g9jUZ57c6s1vIIAUfjXqY9eFg1yiuKJnOECzeW+TJm0+rxRGGWfcP7/dld8bZwqcp/dJqIs9hrJIJ/JD2abV5j1StfJn1/pofo/Kx0ae1KfAO7/Vld7anfVpf28M5kKPDc9kYLRW4RDhIwYV/PozVUAF39Qre3BmrvsM04nisjHHyJlUjZEOefuBj8UIA81zHfGJ84BYeHAP9LKseP1r5LNnvOlHeXJgqRZbUPzT97PHvBVb48VCX09W54du2u3ZJwjD0It/gqmCue/yoolm4b7tQjmohh7cGAWzHC8x/qOFOZmBG4bbERDkQrVYyiGP7iPwPLGrgsAofYbePonEJ2CHxAuvjxEjLvfUj7J1BaP0irY3i888SA63l3alWgwKjbXueZztOSBoucOE33huIZdsWHChXRds72O069PyHhSEBDiOynbAEBiGreCGJKoa5zT8GVBzt4QNgXc+wbq4YvW+hSMkDYNa4EYihWqlYtmouSsYTo4XvgWezHKDcI+7xuPbMMp7JH0GEfhZGRMDIG5FRtLG1IGCNvTp/d9nFZhMx/DXYH/cgSBv6SscM+Tyf0P450Lw+iCmbOGAMonOeO/XlMyTjgAsfmWAN9Y53RFy0hDAovXBDSBFBVAIHDdUJ2lre3J6AVG9Hcln5NQyKCUcrd390g5/BtjpNR2KNGwTVpRDSmk6et6jwCv0ScVhpxopxl3DBIjzVjrYk5gVuEPAaw7UP+aFV+0ex5Aq8y/hTYhiE/UXjhibrlBUisUm8hmHwqujuH3IqQLA/0dT+Af8Q34hT8du3QXlR4nrdkxhJ0554nwAXhpvj+hLUo2u/zWoJM1aXy70ZP8e97APWJ+WGbN1AXNP8tedAasM96PLu4Ik2jhpHZLkqgdGM5TNjuKzNnhkiUmneH8CSCe9wpXV429HDlCu7GcV9JwemWoEbWr3rGZx2iMs5F4+T3S1p89DoYGvkUeLCKC67m+uBsVwVuGpI+QVohGtZ6rHrU+Cu/UaP/ps4KY3iWhlipwNwd4Arh1WLCIy4lpA/2yiF4XZ9ehgMuaRgt7r6FMWiC9DuL64YWtyCrQKuEOLe1iJsG+eO2W8eo+POdrvVtdULrgG0Dbg76xW1uCDcm5GCguzDAeNlz0qPqgfzGunJeAl4aOug6KYQ7l2WhI7DZEMqZ7L5a1uBZWTQF3/QVHvmUosOBX0ZVkbfkgNtDYCbDcDVsIKbQYCJBCY/gak7FHQh+bqiX7LwsnuYfr1gqUTCUsPWgsWdF1H2I1/ZoYBMSLs3o3/blyke+FRiEPE9c1Huq9dpV60GWQNmvybSIrCnee0SGIlDJzJfVzwrttTq7bfkUNCSzV71a19pScNOGHrmi9pWV/Uue6lXYpEcBFfgslSOPG0MBTASc/YK3455PEqvyYY5r0G4AeH6gWHqSCyVxQ2s9ksJw9B/ATBYVUy8fdRL6ZhhlPo1HpIyHelM38OmCuA6oWvzwTah69DTbiW6qxdMCdPdAIGLbrC8lyIimxHRgrhQcA+cdoqluxXc0u7qhcTGNBAYeKkB9CTASfJjVuTo7mvoRsO676Ci+LRanVbd91YgLggp2GI1/kpRq7MAXnuDjBhC8Qpkl3UepwIXgblseDQq2XBcUK8bru0hGgbni7ynzrMNs1xOuJDmNQMAsfAI2B0CjOaAvKuuK2aES8C8XU8Sn98H9SKw12/SwfwVzNyArOLOL1lxEpO37/lKFujlpW3UfTSZwpxaQCkXb+JVd3OAAg1xrQ4vFGzC0MDrbuvLSGtRiSVYuonjeNU5MxMWAVudZzct1azdLmUXzGZLV7BCySxG6Zrq4MsFXqv79A7WiLu1OwwLFgElr7VA3LQjLtZnCCx7+KNo7a4BuG3lhRmKWXQ0LME40Gbxsqt6BQH3arExZ+viCl67Ib1rGHFLQPIQL7JFnHTjRfUCb68whR1mXM3dttpjcWvIAS6uNCRxlmVxxypeCVJw3wjl0/LzmrfaVG4kBgFT6ge57wJ4M7OTfmlNS4j+McpB4G2rTfBGkhAwp2UcWfB2cw/FFogBKQvxrhtTLMnMZYJiFG4eeLM0zVLRg3dIzmJvAbfRgiXjS81rXfeBLIE3TTuVQneZeH8Fb4HXFQ0rcGKJcsNFXsRdduYdViSQBQNy0LCilaSIu+R3TeqP8KKLQAXXzjgw3hR5l3erFvoldOOVr9Cv5eK6v1tzXch0UZfLNGEPvGQi3fU7tMi1m45PgCtb4Nin974Lftmd9yUtJZ94q/NgUG9KvA9rWOjgwKATMTqv3mpcbcDgQxaLRbpYyp+89/5tLMF98GTAVZsP4LfpAuXRYnALBwof+0AxejR0EVVpO4ARbvpz96D1GV7FvNoJB4lNDLiQOKofIQSTicQcnzeq5ZUsxTpi8ctQJeVrJmNj8wbEWxHhYNxjXff8UiT1vww1Oq9R59Dgz1gGb5Kff5a62jA/4tD222Ml75J4zd+8uglmfcQB76s2nktsM2w2z8p2yamWG90eTNrd9ly/ALnAtlP8LO5a1FdSo9sv7h3cVvGqGHkXT9Sr+3ZcjO4faNNYUMErkHf2tIeuqBNhjc0bHXEDoVHBa20qeRm1liw1Mq9H29z68Ard+hs7f0BzWD/3S8g7q+TV3RohR8VVLqq34pgR2G8NL9O8alx3Rrvy7Cr3q2LkXTyPClrBY55JgPqCthFGVbxsgbxxRd2jxKCGTS/zpelW0beD8pB4NxVhVw7t2HSvj0m9lfUx5A/zzWw2q0yPHzYHjWEOuDXvWLnhAtL1Gah3XrWsImkL/WjAkoX7au+r00bQ7my+qFr4ekETpFvyUGsOKOAgZrNNZaE2InCx9XF/qVmFQwNGBVevs42n31K9+5oqFxw0GURc22UayXjBenHrY1Z7UJ/FpOCkRsFjWe+SNsLuef2xCm0QMfvwe60pxnGf5v7iNTR/xWZWb8GjWcOFgBtK3FLBM+uTCpatd5aigue1Pngs4yVcp8VphmT+YYuQGIhxm/Fu37w+j0mPBk4+BIy4ett8q52lGJTneJsbHwHGwx/FQYp2Q6wtogCWH8DNLtdt0S1Pi6RICx8JG1nFCluOV9yWLgrrjAI4HfVQNtYu5emw9ri0EyZGWpCNORYxvVuAGZeHgLIuEVZB5UnAqGLryfsLvDx31Gfa6czSSW+D7XRFVZgEyizlRfEm3yJFSaiM+HQ5Ee5ll3SNVgCczkvi+SJ5c+PMMtIV0BLu6RL32P8Lry8pcVHJcZoYlniDcCNJ49Xp+/uk5QK20PP0kLWYP8qsg2zuvl/VyAlQS1bQ7SnjfQ814O7WeF4jX/P/5l//fT2V77svePeNd/gFNam/FN/eZPd9io0B/ojOwMWVsA8/wO1RZvc/nOgTbqfi7okAfDbUe+KDjcVsPq9X81eJPK/g/So476kfWUG1S6vjmcIqYpGkGwT7r4t8FfffdIP7ajmdNlnC2Qto2fWNtixjudRr4a+VLF0uTa4vJF8XKuXbg/Hr33TjffKn3gp/kkkmmWSSSSaZZJJJJplkkkkmmWSS/yf5H6HANgUotAMHAAAAAElFTkSuQmCC + mediatype: image/png install: spec: clusterPermissions: - - rules: - - apiGroups: - - operators.coreos.com - resources: - - catalogsources - verbs: - - get - serviceAccountName: operand-deployment-lifecycle-manager + - rules: + - apiGroups: + - operators.coreos.com + resources: + - catalogsources + verbs: + - get + serviceAccountName: operand-deployment-lifecycle-manager deployments: - - label: - app.kubernetes.io/instance: operand-deployment-lifecycle-manager - app.kubernetes.io/managed-by: operand-deployment-lifecycle-manager - app.kubernetes.io/name: operand-deployment-lifecycle-manager - productName: IBM_Cloud_Platform_Common_Services - name: operand-deployment-lifecycle-manager - spec: - replicas: 1 - selector: - matchLabels: - name: operand-deployment-lifecycle-manager - strategy: {} - template: - metadata: - annotations: - productID: 068a62892a1e4db39641342e592daa25 - productMetric: FREE - productName: IBM Cloud Platform Common Services - labels: - app.kubernetes.io/instance: operand-deployment-lifecycle-manager - app.kubernetes.io/managed-by: operand-deployment-lifecycle-manager - app.kubernetes.io/name: operand-deployment-lifecycle-manager - intent: projected-odlm + - label: + app.kubernetes.io/instance: operand-deployment-lifecycle-manager + app.kubernetes.io/managed-by: operand-deployment-lifecycle-manager + app.kubernetes.io/name: operand-deployment-lifecycle-manager + productName: IBM_Cloud_Platform_Common_Services + name: operand-deployment-lifecycle-manager + spec: + replicas: 1 + selector: + matchLabels: name: operand-deployment-lifecycle-manager - productName: IBM_Cloud_Platform_Common_Services - spec: - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/arch - operator: In - values: - - amd64 - - ppc64le - - s390x - containers: - - args: - - -v=1 - command: - - /manager - env: - - name: OPERATOR_NAMESPACE - valueFrom: - fieldRef: - apiVersion: v1 - fieldPath: metadata.namespace - - name: WATCH_NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.annotations['olm.targetNamespaces'] - image: icr.io/cpopen/odlm:latest - imagePullPolicy: IfNotPresent - livenessProbe: - failureThreshold: 10 - httpGet: - path: /readyz - port: 8081 - initialDelaySeconds: 120 - periodSeconds: 60 - timeoutSeconds: 10 - name: manager - readinessProbe: - failureThreshold: 10 - httpGet: - path: /healthz - port: 8081 - initialDelaySeconds: 5 - periodSeconds: 20 - timeoutSeconds: 3 - resources: - limits: - cpu: 500m - memory: 512Mi - requests: - cpu: 200m - ephemeral-storage: 256Mi - memory: 200Mi - securityContext: - allowPrivilegeEscalation: false - capabilities: - drop: - - ALL - privileged: false - readOnlyRootFilesystem: true - runAsNonRoot: true - serviceAccount: operand-deployment-lifecycle-manager - serviceAccountName: operand-deployment-lifecycle-manager - terminationGracePeriodSeconds: 10 + strategy: {} + template: + metadata: + annotations: + productID: 068a62892a1e4db39641342e592daa25 + productMetric: FREE + productName: IBM Cloud Platform Common Services + labels: + app.kubernetes.io/instance: operand-deployment-lifecycle-manager + app.kubernetes.io/managed-by: operand-deployment-lifecycle-manager + app.kubernetes.io/name: operand-deployment-lifecycle-manager + intent: projected-odlm + name: operand-deployment-lifecycle-manager + productName: IBM_Cloud_Platform_Common_Services + spec: + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: kubernetes.io/arch + operator: In + values: + - amd64 + - ppc64le + - s390x + containers: + - args: + - -v=1 + command: + - /manager + env: + - name: OPERATOR_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: WATCH_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.annotations['olm.targetNamespaces'] + image: icr.io/cpopen/odlm:latest + imagePullPolicy: IfNotPresent + livenessProbe: + failureThreshold: 10 + httpGet: + path: /readyz + port: 8081 + initialDelaySeconds: 120 + periodSeconds: 60 + timeoutSeconds: 10 + name: manager + readinessProbe: + failureThreshold: 10 + httpGet: + path: /healthz + port: 8081 + initialDelaySeconds: 5 + periodSeconds: 20 + timeoutSeconds: 3 + resources: + limits: + cpu: 500m + memory: 512Mi + requests: + cpu: 200m + ephemeral-storage: 256Mi + memory: 200Mi + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + privileged: false + readOnlyRootFilesystem: true + runAsNonRoot: true + serviceAccount: operand-deployment-lifecycle-manager + serviceAccountName: operand-deployment-lifecycle-manager + terminationGracePeriodSeconds: 10 permissions: - - rules: - - apiGroups: - - '*' - resources: - - '*' - verbs: - - create - - delete - - get - - list - - patch - - update - - watch - - apiGroups: - - operator.ibm.com - resources: - - operandconfigs - - operandconfigs/status - - operandconfigs/finalizers - - operandregistries - - operandregistries/status - - operandregistries/finalizers - - operandrequests - - operandrequests/status - - operandrequests/finalizers - - operandbindinfos - - operandbindinfos/status - - operandbindinfos/finalizers - verbs: - - create - - delete - - get - - list - - patch - - update - - watch - - apiGroups: - - "" - resources: - - configmaps - - secrets - - services - - namespaces - verbs: - - create - - delete - - get - - list - - patch - - update - - watch - - apiGroups: - - route.openshift.io - resources: - - routes - verbs: - - create - - delete - - get - - list - - patch - - update - - watch - - apiGroups: - - operators.coreos.com - resources: - - operatorgroups - - installplans - verbs: - - create - - delete - - get - - list - - patch - - update - - watch - - apiGroups: - - k8s.keycloak.org - resources: - - keycloaks - verbs: - - create - - delete - - get - - list - - patch - - update - - watch - serviceAccountName: operand-deployment-lifecycle-manager + - rules: + - apiGroups: + - '*' + resources: + - '*' + verbs: + - create + - delete + - get + - list + - patch + - update + - watch + - apiGroups: + - operator.ibm.com + resources: + - operandconfigs + - operandconfigs/status + - operandconfigs/finalizers + - operandregistries + - operandregistries/status + - operandregistries/finalizers + - operandrequests + - operandrequests/status + - operandrequests/finalizers + - operandbindinfos + - operandbindinfos/status + - operandbindinfos/finalizers + verbs: + - create + - delete + - get + - list + - patch + - update + - watch + - apiGroups: + - "" + resources: + - configmaps + - secrets + - services + - namespaces + verbs: + - create + - delete + - get + - list + - patch + - update + - watch + - apiGroups: + - route.openshift.io + resources: + - routes + verbs: + - create + - delete + - get + - list + - patch + - update + - watch + - apiGroups: + - operators.coreos.com + resources: + - operatorgroups + - installplans + verbs: + - create + - delete + - get + - list + - patch + - update + - watch + - apiGroups: + - k8s.keycloak.org + resources: + - keycloaks + verbs: + - create + - delete + - get + - list + - patch + - update + - watch + serviceAccountName: operand-deployment-lifecycle-manager strategy: deployment installModes: - - supported: true - type: OwnNamespace - - supported: true - type: SingleNamespace - - supported: true - type: MultiNamespace - - supported: true - type: AllNamespaces + - supported: true + type: OwnNamespace + - supported: true + type: SingleNamespace + - supported: true + type: MultiNamespace + - supported: true + type: AllNamespaces keywords: - - IBM - - Cloud + - IBM + - Cloud labels: name: operand-deployment-lifecycle-manager links: - - name: IBM Operand Deployment Lifecycle Manager Project - url: https://github.com/IBM/operand-deployment-lifecycle-manager + - name: IBM Operand Deployment Lifecycle Manager Project + url: https://github.com/IBM/operand-deployment-lifecycle-manager maintainers: - - email: support@ibm.com - name: IBM Support + - email: support@ibm.com + name: IBM Support maturity: stable minKubeVersion: 1.19.0 provider: name: IBM - relatedImages: - - image: icr.io/cpopen/odlm:4.2.1 - name: ODLM_IMAGE version: 4.2.1 + relatedImages: + - image: icr.io/cpopen/odlm:4.2.1 + name: ODLM_IMAGE diff --git a/bundle/metadata/annotations.yaml b/bundle/metadata/annotations.yaml index b322c19f..55d60ed0 100644 --- a/bundle/metadata/annotations.yaml +++ b/bundle/metadata/annotations.yaml @@ -6,10 +6,9 @@ annotations: operators.operatorframework.io.bundle.package.v1: ibm-odlm operators.operatorframework.io.bundle.channels.v1: v4.2 operators.operatorframework.io.bundle.channel.default.v1: v4.2 - operators.operatorframework.io.metrics.builder: operator-sdk-v1.24.0 + operators.operatorframework.io.metrics.builder: operator-sdk-v1.29.0 operators.operatorframework.io.metrics.mediatype.v1: metrics+v1 operators.operatorframework.io.metrics.project_layout: go.kubebuilder.io/v3 - # Annotations for testing. operators.operatorframework.io.test.mediatype.v1: scorecard+v1 operators.operatorframework.io.test.config.v1: tests/scorecard/ diff --git a/common/Makefile.common.mk b/common/Makefile.common.mk index 5ea7edab..50fe01ed 100644 --- a/common/Makefile.common.mk +++ b/common/Makefile.common.mk @@ -91,10 +91,6 @@ CONTROLLER_GEN ?= $(shell pwd)/common/bin/controller-gen controller-gen: ## Download controller-gen locally if necessary. $(call go-get-tool,$(CONTROLLER_GEN),sigs.k8s.io/controller-tools/cmd/controller-gen@v0.6.1) -KUSTOMIZE ?= $(shell pwd)/common/bin/kustomize -kustomize: ## Download kustomize locally if necessary. - $(call go-get-tool,$(KUSTOMIZE),sigs.k8s.io/kustomize/kustomize/v4@v4.5.4) - KIND ?= $(shell pwd)/common/bin/kind kind: ## Download kind locally if necessary. $(call go-get-tool,$(KIND),sigs.k8s.io/kind@v0.17.0) diff --git a/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml b/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml index fa0dd58b..88d5602e 100644 --- a/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml +++ b/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml @@ -467,6 +467,6 @@ spec: provider: name: IBM relatedImages: - - image: icr.io/cpopen/odlm + - image: icr.io/cpopen/odlm:4.2.1 name: ODLM_IMAGE version: 0.0.0 diff --git a/controllers/testutil/test_util.go b/controllers/testutil/test_util.go index 16033f2b..6052a98e 100644 --- a/controllers/testutil/test_util.go +++ b/controllers/testutil/test_util.go @@ -140,8 +140,10 @@ func OperandConfigObj(name, namespace string) *apiv1alpha1.OperandConfig { Services: []apiv1alpha1.ConfigService{ { Name: "jaeger", - Spec: map[string]runtime.RawExtension{ - "jaeger": {Raw: []byte(`{"strategy": "streaming"}`)}, + Spec: map[string]apiv1alpha1.ExtensionWithMarker{ + "jaeger": { + RawExtension: runtime.RawExtension{Raw: []byte(`{"strategy": "streaming"}`)}, + }, }, Resources: []apiv1alpha1.ConfigResource{ { @@ -163,8 +165,10 @@ func OperandConfigObj(name, namespace string) *apiv1alpha1.OperandConfig { }, { Name: "mongodb-atlas-kubernetes", - Spec: map[string]runtime.RawExtension{ - "atlasDeployment": {Raw: []byte(`{"deploymentSpec":{"name": "test-deployment"}, "projectRef": {"name": "my-updated-project"}}`)}, + Spec: map[string]apiv1alpha1.ExtensionWithMarker{ + "atlasDeployment": { + RawExtension: runtime.RawExtension{Raw: []byte(`{"deploymentSpec":{"name": "test-deployment"}, "projectRef": {"name": "my-updated-project"}}`)}, + }, }, }, }, diff --git a/test/e2e/helpers_test.go b/test/e2e/helpers_test.go index 65245ad3..191130e7 100644 --- a/test/e2e/helpers_test.go +++ b/test/e2e/helpers_test.go @@ -304,8 +304,10 @@ func updateJaegerStrategy(ns string) error { if err != nil { return false, client.IgnoreNotFound(err) } - con.Spec.Services[0].Spec = map[string]runtime.RawExtension{ - "jaeger": {Raw: []byte(`{"strategy": "allinone"}`)}, + con.Spec.Services[0].Spec = map[string]v1alpha1.ExtensionWithMarker{ + "jaeger": { + RawExtension: runtime.RawExtension{Raw: []byte(`{"strategy": "allinone"}`)}, + }, } if err := k8sClient.Update(context.TODO(), con); err != nil { fmt.Println(" --- Waiting for OperandConfig instance stable ...") @@ -621,14 +623,17 @@ func newOperandConfigCR(name, namespace string) *v1alpha1.OperandConfig { Services: []v1alpha1.ConfigService{ { Name: "jaeger", - Spec: map[string]runtime.RawExtension{ - "jaeger": {Raw: []byte(`{"strategy": "streaming"}`)}, + Spec: map[string]v1alpha1.ExtensionWithMarker{ + "jaeger": { + RawExtension: runtime.RawExtension{Raw: []byte(`{"strategy": "streaming"}`)}}, }, }, { Name: "mongodb-atlas-kubernetes", - Spec: map[string]runtime.RawExtension{ - "atlasDeployment": {Raw: []byte(`{"deploymentSpec":{"name": "test-deployment"}}`)}, + Spec: map[string]v1alpha1.ExtensionWithMarker{ + "atlasDeployment": { + RawExtension: runtime.RawExtension{Raw: []byte(`{"deploymentSpec":{"name": "test-deployment"}}`)}, + }, }, Resources: []v1alpha1.ConfigResource{ { From 5615db2d2445eee25f0a7975adc65c4f27b87205 Mon Sep 17 00:00:00 2001 From: YuChen Shen <59578388+YCShen1010@users.noreply.github.com> Date: Wed, 1 Nov 2023 00:26:50 -0400 Subject: [PATCH 057/179] fix for failing to list packagemanifests resource (#989) Signed-off-by: YuChen --- Makefile | 2 +- bundle.Dockerfile | 2 +- ...fecycle-manager.clusterserviceversion.yaml | 553 +++++++++--------- bundle/metadata/annotations.yaml | 3 +- config/rbac/role.yaml | 10 + 5 files changed, 296 insertions(+), 274 deletions(-) diff --git a/Makefile b/Makefile index 0813c1f8..9b453970 100644 --- a/Makefile +++ b/Makefile @@ -34,7 +34,7 @@ VERSION ?= $(shell git describe --exact-match 2> /dev/null || \ git describe --match=$(git rev-parse --short=8 HEAD) --always --dirty --abbrev=8) RELEASE_VERSION ?= $(shell cat ./version/version.go | grep "Version =" | awk '{ print $$3}' | tr -d '"') LATEST_VERSION ?= latest -OPERATOR_SDK_VERSION=v1.24.0 +OPERATOR_SDK_VERSION=v1.32.0 YQ_VERSION=v4.17.2 DEFAULT_CHANNEL ?= v$(shell cat ./version/version.go | grep "Version =" | awk '{ print $$3}' | tr -d '"' | cut -d '.' -f1,2) CHANNELS ?= $(DEFAULT_CHANNEL) diff --git a/bundle.Dockerfile b/bundle.Dockerfile index c12c2221..3b1d7cf3 100644 --- a/bundle.Dockerfile +++ b/bundle.Dockerfile @@ -7,7 +7,7 @@ LABEL operators.operatorframework.io.bundle.metadata.v1=metadata/ LABEL operators.operatorframework.io.bundle.package.v1=ibm-odlm LABEL operators.operatorframework.io.bundle.channels.v1=v4.2 LABEL operators.operatorframework.io.bundle.channel.default.v1=v4.2 -LABEL operators.operatorframework.io.metrics.builder=operator-sdk-v1.29.0 +LABEL operators.operatorframework.io.metrics.builder=operator-sdk-v1.32.0 LABEL operators.operatorframework.io.metrics.mediatype.v1=metrics+v1 LABEL operators.operatorframework.io.metrics.project_layout=go.kubebuilder.io/v3 diff --git a/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml b/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml index 507a8262..a51b5818 100644 --- a/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml +++ b/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml @@ -129,12 +129,13 @@ metadata: categories: Developer Tools, Monitoring, Logging & Tracing, Security certified: "false" containerImage: icr.io/cpopen/odlm:latest - createdAt: "2023-10-30T14:30:29Z" - description: The Operand Deployment Lifecycle Manager provides a Kubernetes CRD-based API to manage the lifecycle of operands. + createdAt: "2023-10-31T21:57:26Z" + description: The Operand Deployment Lifecycle Manager provides a Kubernetes CRD-based + API to manage the lifecycle of operands. nss.operator.ibm.com/managed-operators: ibm-odlm olm.skipRange: '>=1.2.0 <4.2.1' operators.openshift.io/infrastructure-features: '["disconnected"]' - operators.operatorframework.io/builder: operator-sdk-v1.29.0 + operators.operatorframework.io/builder: operator-sdk-v1.32.0 operators.operatorframework.io/project_layout: go.kubebuilder.io/v3 repository: https://github.com/IBM/operand-deployment-lifecycle-manager support: IBM @@ -149,72 +150,72 @@ spec: apiservicedefinitions: {} customresourcedefinitions: owned: - - description: OperandBindInfo is the Schema for the operandbindinfoes API. Documentation For additional details regarding install parameters check https://ibm.biz/icpfs39install. License By installing this product you accept the license terms https://ibm.biz/icpfs39license - displayName: OperandBindInfo - kind: OperandBindInfo - name: operandbindinfos.operator.ibm.com - statusDescriptors: - - description: Phase describes the overall phase of OperandBindInfo. - displayName: Phase - path: phase - x-descriptors: - - urn:alm:descriptor:io.kubernetes.phase - version: v1alpha1 - - description: OperandConfig is the Schema for the operandconfigs API. Documentation For additional details regarding install parameters check https://ibm.biz/icpfs39install. License By installing this product you accept the license terms https://ibm.biz/icpfs39license - displayName: OperandConfig - kind: OperandConfig - name: operandconfigs.operator.ibm.com - specDescriptors: - - description: Services is a list of configuration of service. - displayName: Operand Services Config List - path: services - statusDescriptors: - - description: Phase describes the overall phase of operands in the OperandConfig. - displayName: Phase - path: phase - x-descriptors: - - urn:alm:descriptor:io.kubernetes.phase - version: v1alpha1 - - description: OperandRegistry is the Schema for the operandregistries API. Documentation For additional details regarding install parameters check https://ibm.biz/icpfs39install. License By installing this product you accept the license terms https://ibm.biz/icpfs39license - displayName: OperandRegistry - kind: OperandRegistry - name: operandregistries.operator.ibm.com - specDescriptors: - - description: Operators is a list of operator OLM definition. - displayName: Operators Registry List - path: operators - statusDescriptors: - - description: Conditions represents the current state of the Request Service. - displayName: Conditions - path: conditions - x-descriptors: - - urn:alm:descriptor:io.kubernetes.conditions - - description: Phase describes the overall phase of operators in the OperandRegistry. - displayName: Phase - path: phase - x-descriptors: - - urn:alm:descriptor:io.kubernetes.phase - version: v1alpha1 - - description: OperandRequest is the Schema for the operandrequests API. Documentation For additional details regarding install parameters check https://ibm.biz/icpfs39install. License By installing this product you accept the license terms https://ibm.biz/icpfs39license - displayName: OperandRequest - kind: OperandRequest - name: operandrequests.operator.ibm.com - specDescriptors: - - description: Requests defines a list of operands installation. - displayName: Operators Request List - path: requests - statusDescriptors: - - description: Conditions represents the current state of the Request Service. - displayName: Conditions - path: conditions - x-descriptors: - - urn:alm:descriptor:io.kubernetes.conditions - - description: Phase is the cluster running phase. - displayName: Phase - path: phase - x-descriptors: - - urn:alm:descriptor:io.kubernetes.phase - version: v1alpha1 + - description: OperandBindInfo is the Schema for the operandbindinfoes API. + displayName: OperandBindInfo + kind: OperandBindInfo + name: operandbindinfos.operator.ibm.com + statusDescriptors: + - description: Phase describes the overall phase of OperandBindInfo. + displayName: Phase + path: phase + x-descriptors: + - urn:alm:descriptor:io.kubernetes.phase + version: v1alpha1 + - description: OperandConfig is the Schema for the operandconfigs API. + displayName: OperandConfig + kind: OperandConfig + name: operandconfigs.operator.ibm.com + specDescriptors: + - description: Services is a list of configuration of service. + displayName: Operand Services Config List + path: services + statusDescriptors: + - description: Phase describes the overall phase of operands in the OperandConfig. + displayName: Phase + path: phase + x-descriptors: + - urn:alm:descriptor:io.kubernetes.phase + version: v1alpha1 + - description: OperandRegistry is the Schema for the operandregistries API. + displayName: OperandRegistry + kind: OperandRegistry + name: operandregistries.operator.ibm.com + specDescriptors: + - description: Operators is a list of operator OLM definition. + displayName: Operators Registry List + path: operators + statusDescriptors: + - description: Conditions represents the current state of the Request Service. + displayName: Conditions + path: conditions + x-descriptors: + - urn:alm:descriptor:io.kubernetes.conditions + - description: Phase describes the overall phase of operators in the OperandRegistry. + displayName: Phase + path: phase + x-descriptors: + - urn:alm:descriptor:io.kubernetes.phase + version: v1alpha1 + - description: OperandRequest is the Schema for the operandrequests API. + displayName: OperandRequest + kind: OperandRequest + name: operandrequests.operator.ibm.com + specDescriptors: + - description: Requests defines a list of operands installation. + displayName: Operators Request List + path: requests + statusDescriptors: + - description: Conditions represents the current state of the Request Service. + displayName: Conditions + path: conditions + x-descriptors: + - urn:alm:descriptor:io.kubernetes.conditions + - description: Phase is the cluster running phase. + displayName: Phase + path: phase + x-descriptors: + - urn:alm:descriptor:io.kubernetes.phase + version: v1alpha1 description: |- # Introduction @@ -557,221 +558,231 @@ spec: The Operand Deployment Lifecycle Manager supports running under the OpenShift Container Platform default restricted security context constraints. displayName: Operand Deployment Lifecycle Manager icon: - - base64data: iVBORw0KGgoAAAANSUhEUgAAAK8AAACvCAMAAAC8TH5HAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAB1UExURQAAAJGS77CC4pCS75yM64uV8pSQ7puA85OV87OB4auF5Hyd+H2c936b9n6b94Ca9n+b9n+b9n+b9qOJ56SI55yM6qSI536b96aH5q2D45mN64OZ9ZWQ7oyU8XWg+6uG5oqg/p6L6m+k/ZuY+3mr/6qQ9LqM80D8C0oAAAAbdFJOUwA67R4KKxMBBP6ak6vZgVtJxG5ot+hQ7YDVkwC2C58AAAuSSURBVHja7ZyJerK8EoCDCSTKjoiIS13of/+XeGYm4NLKrvj1OYxt7aa8TiazJZGxSSaZZJJJJvmcSCn/Eq7Cz79DLJk0rb+kXdM9nz0m/4p2mZufz3lAZvEn1HsGye2J9128h7/Gezj8Nd7D3+I9/xu8SjWHrS76bfN8A+NsYxjowCvbPN+QSGB6kWi6QHteyQLPfx+wYsH2eHSthgu05lXMy/PceRcwxtnjdnts4mjLq5hBceVdcVsya71FMeov0JIXMuQwR+DoXX5EMgf0uz2GrDYbb8mrmE+4Z/NdvDCApN+jX3uFdrySqfW70wzFbFLwWtVNkXa8ONlIvfx9Dk0xSyvYq0NpxasYJ9o8emcUVCw6EjGvuUpLXgfVm9cP1fAZp1yyCKeGBf8pB96g9jUZ57c6s1vIIAUfjXqY9eFg1yiuKJnOECzeW+TJm0+rxRGGWfcP7/dld8bZwqcp/dJqIs9hrJIJ/JD2abV5j1StfJn1/pofo/Kx0ae1KfAO7/Vld7anfVpf28M5kKPDc9kYLRW4RDhIwYV/PozVUAF39Qre3BmrvsM04nisjHHyJlUjZEOefuBj8UIA81zHfGJ84BYeHAP9LKseP1r5LNnvOlHeXJgqRZbUPzT97PHvBVb48VCX09W54du2u3ZJwjD0It/gqmCue/yoolm4b7tQjmohh7cGAWzHC8x/qOFOZmBG4bbERDkQrVYyiGP7iPwPLGrgsAofYbePonEJ2CHxAuvjxEjLvfUj7J1BaP0irY3i888SA63l3alWgwKjbXueZztOSBoucOE33huIZdsWHChXRds72O069PyHhSEBDiOynbAEBiGreCGJKoa5zT8GVBzt4QNgXc+wbq4YvW+hSMkDYNa4EYihWqlYtmouSsYTo4XvgWezHKDcI+7xuPbMMp7JH0GEfhZGRMDIG5FRtLG1IGCNvTp/d9nFZhMx/DXYH/cgSBv6SscM+Tyf0P450Lw+iCmbOGAMonOeO/XlMyTjgAsfmWAN9Y53RFy0hDAovXBDSBFBVAIHDdUJ2lre3J6AVG9Hcln5NQyKCUcrd390g5/BtjpNR2KNGwTVpRDSmk6et6jwCv0ScVhpxopxl3DBIjzVjrYk5gVuEPAaw7UP+aFV+0ex5Aq8y/hTYhiE/UXjhibrlBUisUm8hmHwqujuH3IqQLA/0dT+Af8Q34hT8du3QXlR4nrdkxhJ0554nwAXhpvj+hLUo2u/zWoJM1aXy70ZP8e97APWJ+WGbN1AXNP8tedAasM96PLu4Ik2jhpHZLkqgdGM5TNjuKzNnhkiUmneH8CSCe9wpXV429HDlCu7GcV9JwemWoEbWr3rGZx2iMs5F4+T3S1p89DoYGvkUeLCKC67m+uBsVwVuGpI+QVohGtZ6rHrU+Cu/UaP/ps4KY3iWhlipwNwd4Arh1WLCIy4lpA/2yiF4XZ9ehgMuaRgt7r6FMWiC9DuL64YWtyCrQKuEOLe1iJsG+eO2W8eo+POdrvVtdULrgG0Dbg76xW1uCDcm5GCguzDAeNlz0qPqgfzGunJeAl4aOug6KYQ7l2WhI7DZEMqZ7L5a1uBZWTQF3/QVHvmUosOBX0ZVkbfkgNtDYCbDcDVsIKbQYCJBCY/gak7FHQh+bqiX7LwsnuYfr1gqUTCUsPWgsWdF1H2I1/ZoYBMSLs3o3/blyke+FRiEPE9c1Huq9dpV60GWQNmvybSIrCnee0SGIlDJzJfVzwrttTq7bfkUNCSzV71a19pScNOGHrmi9pWV/Uue6lXYpEcBFfgslSOPG0MBTASc/YK3455PEqvyYY5r0G4AeH6gWHqSCyVxQ2s9ksJw9B/ATBYVUy8fdRL6ZhhlPo1HpIyHelM38OmCuA6oWvzwTah69DTbiW6qxdMCdPdAIGLbrC8lyIimxHRgrhQcA+cdoqluxXc0u7qhcTGNBAYeKkB9CTASfJjVuTo7mvoRsO676Ci+LRanVbd91YgLggp2GI1/kpRq7MAXnuDjBhC8Qpkl3UepwIXgblseDQq2XBcUK8bru0hGgbni7ynzrMNs1xOuJDmNQMAsfAI2B0CjOaAvKuuK2aES8C8XU8Sn98H9SKw12/SwfwVzNyArOLOL1lxEpO37/lKFujlpW3UfTSZwpxaQCkXb+JVd3OAAg1xrQ4vFGzC0MDrbuvLSGtRiSVYuonjeNU5MxMWAVudZzct1azdLmUXzGZLV7BCySxG6Zrq4MsFXqv79A7WiLu1OwwLFgElr7VA3LQjLtZnCCx7+KNo7a4BuG3lhRmKWXQ0LME40Gbxsqt6BQH3arExZ+viCl67Ib1rGHFLQPIQL7JFnHTjRfUCb68whR1mXM3dttpjcWvIAS6uNCRxlmVxxypeCVJw3wjl0/LzmrfaVG4kBgFT6ge57wJ4M7OTfmlNS4j+McpB4G2rTfBGkhAwp2UcWfB2cw/FFogBKQvxrhtTLMnMZYJiFG4eeLM0zVLRg3dIzmJvAbfRgiXjS81rXfeBLIE3TTuVQneZeH8Fb4HXFQ0rcGKJcsNFXsRdduYdViSQBQNy0LCilaSIu+R3TeqP8KKLQAXXzjgw3hR5l3erFvoldOOVr9Cv5eK6v1tzXch0UZfLNGEPvGQi3fU7tMi1m45PgCtb4Nin974Lftmd9yUtJZ94q/NgUG9KvA9rWOjgwKATMTqv3mpcbcDgQxaLRbpYyp+89/5tLMF98GTAVZsP4LfpAuXRYnALBwof+0AxejR0EVVpO4ARbvpz96D1GV7FvNoJB4lNDLiQOKofIQSTicQcnzeq5ZUsxTpi8ctQJeVrJmNj8wbEWxHhYNxjXff8UiT1vww1Oq9R59Dgz1gGb5Kff5a62jA/4tD222Ml75J4zd+8uglmfcQB76s2nktsM2w2z8p2yamWG90eTNrd9ly/ALnAtlP8LO5a1FdSo9sv7h3cVvGqGHkXT9Sr+3ZcjO4faNNYUMErkHf2tIeuqBNhjc0bHXEDoVHBa20qeRm1liw1Mq9H29z68Ard+hs7f0BzWD/3S8g7q+TV3RohR8VVLqq34pgR2G8NL9O8alx3Rrvy7Cr3q2LkXTyPClrBY55JgPqCthFGVbxsgbxxRd2jxKCGTS/zpelW0beD8pB4NxVhVw7t2HSvj0m9lfUx5A/zzWw2q0yPHzYHjWEOuDXvWLnhAtL1Gah3XrWsImkL/WjAkoX7au+r00bQ7my+qFr4ekETpFvyUGsOKOAgZrNNZaE2InCx9XF/qVmFQwNGBVevs42n31K9+5oqFxw0GURc22UayXjBenHrY1Z7UJ/FpOCkRsFjWe+SNsLuef2xCm0QMfvwe60pxnGf5v7iNTR/xWZWb8GjWcOFgBtK3FLBM+uTCpatd5aigue1Pngs4yVcp8VphmT+YYuQGIhxm/Fu37w+j0mPBk4+BIy4ett8q52lGJTneJsbHwHGwx/FQYp2Q6wtogCWH8DNLtdt0S1Pi6RICx8JG1nFCluOV9yWLgrrjAI4HfVQNtYu5emw9ri0EyZGWpCNORYxvVuAGZeHgLIuEVZB5UnAqGLryfsLvDx31Gfa6czSSW+D7XRFVZgEyizlRfEm3yJFSaiM+HQ5Ee5ll3SNVgCczkvi+SJ5c+PMMtIV0BLu6RL32P8Lry8pcVHJcZoYlniDcCNJ49Xp+/uk5QK20PP0kLWYP8qsg2zuvl/VyAlQS1bQ7SnjfQ814O7WeF4jX/P/5l//fT2V77svePeNd/gFNam/FN/eZPd9io0B/ojOwMWVsA8/wO1RZvc/nOgTbqfi7okAfDbUe+KDjcVsPq9X81eJPK/g/So476kfWUG1S6vjmcIqYpGkGwT7r4t8FfffdIP7ajmdNlnC2Qto2fWNtixjudRr4a+VLF0uTa4vJF8XKuXbg/Hr33TjffKn3gp/kkkmmWSSSSaZZJJJJplkkkkmmWSS/yf5H6HANgUotAMHAAAAAElFTkSuQmCC - mediatype: image/png + - base64data: iVBORw0KGgoAAAANSUhEUgAAAK8AAACvCAMAAAC8TH5HAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAB1UExURQAAAJGS77CC4pCS75yM64uV8pSQ7puA85OV87OB4auF5Hyd+H2c936b9n6b94Ca9n+b9n+b9n+b9qOJ56SI55yM6qSI536b96aH5q2D45mN64OZ9ZWQ7oyU8XWg+6uG5oqg/p6L6m+k/ZuY+3mr/6qQ9LqM80D8C0oAAAAbdFJOUwA67R4KKxMBBP6ak6vZgVtJxG5ot+hQ7YDVkwC2C58AAAuSSURBVHja7ZyJerK8EoCDCSTKjoiIS13of/+XeGYm4NLKrvj1OYxt7aa8TiazJZGxSSaZZJJJJvmcSCn/Eq7Cz79DLJk0rb+kXdM9nz0m/4p2mZufz3lAZvEn1HsGye2J9128h7/Gezj8Nd7D3+I9/xu8SjWHrS76bfN8A+NsYxjowCvbPN+QSGB6kWi6QHteyQLPfx+wYsH2eHSthgu05lXMy/PceRcwxtnjdnts4mjLq5hBceVdcVsya71FMeov0JIXMuQwR+DoXX5EMgf0uz2GrDYbb8mrmE+4Z/NdvDCApN+jX3uFdrySqfW70wzFbFLwWtVNkXa8ONlIvfx9Dk0xSyvYq0NpxasYJ9o8emcUVCw6EjGvuUpLXgfVm9cP1fAZp1yyCKeGBf8pB96g9jUZ57c6s1vIIAUfjXqY9eFg1yiuKJnOECzeW+TJm0+rxRGGWfcP7/dld8bZwqcp/dJqIs9hrJIJ/JD2abV5j1StfJn1/pofo/Kx0ae1KfAO7/Vld7anfVpf28M5kKPDc9kYLRW4RDhIwYV/PozVUAF39Qre3BmrvsM04nisjHHyJlUjZEOefuBj8UIA81zHfGJ84BYeHAP9LKseP1r5LNnvOlHeXJgqRZbUPzT97PHvBVb48VCX09W54du2u3ZJwjD0It/gqmCue/yoolm4b7tQjmohh7cGAWzHC8x/qOFOZmBG4bbERDkQrVYyiGP7iPwPLGrgsAofYbePonEJ2CHxAuvjxEjLvfUj7J1BaP0irY3i888SA63l3alWgwKjbXueZztOSBoucOE33huIZdsWHChXRds72O069PyHhSEBDiOynbAEBiGreCGJKoa5zT8GVBzt4QNgXc+wbq4YvW+hSMkDYNa4EYihWqlYtmouSsYTo4XvgWezHKDcI+7xuPbMMp7JH0GEfhZGRMDIG5FRtLG1IGCNvTp/d9nFZhMx/DXYH/cgSBv6SscM+Tyf0P450Lw+iCmbOGAMonOeO/XlMyTjgAsfmWAN9Y53RFy0hDAovXBDSBFBVAIHDdUJ2lre3J6AVG9Hcln5NQyKCUcrd390g5/BtjpNR2KNGwTVpRDSmk6et6jwCv0ScVhpxopxl3DBIjzVjrYk5gVuEPAaw7UP+aFV+0ex5Aq8y/hTYhiE/UXjhibrlBUisUm8hmHwqujuH3IqQLA/0dT+Af8Q34hT8du3QXlR4nrdkxhJ0554nwAXhpvj+hLUo2u/zWoJM1aXy70ZP8e97APWJ+WGbN1AXNP8tedAasM96PLu4Ik2jhpHZLkqgdGM5TNjuKzNnhkiUmneH8CSCe9wpXV429HDlCu7GcV9JwemWoEbWr3rGZx2iMs5F4+T3S1p89DoYGvkUeLCKC67m+uBsVwVuGpI+QVohGtZ6rHrU+Cu/UaP/ps4KY3iWhlipwNwd4Arh1WLCIy4lpA/2yiF4XZ9ehgMuaRgt7r6FMWiC9DuL64YWtyCrQKuEOLe1iJsG+eO2W8eo+POdrvVtdULrgG0Dbg76xW1uCDcm5GCguzDAeNlz0qPqgfzGunJeAl4aOug6KYQ7l2WhI7DZEMqZ7L5a1uBZWTQF3/QVHvmUosOBX0ZVkbfkgNtDYCbDcDVsIKbQYCJBCY/gak7FHQh+bqiX7LwsnuYfr1gqUTCUsPWgsWdF1H2I1/ZoYBMSLs3o3/blyke+FRiEPE9c1Huq9dpV60GWQNmvybSIrCnee0SGIlDJzJfVzwrttTq7bfkUNCSzV71a19pScNOGHrmi9pWV/Uue6lXYpEcBFfgslSOPG0MBTASc/YK3455PEqvyYY5r0G4AeH6gWHqSCyVxQ2s9ksJw9B/ATBYVUy8fdRL6ZhhlPo1HpIyHelM38OmCuA6oWvzwTah69DTbiW6qxdMCdPdAIGLbrC8lyIimxHRgrhQcA+cdoqluxXc0u7qhcTGNBAYeKkB9CTASfJjVuTo7mvoRsO676Ci+LRanVbd91YgLggp2GI1/kpRq7MAXnuDjBhC8Qpkl3UepwIXgblseDQq2XBcUK8bru0hGgbni7ynzrMNs1xOuJDmNQMAsfAI2B0CjOaAvKuuK2aES8C8XU8Sn98H9SKw12/SwfwVzNyArOLOL1lxEpO37/lKFujlpW3UfTSZwpxaQCkXb+JVd3OAAg1xrQ4vFGzC0MDrbuvLSGtRiSVYuonjeNU5MxMWAVudZzct1azdLmUXzGZLV7BCySxG6Zrq4MsFXqv79A7WiLu1OwwLFgElr7VA3LQjLtZnCCx7+KNo7a4BuG3lhRmKWXQ0LME40Gbxsqt6BQH3arExZ+viCl67Ib1rGHFLQPIQL7JFnHTjRfUCb68whR1mXM3dttpjcWvIAS6uNCRxlmVxxypeCVJw3wjl0/LzmrfaVG4kBgFT6ge57wJ4M7OTfmlNS4j+McpB4G2rTfBGkhAwp2UcWfB2cw/FFogBKQvxrhtTLMnMZYJiFG4eeLM0zVLRg3dIzmJvAbfRgiXjS81rXfeBLIE3TTuVQneZeH8Fb4HXFQ0rcGKJcsNFXsRdduYdViSQBQNy0LCilaSIu+R3TeqP8KKLQAXXzjgw3hR5l3erFvoldOOVr9Cv5eK6v1tzXch0UZfLNGEPvGQi3fU7tMi1m45PgCtb4Nin974Lftmd9yUtJZ94q/NgUG9KvA9rWOjgwKATMTqv3mpcbcDgQxaLRbpYyp+89/5tLMF98GTAVZsP4LfpAuXRYnALBwof+0AxejR0EVVpO4ARbvpz96D1GV7FvNoJB4lNDLiQOKofIQSTicQcnzeq5ZUsxTpi8ctQJeVrJmNj8wbEWxHhYNxjXff8UiT1vww1Oq9R59Dgz1gGb5Kff5a62jA/4tD222Ml75J4zd+8uglmfcQB76s2nktsM2w2z8p2yamWG90eTNrd9ly/ALnAtlP8LO5a1FdSo9sv7h3cVvGqGHkXT9Sr+3ZcjO4faNNYUMErkHf2tIeuqBNhjc0bHXEDoVHBa20qeRm1liw1Mq9H29z68Ard+hs7f0BzWD/3S8g7q+TV3RohR8VVLqq34pgR2G8NL9O8alx3Rrvy7Cr3q2LkXTyPClrBY55JgPqCthFGVbxsgbxxRd2jxKCGTS/zpelW0beD8pB4NxVhVw7t2HSvj0m9lfUx5A/zzWw2q0yPHzYHjWEOuDXvWLnhAtL1Gah3XrWsImkL/WjAkoX7au+r00bQ7my+qFr4ekETpFvyUGsOKOAgZrNNZaE2InCx9XF/qVmFQwNGBVevs42n31K9+5oqFxw0GURc22UayXjBenHrY1Z7UJ/FpOCkRsFjWe+SNsLuef2xCm0QMfvwe60pxnGf5v7iNTR/xWZWb8GjWcOFgBtK3FLBM+uTCpatd5aigue1Pngs4yVcp8VphmT+YYuQGIhxm/Fu37w+j0mPBk4+BIy4ett8q52lGJTneJsbHwHGwx/FQYp2Q6wtogCWH8DNLtdt0S1Pi6RICx8JG1nFCluOV9yWLgrrjAI4HfVQNtYu5emw9ri0EyZGWpCNORYxvVuAGZeHgLIuEVZB5UnAqGLryfsLvDx31Gfa6czSSW+D7XRFVZgEyizlRfEm3yJFSaiM+HQ5Ee5ll3SNVgCczkvi+SJ5c+PMMtIV0BLu6RL32P8Lry8pcVHJcZoYlniDcCNJ49Xp+/uk5QK20PP0kLWYP8qsg2zuvl/VyAlQS1bQ7SnjfQ814O7WeF4jX/P/5l//fT2V77svePeNd/gFNam/FN/eZPd9io0B/ojOwMWVsA8/wO1RZvc/nOgTbqfi7okAfDbUe+KDjcVsPq9X81eJPK/g/So476kfWUG1S6vjmcIqYpGkGwT7r4t8FfffdIP7ajmdNlnC2Qto2fWNtixjudRr4a+VLF0uTa4vJF8XKuXbg/Hr33TjffKn3gp/kkkmmWSSSSaZZJJJJplkkkkmmWSS/yf5H6HANgUotAMHAAAAAElFTkSuQmCC + mediatype: image/png install: spec: clusterPermissions: - - rules: - - apiGroups: - - operators.coreos.com - resources: - - catalogsources - verbs: - - get - serviceAccountName: operand-deployment-lifecycle-manager + - rules: + - apiGroups: + - operators.coreos.com + resources: + - catalogsources + verbs: + - get + serviceAccountName: operand-deployment-lifecycle-manager deployments: - - label: - app.kubernetes.io/instance: operand-deployment-lifecycle-manager - app.kubernetes.io/managed-by: operand-deployment-lifecycle-manager - app.kubernetes.io/name: operand-deployment-lifecycle-manager - productName: IBM_Cloud_Platform_Common_Services - name: operand-deployment-lifecycle-manager - spec: - replicas: 1 - selector: - matchLabels: + - label: + app.kubernetes.io/instance: operand-deployment-lifecycle-manager + app.kubernetes.io/managed-by: operand-deployment-lifecycle-manager + app.kubernetes.io/name: operand-deployment-lifecycle-manager + productName: IBM_Cloud_Platform_Common_Services + name: operand-deployment-lifecycle-manager + spec: + replicas: 1 + selector: + matchLabels: + name: operand-deployment-lifecycle-manager + strategy: {} + template: + metadata: + annotations: + productID: 068a62892a1e4db39641342e592daa25 + productMetric: FREE + productName: IBM Cloud Platform Common Services + labels: + app.kubernetes.io/instance: operand-deployment-lifecycle-manager + app.kubernetes.io/managed-by: operand-deployment-lifecycle-manager + app.kubernetes.io/name: operand-deployment-lifecycle-manager + intent: projected-odlm name: operand-deployment-lifecycle-manager - strategy: {} - template: - metadata: - annotations: - productID: 068a62892a1e4db39641342e592daa25 - productMetric: FREE - productName: IBM Cloud Platform Common Services - labels: - app.kubernetes.io/instance: operand-deployment-lifecycle-manager - app.kubernetes.io/managed-by: operand-deployment-lifecycle-manager - app.kubernetes.io/name: operand-deployment-lifecycle-manager - intent: projected-odlm - name: operand-deployment-lifecycle-manager - productName: IBM_Cloud_Platform_Common_Services - spec: - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/arch - operator: In - values: - - amd64 - - ppc64le - - s390x - containers: - - args: - - -v=1 - command: - - /manager - env: - - name: OPERATOR_NAMESPACE - valueFrom: - fieldRef: - apiVersion: v1 - fieldPath: metadata.namespace - - name: WATCH_NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.annotations['olm.targetNamespaces'] - image: icr.io/cpopen/odlm:latest - imagePullPolicy: IfNotPresent - livenessProbe: - failureThreshold: 10 - httpGet: - path: /readyz - port: 8081 - initialDelaySeconds: 120 - periodSeconds: 60 - timeoutSeconds: 10 - name: manager - readinessProbe: - failureThreshold: 10 - httpGet: - path: /healthz - port: 8081 - initialDelaySeconds: 5 - periodSeconds: 20 - timeoutSeconds: 3 - resources: - limits: - cpu: 500m - memory: 512Mi - requests: - cpu: 200m - ephemeral-storage: 256Mi - memory: 200Mi - securityContext: - allowPrivilegeEscalation: false - capabilities: - drop: - - ALL - privileged: false - readOnlyRootFilesystem: true - runAsNonRoot: true - serviceAccount: operand-deployment-lifecycle-manager - serviceAccountName: operand-deployment-lifecycle-manager - terminationGracePeriodSeconds: 10 + productName: IBM_Cloud_Platform_Common_Services + spec: + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: kubernetes.io/arch + operator: In + values: + - amd64 + - ppc64le + - s390x + containers: + - args: + - -v=1 + command: + - /manager + env: + - name: OPERATOR_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: WATCH_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.annotations['olm.targetNamespaces'] + image: icr.io/cpopen/odlm:latest + imagePullPolicy: IfNotPresent + livenessProbe: + failureThreshold: 10 + httpGet: + path: /readyz + port: 8081 + initialDelaySeconds: 120 + periodSeconds: 60 + timeoutSeconds: 10 + name: manager + readinessProbe: + failureThreshold: 10 + httpGet: + path: /healthz + port: 8081 + initialDelaySeconds: 5 + periodSeconds: 20 + timeoutSeconds: 3 + resources: + limits: + cpu: 500m + memory: 512Mi + requests: + cpu: 200m + ephemeral-storage: 256Mi + memory: 200Mi + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + privileged: false + readOnlyRootFilesystem: true + runAsNonRoot: true + serviceAccount: operand-deployment-lifecycle-manager + serviceAccountName: operand-deployment-lifecycle-manager + terminationGracePeriodSeconds: 10 permissions: - - rules: - - apiGroups: - - '*' - resources: - - '*' - verbs: - - create - - delete - - get - - list - - patch - - update - - watch - - apiGroups: - - operator.ibm.com - resources: - - operandconfigs - - operandconfigs/status - - operandconfigs/finalizers - - operandregistries - - operandregistries/status - - operandregistries/finalizers - - operandrequests - - operandrequests/status - - operandrequests/finalizers - - operandbindinfos - - operandbindinfos/status - - operandbindinfos/finalizers - verbs: - - create - - delete - - get - - list - - patch - - update - - watch - - apiGroups: - - "" - resources: - - configmaps - - secrets - - services - - namespaces - verbs: - - create - - delete - - get - - list - - patch - - update - - watch - - apiGroups: - - route.openshift.io - resources: - - routes - verbs: - - create - - delete - - get - - list - - patch - - update - - watch - - apiGroups: - - operators.coreos.com - resources: - - operatorgroups - - installplans - verbs: - - create - - delete - - get - - list - - patch - - update - - watch - - apiGroups: - - k8s.keycloak.org - resources: - - keycloaks - verbs: - - create - - delete - - get - - list - - patch - - update - - watch - serviceAccountName: operand-deployment-lifecycle-manager + - rules: + - apiGroups: + - '*' + resources: + - '*' + verbs: + - create + - delete + - get + - list + - patch + - update + - watch + - apiGroups: + - operator.ibm.com + resources: + - operandconfigs + - operandconfigs/status + - operandconfigs/finalizers + - operandregistries + - operandregistries/status + - operandregistries/finalizers + - operandrequests + - operandrequests/status + - operandrequests/finalizers + - operandbindinfos + - operandbindinfos/status + - operandbindinfos/finalizers + verbs: + - create + - delete + - get + - list + - patch + - update + - watch + - apiGroups: + - "" + resources: + - configmaps + - secrets + - services + - namespaces + verbs: + - create + - delete + - get + - list + - patch + - update + - watch + - apiGroups: + - route.openshift.io + resources: + - routes + verbs: + - create + - delete + - get + - list + - patch + - update + - watch + - apiGroups: + - operators.coreos.com + resources: + - operatorgroups + - installplans + verbs: + - create + - delete + - get + - list + - patch + - update + - watch + - apiGroups: + - k8s.keycloak.org + resources: + - keycloaks + verbs: + - create + - delete + - get + - list + - patch + - update + - watch + - apiGroups: + - packages.operators.coreos.com + resources: + - packagemanifests + verbs: + - get + - list + - patch + - update + - watch + serviceAccountName: operand-deployment-lifecycle-manager strategy: deployment installModes: - - supported: true - type: OwnNamespace - - supported: true - type: SingleNamespace - - supported: true - type: MultiNamespace - - supported: true - type: AllNamespaces + - supported: true + type: OwnNamespace + - supported: true + type: SingleNamespace + - supported: true + type: MultiNamespace + - supported: true + type: AllNamespaces keywords: - - IBM - - Cloud + - IBM + - Cloud labels: name: operand-deployment-lifecycle-manager links: - - name: IBM Operand Deployment Lifecycle Manager Project - url: https://github.com/IBM/operand-deployment-lifecycle-manager + - name: IBM Operand Deployment Lifecycle Manager Project + url: https://github.com/IBM/operand-deployment-lifecycle-manager maintainers: - - email: support@ibm.com - name: IBM Support + - email: support@ibm.com + name: IBM Support maturity: stable minKubeVersion: 1.19.0 provider: diff --git a/bundle/metadata/annotations.yaml b/bundle/metadata/annotations.yaml index 55d60ed0..59d1fb06 100644 --- a/bundle/metadata/annotations.yaml +++ b/bundle/metadata/annotations.yaml @@ -6,9 +6,10 @@ annotations: operators.operatorframework.io.bundle.package.v1: ibm-odlm operators.operatorframework.io.bundle.channels.v1: v4.2 operators.operatorframework.io.bundle.channel.default.v1: v4.2 - operators.operatorframework.io.metrics.builder: operator-sdk-v1.29.0 + operators.operatorframework.io.metrics.builder: operator-sdk-v1.32.0 operators.operatorframework.io.metrics.mediatype.v1: metrics+v1 operators.operatorframework.io.metrics.project_layout: go.kubebuilder.io/v3 + # Annotations for testing. operators.operatorframework.io.test.mediatype.v1: scorecard+v1 operators.operatorframework.io.test.config.v1: tests/scorecard/ diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml index 3ae85fa3..be1d8f4a 100644 --- a/config/rbac/role.yaml +++ b/config/rbac/role.yaml @@ -103,3 +103,13 @@ rules: - k8s.keycloak.org resources: - keycloaks +- apiGroups: + - packages.operators.coreos.com + resources: + - packagemanifests + verbs: + - get + - list + - patch + - update + - watch From 15c4823bdaa74059e825c1021bb095c8a074a1f8 Mon Sep 17 00:00:00 2001 From: Daniel Fan Date: Thu, 2 Nov 2023 00:17:51 -0400 Subject: [PATCH 058/179] Add value reference in OperandConfig (#990) * Add value reference in OperandConfig Signed-off-by: Daniel Fan * Add generic object value reference Signed-off-by: Daniel Fan * Remove unused code Signed-off-by: Daniel Fan * Update test case for Value Reference in Template Signed-off-by: Daniel Fan --------- Signed-off-by: Daniel Fan --- controllers/constant/constant.go | 6 + .../operandbindinfo_controller.go | 43 +-- .../operandrequest_controller.go | 63 ++++- .../operandrequest_controller_test.go | 13 +- .../operandrequest/reconcile_operand.go | 52 +++- controllers/operator/manager.go | 255 ++++++++++++++++++ controllers/testutil/test_util.go | 45 +++- controllers/util/util.go | 79 ++++++ go.mod | 2 +- main.go | 4 +- 10 files changed, 513 insertions(+), 49 deletions(-) diff --git a/controllers/constant/constant.go b/controllers/constant/constant.go index cb536c94..5f334292 100644 --- a/controllers/constant/constant.go +++ b/controllers/constant/constant.go @@ -31,6 +31,12 @@ const ( //OpreqLabel is the label used to label the subscription/CR managed by ODLM OpreqLabel string = "operator.ibm.com/opreq-control" + //ODLMReferenceLabel is the label used to label the resources used for ODLM operand value reference + ODLMReferenceLabel string = "operator.ibm.com/referenced-by-odlm-resource" + + //ODLMWatchedLabel is the label used to label the resources watched by ODLM for value reference + ODLMWatchedLabel string = "operator.ibm.com/watched-by-odlm" + //OpbiNsLabel is the label used to add OperandBindInfo namespace to the secrets/configmaps watched by ODLM OpbiNsLabel string = "operator.ibm.com/watched-by-opbi-with-namespace" diff --git a/controllers/operandbindinfo/operandbindinfo_controller.go b/controllers/operandbindinfo/operandbindinfo_controller.go index fc796a9c..9529f227 100644 --- a/controllers/operandbindinfo/operandbindinfo_controller.go +++ b/controllers/operandbindinfo/operandbindinfo_controller.go @@ -27,7 +27,6 @@ import ( "github.com/pkg/errors" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/api/equality" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" @@ -250,6 +249,7 @@ func (r *Reconciler) copySecret(ctx context.Context, sourceName, targetName, sou } secretLabel[bindInfoInstance.Namespace+"."+bindInfoInstance.Name+"/bindinfo"] = "true" secretLabel[constant.OpbiTypeLabel] = "copy" + secretLabel[constant.ODLMWatchedLabel] = "true" secretCopy := &corev1.Secret{ ObjectMeta: metav1.ObjectMeta{ Name: targetName, @@ -274,7 +274,7 @@ func (r *Reconciler) copySecret(ctx context.Context, sourceName, targetName, sou if err := r.Client.Get(ctx, types.NamespacedName{Namespace: targetNs, Name: targetName}, existingSecret); err != nil { return false, errors.Wrapf(err, "failed to get secret %s/%s", targetNs, targetName) } - if needUpdate := compareSecret(secretCopy, existingSecret); needUpdate { + if needUpdate := util.CompareSecret(secretCopy, existingSecret); needUpdate { podRefreshment = true if err := r.Update(ctx, secretCopy); err != nil { return false, errors.Wrapf(err, "failed to update secret %s/%s", targetNs, targetName) @@ -290,9 +290,10 @@ func (r *Reconciler) copySecret(ctx context.Context, sourceName, targetName, sou } } - ensureLabelsForSecret(secret, map[string]string{ + util.EnsureLabelsForSecret(secret, map[string]string{ bindInfoInstance.Namespace + "." + bindInfoInstance.Name + "/bindinfo": "true", - constant.OpbiTypeLabel: "original", + constant.OpbiTypeLabel: "original", + constant.ODLMWatchedLabel: "true", }) // Update the operand Secret @@ -342,6 +343,7 @@ func (r *Reconciler) copyConfigmap(ctx context.Context, sourceName, targetName, } cmLabel[bindInfoInstance.Namespace+"."+bindInfoInstance.Name+"/bindinfo"] = "true" cmLabel[constant.OpbiTypeLabel] = "copy" + cmLabel[constant.ODLMWatchedLabel] = "true" cmCopy := &corev1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{ Name: targetName, @@ -365,7 +367,7 @@ func (r *Reconciler) copyConfigmap(ctx context.Context, sourceName, targetName, if err := r.Client.Get(ctx, types.NamespacedName{Namespace: targetNs, Name: targetName}, existingCm); err != nil { return false, errors.Wrapf(err, "failed to get ConfigMap %s/%s", targetNs, targetName) } - if needUpdate := compareConfigMap(cmCopy, existingCm); needUpdate { + if needUpdate := util.CompareConfigMap(cmCopy, existingCm); needUpdate { podRefreshment = true if err := r.Update(ctx, cmCopy); err != nil { return false, errors.Wrapf(err, "failed to update ConfigMap %s/%s", targetNs, sourceName) @@ -383,9 +385,10 @@ func (r *Reconciler) copyConfigmap(ctx context.Context, sourceName, targetName, } // Set the OperandBindInfo label for the ConfigMap - ensureLabelsForConfigMap(cm, map[string]string{ + util.EnsureLabelsForConfigMap(cm, map[string]string{ bindInfoInstance.Namespace + "." + bindInfoInstance.Name + "/bindinfo": "true", - constant.OpbiTypeLabel: "original", + constant.OpbiTypeLabel: "original", + constant.ODLMWatchedLabel: "true", }) // Update the operand Configmap @@ -769,29 +772,3 @@ func (r *Reconciler) SetupWithManager(mgr ctrl.Manager) error { builder.WithPredicates(opregPredicates), ).Complete(r) } - -func ensureLabelsForSecret(secret *corev1.Secret, labels map[string]string) { - if secret.Labels == nil { - secret.Labels = make(map[string]string) - } - for k, v := range labels { - secret.Labels[k] = v - } -} - -func ensureLabelsForConfigMap(cm *corev1.ConfigMap, labels map[string]string) { - if cm.Labels == nil { - cm.Labels = make(map[string]string) - } - for k, v := range labels { - cm.Labels[k] = v - } -} - -func compareSecret(secret *corev1.Secret, existingSecret *corev1.Secret) (needUpdate bool) { - return !equality.Semantic.DeepEqual(secret.GetLabels(), existingSecret.GetLabels()) || !equality.Semantic.DeepEqual(secret.Type, existingSecret.Type) || !equality.Semantic.DeepEqual(secret.Data, existingSecret.Data) || !equality.Semantic.DeepEqual(secret.StringData, existingSecret.StringData) -} - -func compareConfigMap(configMap *corev1.ConfigMap, existingConfigMap *corev1.ConfigMap) (needUpdate bool) { - return !equality.Semantic.DeepEqual(configMap.GetLabels(), existingConfigMap.GetLabels()) || !equality.Semantic.DeepEqual(configMap.Data, existingConfigMap.Data) || !equality.Semantic.DeepEqual(configMap.BinaryData, existingConfigMap.BinaryData) -} diff --git a/controllers/operandrequest/operandrequest_controller.go b/controllers/operandrequest/operandrequest_controller.go index 5a52fcb8..a0c11af0 100644 --- a/controllers/operandrequest/operandrequest_controller.go +++ b/controllers/operandrequest/operandrequest_controller.go @@ -299,11 +299,69 @@ func (r *Reconciler) getConfigToRequestMapper() handler.MapFunc { } } +func (r *Reconciler) getReferenceToRequestMapper() handler.MapFunc { + ctx := context.Background() + return func(object client.Object) []ctrl.Request { + labels := object.GetLabels() + if labels == nil { + return []ctrl.Request{} + } + odlmReference, ok := labels[constant.ODLMReferenceLabel] + if !ok { + return []ctrl.Request{} + } + odlmReferenceSlices := strings.Split(odlmReference, ".") + if len(odlmReferenceSlices) != 3 { + return []ctrl.Request{} + } + + var requestList []operatorv1alpha1.OperandRequest + if odlmReferenceSlices[0] == "OperandConfig" { + requestList, _ = r.ListOperandRequestsByConfig(ctx, types.NamespacedName{Namespace: odlmReferenceSlices[1], Name: odlmReferenceSlices[2]}) + } else if odlmReferenceSlices[0] == "OperandRegistry" { + requestList, _ = r.ListOperandRequestsByRegistry(ctx, types.NamespacedName{Namespace: odlmReferenceSlices[1], Name: odlmReferenceSlices[2]}) + } else { + return []ctrl.Request{} + } + + requests := []ctrl.Request{} + for _, request := range requestList { + namespaceName := types.NamespacedName{Name: request.Name, Namespace: request.Namespace} + req := ctrl.Request{NamespacedName: namespaceName} + requests = append(requests, req) + } + return requests + } +} + // SetupWithManager adds OperandRequest controller to the manager. func (r *Reconciler) SetupWithManager(mgr ctrl.Manager) error { options := controller.Options{ MaxConcurrentReconciles: r.MaxConcurrentReconciles, // Set the desired value for max concurrent reconciles. } + ReferencePredicates := predicate.Funcs{ + CreateFunc: func(e event.CreateEvent) bool { + labels := e.Object.GetLabels() + for labelKey, labelValue := range labels { + if labelKey == constant.ODLMWatchedLabel { + return labelValue == "true" + } + } + return false + }, + UpdateFunc: func(e event.UpdateEvent) bool { + labels := e.ObjectNew.GetLabels() + for labelKey, labelValue := range labels { + if labelKey == constant.ODLMWatchedLabel { + return labelValue == "true" + } + } + return false + }, + DeleteFunc: func(e event.DeleteEvent) bool { + return true + }, + } return ctrl.NewControllerManagedBy(mgr). WithOptions(options). For(&operatorv1alpha1.OperandRequest{}, builder.WithPredicates(predicate.GenerationChangedPredicate{})). @@ -342,5 +400,8 @@ func (r *Reconciler) SetupWithManager(mgr ctrl.Manager) error { newObject := e.ObjectNew.(*operatorv1alpha1.OperandConfig) return !reflect.DeepEqual(oldObject.Spec, newObject.Spec) }, - })).Complete(r) + })). + Watches(&source.Kind{Type: &corev1.ConfigMap{}}, handler.EnqueueRequestsFromMapFunc(r.getReferenceToRequestMapper()), builder.WithPredicates(ReferencePredicates)). + Watches(&source.Kind{Type: &corev1.Secret{}}, handler.EnqueueRequestsFromMapFunc(r.getReferenceToRequestMapper()), builder.WithPredicates(ReferencePredicates)). + Complete(r) } diff --git a/controllers/operandrequest/operandrequest_controller_test.go b/controllers/operandrequest/operandrequest_controller_test.go index 019111d7..a9af6751 100644 --- a/controllers/operandrequest/operandrequest_controller_test.go +++ b/controllers/operandrequest/operandrequest_controller_test.go @@ -43,7 +43,7 @@ var _ = Describe("OperandRequest controller", func() { namespace = "ibm-cloudpak" registryName1 = "common-service" registryName2 = "common-service-2" - registryNamespace = "ibm-common-services" + registryNamespace = "data-ns" operatorNamespace = "ibm-operators" ) @@ -319,6 +319,12 @@ var _ = Describe("OperandRequest controller", func() { return err }, testutil.Timeout, testutil.Interval).Should(Succeed()) + Eventually(func() error { + jaegerConfigMap := &corev1.ConfigMap{} + err := k8sClient.Get(context.TODO(), types.NamespacedName{Name: "jaeger-configmap-reference", Namespace: registryNamespaceName}, jaegerConfigMap) + return err + }, testutil.Timeout, testutil.Interval).Should(Succeed()) + By("Disabling the jaeger operator from first OperandRequest") requestInstance1 := &operatorv1alpha1.OperandRequest{} Expect(k8sClient.Get(ctx, requestKey1, requestInstance1)).Should(Succeed()) @@ -364,6 +370,11 @@ var _ = Describe("OperandRequest controller", func() { err := k8sClient.Get(context.TODO(), types.NamespacedName{Name: "jaeger-configmap", Namespace: registryNamespaceName}, jaegerConfigMap) return err != nil && errors.IsNotFound(err) }, testutil.Timeout, testutil.Interval).Should(BeTrue()) + Eventually(func() bool { + jaegerConfigMap := &corev1.ConfigMap{} + err := k8sClient.Get(context.TODO(), types.NamespacedName{Name: "jaeger-configmap-reference", Namespace: registryNamespaceName}, jaegerConfigMap) + return err != nil && errors.IsNotFound(err) + }, testutil.Timeout, testutil.Interval).Should(BeTrue()) By("Checking operators have been deleted") Eventually(func() bool { diff --git a/controllers/operandrequest/reconcile_operand.go b/controllers/operandrequest/reconcile_operand.go index cb445db3..1e8ffc43 100644 --- a/controllers/operandrequest/reconcile_operand.go +++ b/controllers/operandrequest/reconcile_operand.go @@ -170,7 +170,7 @@ func (r *Reconciler) reconcileOperand(ctx context.Context, requestInstance *oper klog.V(2).Infof("There is no service: %s from the OperandConfig instance: %s/%s, Skip reconciling Operands", operand.Name, registryKey.Namespace, req.Registry) continue } - err = r.reconcileCRwithConfig(ctx, opdConfig, configInstance.Namespace, csv, requestInstance, operand.Name, sub.Namespace, &r.Mutex) + err = r.reconcileCRwithConfig(ctx, opdConfig, configInstance.Name, configInstance.Namespace, csv, requestInstance, operand.Name, sub.Namespace, &r.Mutex) if err != nil { merr.Add(err) requestInstance.SetMemberStatus(operand.Name, "", operatorv1alpha1.ServiceFailed, &r.Mutex) @@ -202,12 +202,13 @@ func (r *Reconciler) reconcileOperand(ctx context.Context, requestInstance *oper } // reconcileCRwithConfig merge and create custom resource base on OperandConfig and CSV alm-examples -func (r *Reconciler) reconcileCRwithConfig(ctx context.Context, service *operatorv1alpha1.ConfigService, namespace string, csv *olmv1alpha1.ClusterServiceVersion, requestInstance *operatorv1alpha1.OperandRequest, operandName string, operatorNamespace string, mu sync.Locker) error { +func (r *Reconciler) reconcileCRwithConfig(ctx context.Context, service *operatorv1alpha1.ConfigService, opConfigName, opConfigNs string, csv *olmv1alpha1.ClusterServiceVersion, requestInstance *operatorv1alpha1.OperandRequest, operandName string, operatorNamespace string, mu sync.Locker) error { merr := &util.MultiErr{} // Create k8s resources required by service if service.Resources != nil { - for _, res := range service.Resources { + for i := range service.Resources { + res := service.Resources[i] if res.APIVersion == "" { return fmt.Errorf("The APIVersion of k8s resource is empty for operator " + service.Name) } @@ -220,11 +221,27 @@ func (r *Reconciler) reconcileCRwithConfig(ctx context.Context, service *operato } var k8sResNs string if res.Namespace == "" { - k8sResNs = namespace + k8sResNs = opConfigNs } else { k8sResNs = res.Namespace } + resObject, err := util.ObjectToNewUnstructured(&res) + if err != nil { + klog.Errorf("Failed to convert %s %s/%s object to unstructured.Unstructured object", res.Kind, k8sResNs, res.Name) + return err + } + + if err := r.ParseValueReferenceInObject(ctx, "data", resObject.Object["data"], resObject.Object, "OperandConfig", opConfigName, opConfigNs); err != nil { + klog.Errorf("Failed to parse value reference in resource %s/%s: %v", k8sResNs, res.Name, err) + return err + } + // cover unstructured.Unstructured object to original OperandConfig object + if err := runtime.DefaultUnstructuredConverter.FromUnstructured(resObject.Object, &res); err != nil { + klog.Errorf("Failed to convert unstructured.Unstructured object to %s %s/%s object", res.Kind, k8sResNs, res.Name) + return err + } + var k8sRes unstructured.Unstructured k8sRes.SetAPIVersion(res.APIVersion) k8sRes.SetKind(res.Kind) @@ -271,7 +288,7 @@ func (r *Reconciler) reconcileCRwithConfig(ctx context.Context, service *operato var almExampleList []interface{} err := json.Unmarshal([]byte(almExamples), &almExampleList) if err != nil { - return errors.Wrapf(err, "failed to convert alm-examples in the Subscription %s/%s to slice", namespace, service.Name) + return errors.Wrapf(err, "failed to convert alm-examples in the Subscription %s/%s to slice", opConfigNs, service.Name) } foundMap := make(map[string]bool) @@ -279,6 +296,22 @@ func (r *Reconciler) reconcileCRwithConfig(ctx context.Context, service *operato foundMap[cr] = false } + serviceObject, err := util.ObjectToNewUnstructured(service) + if err != nil { + klog.Errorf("Failed to convert OperandConfig service object %s to unstructured.Unstructured object", service.Name) + return err + } + + if err := r.ParseValueReferenceInObject(ctx, "spec", serviceObject.Object["spec"], serviceObject.Object, "OperandConfig", opConfigName, opConfigNs); err != nil { + klog.Errorf("Failed to parse value reference for service %s: %v", service.Name, err) + return err + } + // cover unstructured.Unstructured object to original OperandConfig object + if err := runtime.DefaultUnstructuredConverter.FromUnstructured(serviceObject.Object, service); err != nil { + klog.Errorf("Failed to convert unstructured.Unstructured object to service object %s", service.Name) + return err + } + // Merge OperandConfig and ClusterServiceVersion alm-examples for _, almExample := range almExampleList { // Create an unstructured object for CR and check its value @@ -293,7 +326,7 @@ func (r *Reconciler) reconcileCRwithConfig(ctx context.Context, service *operato err := r.Client.Get(ctx, types.NamespacedName{ Name: name, - Namespace: namespace, + Namespace: opConfigNs, }, &crFromALM) foundInConfig := false @@ -308,19 +341,20 @@ func (r *Reconciler) reconcileCRwithConfig(ctx context.Context, service *operato klog.Warningf("%v in the alm-example doesn't exist in the OperandConfig for %v", crFromALM.GetKind(), csv.GetName()) continue } + if err != nil && !apierrors.IsNotFound(err) { - merr.Add(errors.Wrapf(err, "failed to get the custom resource %s/%s", namespace, name)) + merr.Add(errors.Wrapf(err, "failed to get the custom resource %s/%s", opConfigNs, name)) continue } else if apierrors.IsNotFound(err) { // Create Custom Resource - if err := r.compareConfigandExample(ctx, crFromALM, service, namespace); err != nil { + if err := r.compareConfigandExample(ctx, crFromALM, service, opConfigNs); err != nil { merr.Add(err) continue } } else { if r.CheckLabel(crFromALM, map[string]string{constant.OpreqLabel: "true"}) { // Update or Delete Custom Resource - if err := r.existingCustomResource(ctx, crFromALM, spec.(map[string]interface{}), service, namespace); err != nil { + if err := r.existingCustomResource(ctx, crFromALM, spec.(map[string]interface{}), service, opConfigNs); err != nil { merr.Add(err) continue } diff --git a/controllers/operator/manager.go b/controllers/operator/manager.go index abe302f3..3dbb3115 100644 --- a/controllers/operator/manager.go +++ b/controllers/operator/manager.go @@ -18,6 +18,7 @@ package operator import ( "context" + "encoding/json" "fmt" "sort" "strings" @@ -25,6 +26,7 @@ import ( olmv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1" operatorsv1 "github.com/operator-framework/operator-lifecycle-manager/pkg/package-server/apis/operators/v1" "github.com/pkg/errors" + corev1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" @@ -427,3 +429,256 @@ func (m *ODLMOperator) EnsureAnnotation(cr unstructured.Unstructured, annotation } cr.SetAnnotations(existingAnnotations) } + +func (m *ODLMOperator) ParseValueReferenceInObject(ctx context.Context, key string, object interface{}, finalObject map[string]interface{}, instanceType, instanceName, instanceNs string) error { + switch object.(type) { + case map[string]interface{}: + for subKey, value := range object.(map[string]interface{}) { + if subKey == "templatingValueFrom" { + valueRef := "" + if templateRef, ok := value.(map[string]interface{}); ok { + // convert templateRef to templatingValueRef struct + templateRefByte, err := json.Marshal(templateRef) + if err != nil { + klog.Errorf("Failed to convert templateRef to templatingValueRef struct for %s %s/%s: %v", instanceType, instanceNs, instanceName, err) + return err + } + templateRefObj := &util.TemplateValueRef{} + if err := json.Unmarshal(templateRefByte, templateRefObj); err != nil { + klog.Errorf("Failed to convert templateRef to templatingValueRef struct for %s %s/%s: %v", instanceType, instanceNs, instanceName, err) + return err + } + + // get the defaultValue from template + valueRef, err = m.GetDefaultValueFromTemplate(ctx, templateRefObj, instanceType, instanceName, instanceNs) + if err != nil { + klog.Errorf("Failed to get default value from template for %s %s/%s on field %s: %v", instanceType, instanceNs, instanceName, key, err) + } + + // get the value from the ConfigMap reference + if ref, err := m.ParseConfigMapRef(ctx, templateRefObj.ConfigMapKeyRef, instanceType, instanceName, instanceNs); err != nil { + klog.Errorf("Failed to get value reference from ConfigMap for %s %s/%s on field %s: %v", instanceType, instanceNs, instanceName, key, err) + return err + } else if ref != "" { + valueRef = ref + } + + // get the value from the secret + if ref, err := m.ParseSecretKeyRef(ctx, templateRefObj.SecretRef, instanceType, instanceName, instanceNs); err != nil { + klog.Errorf("Failed to get value reference from Secret for %s %s/%s on field %s: %v", instanceType, instanceNs, instanceName, key, err) + return err + } else if ref != "" { + valueRef = ref + } + + // get the value from the object + if ref, err := m.ParseObjectRef(ctx, templateRefObj.ObjectRef, instanceType, instanceName, instanceNs); err != nil { + klog.Errorf("Failed to get value reference from Object for %s %s/%s on field %s: %v", instanceType, instanceNs, instanceName, key, err) + return err + } else if ref != "" { + valueRef = ref + } + + if valueRef == "" && templateRefObj.Required { + return errors.Errorf("Found empty value reference from template for %s %s/%s on field %s, retry in few second", instanceType, instanceNs, instanceName, key) + } + } + // overwrite the value with the value from the reference + finalObject[key] = valueRef + } else { + if err := m.ParseValueReferenceInObject(ctx, subKey, object.(map[string]interface{})[subKey], finalObject[key].(map[string]interface{}), instanceType, instanceName, instanceNs); err != nil { + return err + } + } + } + case []interface{}: + for i := range finalObject[key].([]interface{}) { + if _, ok := finalObject[key].([]interface{})[i].(map[string]interface{}); ok { + for subKey, value := range finalObject[key].([]interface{})[i].(map[string]interface{}) { + if err := m.ParseValueReferenceInObject(ctx, subKey, value, finalObject[key].([]interface{})[i].(map[string]interface{}), instanceType, instanceName, instanceNs); err != nil { + return err + } + } + } + } + } + return nil +} + +func (m *ODLMOperator) GetDefaultValueFromTemplate(ctx context.Context, template *util.TemplateValueRef, instanceType, instanceName, instanceNs string) (string, error) { + if template == nil { + return "", nil + } + if template.Default != nil { + defaultValue := template.Default.DefaultValue + if ref, err := m.ParseConfigMapRef(ctx, template.Default.ConfigMapKeyRef, instanceType, instanceName, instanceNs); err != nil { + return "", err + } else if ref != "" { + defaultValue = ref + } + if ref, err := m.ParseSecretKeyRef(ctx, template.Default.SecretRef, instanceType, instanceName, instanceNs); err != nil { + return "", err + } else if ref != "" { + defaultValue = ref + } + if ref, err := m.ParseObjectRef(ctx, template.Default.ObjectRef, instanceType, instanceName, instanceNs); err != nil { + return "", err + } else if ref != "" { + defaultValue = ref + } + + if defaultValue == "" && template.Default.Required { + return "", errors.Errorf("Failed to get default value from template, retry in few second") + } + return defaultValue, nil + } + return "", nil +} + +func (m *ODLMOperator) ParseConfigMapRef(ctx context.Context, cm *util.ConfigMapRef, instanceType, instanceName, instanceNs string) (string, error) { + if cm == nil { + return "", nil + } + if cm.Namespace == "" { + cm.Namespace = instanceNs + } + cmData, err := m.GetValueRefFromConfigMap(ctx, instanceType, instanceName, instanceNs, cm.Name, cm.Namespace, cm.Key) + if err != nil { + klog.Errorf("Failed to get value reference from ConfigMap %s/%s with key %s: %v", cm.Namespace, cm.Name, cm.Key, err) + return "", err + } + return cmData, nil +} + +func (m *ODLMOperator) ParseSecretKeyRef(ctx context.Context, secret *util.SecretRef, instanceType, instanceName, instanceNs string) (string, error) { + if secret == nil { + return "", nil + } + if secret.Namespace == "" { + secret.Namespace = instanceNs + } + secretData, err := m.GetValueRefFromSecret(ctx, instanceType, instanceName, instanceNs, secret.Name, secret.Namespace, secret.Key) + if err != nil { + klog.Errorf("Failed to get value reference from Secret %s/%s with key %s: %v", secret.Namespace, secret.Name, secret.Key, err) + return "", err + } + return secretData, nil +} + +func (m *ODLMOperator) ParseObjectRef(ctx context.Context, obj *util.ObjectRef, instanceType, instanceName, instanceNs string) (string, error) { + if obj == nil { + return "", nil + } + if obj.Namespace == "" { + obj.Namespace = instanceNs + } + if obj.APIVersion == "" { + return "", errors.New("apiVersion is empty") + } + if obj.Kind == "" { + return "", errors.New("kind is empty") + } + // get the value from the object + objData, err := m.GetValueRefFromObject(ctx, instanceType, instanceName, instanceNs, obj.APIVersion, obj.Kind, obj.Name, obj.Namespace, obj.Path) + if err != nil { + klog.Errorf("Failed to get value reference from Object %s/%s with path %s: %v", obj.Namespace, obj.Name, obj.Path, err) + return "", err + } + return objData, nil +} + +func (m *ODLMOperator) GetValueRefFromConfigMap(ctx context.Context, instanceType, instanceName, instanceNs, cmName, cmNs, configMapKey string) (string, error) { + cm := &corev1.ConfigMap{} + if err := m.Client.Get(ctx, types.NamespacedName{Name: cmName, Namespace: cmNs}, cm); err != nil { + if apierrors.IsNotFound(err) { + klog.V(2).Infof("Configmap %s/%s is not found", cmNs, cmName) + return "", nil + } + return "", errors.Wrapf(err, "failed to get Configmap %s/%s", cmNs, cmName) + } + + // Set the Value Reference label for the ConfigMap + util.EnsureLabelsForConfigMap(cm, map[string]string{ + constant.ODLMReferenceLabel: instanceType + "." + instanceNs + "." + instanceName, + constant.ODLMWatchedLabel: "true", + }) + // Update the ConfigMap with the Value Reference label + if err := m.Update(ctx, cm); err != nil { + return "", errors.Wrapf(err, "failed to update ConfigMap %s/%s", cm.Namespace, cm.Name) + } + klog.V(2).Infof("Set the Value Reference label for ConfigMap %s/%s", cm.Namespace, cm.Name) + + if cm.Data != nil { + if data, ok := cm.Data[configMapKey]; ok { + return data, nil + } + } + return "", nil +} + +func (m *ODLMOperator) GetValueRefFromSecret(ctx context.Context, instanceType, instanceName, instanceNs, secretName, secretNs, secretKey string) (string, error) { + secret := &corev1.Secret{} + if err := m.Client.Get(ctx, types.NamespacedName{Name: secretName, Namespace: secretNs}, secret); err != nil { + if apierrors.IsNotFound(err) { + klog.V(3).Infof("Secret %s/%s is not found", secretNs, secretName) + return "", nil + } + return "", errors.Wrapf(err, "failed to get Secret %s/%s", secretNs, secretName) + } + + // Set the Value Reference label for the Secret + util.EnsureLabelsForSecret(secret, map[string]string{ + constant.ODLMReferenceLabel: instanceType + "." + instanceNs + "." + instanceName, + constant.ODLMWatchedLabel: "true", + }) + // Update the Secret with the Value Reference label + if err := m.Update(ctx, secret); err != nil { + return "", errors.Wrapf(err, "failed to update Secret %s/%s", secret.Namespace, secret.Name) + } + klog.V(2).Infof("Set the Value Reference label for Secret %s/%s", secret.Namespace, secret.Name) + + if secret.Data != nil { + if data, ok := secret.Data[secretKey]; ok { + return string(data), nil + } + } + return "", nil +} + +func (m *ODLMOperator) GetValueRefFromObject(ctx context.Context, instanceType, instanceName, instanceNs, objAPIVersion, objKind, objName, objNs, path string) (string, error) { + var obj unstructured.Unstructured + obj.SetAPIVersion(objAPIVersion) + obj.SetKind(objKind) + if err := m.Client.Get(ctx, types.NamespacedName{Name: objName, Namespace: objNs}, &obj); err != nil { + if apierrors.IsNotFound(err) { + klog.V(3).Infof("%s %s/%s is not found", objKind, objNs, objName) + return "", nil + } + return "", errors.Wrapf(err, "failed to get %s %s/%s", objKind, objNs, objName) + } + + // Set the Value Reference label for the object + m.EnsureLabel(obj, map[string]string{ + constant.ODLMReferenceLabel: instanceType + "." + instanceNs + "." + instanceName, + constant.ODLMWatchedLabel: "true", + }) + // Update the object with the Value Reference label + if err := m.Update(ctx, &obj); err != nil { + return "", errors.Wrapf(err, "failed to update %s %s/%s", objKind, obj.GetNamespace(), obj.GetName()) + } + klog.V(2).Infof("Set the Value Reference label for %s %s/%s", objKind, obj.GetNamespace(), obj.GetName()) + + if path == "" { + return "", nil + } + + value, ok, err := unstructured.NestedString(obj.Object, strings.Split(path, ".")...) + if err != nil { + return "", errors.Wrapf(err, "failed to parse path %v from %s %s/%s", path, obj.GetKind(), obj.GetNamespace(), obj.GetName()) + } else if !ok { + return "", errors.Errorf("failed to get path %v from %s %s/%s, the value is not found", path, obj.GetKind(), obj.GetNamespace(), obj.GetName()) + } + + klog.V(2).Infof("Get value %s from %s %s/%s", value, objKind, obj.GetNamespace(), obj.GetName()) + return value, nil +} diff --git a/controllers/testutil/test_util.go b/controllers/testutil/test_util.go index 6052a98e..2e761d52 100644 --- a/controllers/testutil/test_util.go +++ b/controllers/testutil/test_util.go @@ -56,7 +56,7 @@ var SubConfig = &olmv1alpha1.SubscriptionConfig{ // CreateNSName generates random namespace names. Namespaces are never deleted in test environment func CreateNSName(prefix string) string { - suffix := make([]byte, 10) + suffix := make([]byte, 4) _, err := rand.Read(suffix) if err != nil { panic(err) @@ -142,7 +142,18 @@ func OperandConfigObj(name, namespace string) *apiv1alpha1.OperandConfig { Name: "jaeger", Spec: map[string]apiv1alpha1.ExtensionWithMarker{ "jaeger": { - RawExtension: runtime.RawExtension{Raw: []byte(`{"strategy": "streaming"}`)}, + RawExtension: runtime.RawExtension{Raw: []byte(`{ + "strategy": { + "templatingValueFrom": { + "required": true, + "configMapKeyRef": { + "name": "jaeger-configmap-reference", + "key": "putStrategy" + } + } + } + }`), + }, }, }, Resources: []apiv1alpha1.ConfigResource{ @@ -161,6 +172,36 @@ func OperandConfigObj(name, namespace string) *apiv1alpha1.OperandConfig { }, Force: false, }, + { + Name: "jaeger-configmap-reference", + APIVersion: "v1", + Kind: "ConfigMap", + Labels: map[string]string{ + "jaeger": "jaeger-configmap-reference", + }, + Annotations: map[string]string{ + "jaeger": "jaeger-configmap-reference", + }, + Data: &runtime.RawExtension{ + Raw: []byte(`{ + "data": { + "getStrategy": { + "templatingValueFrom": { + "required": true, + "objectRef": { + "apiVersion": "v1", + "kind": "ConfigMap", + "name": "jaeger-configmap", + "path": "data.strategy" + } + } + }, + "putStrategy": "streaming" + } + }`), + }, + Force: false, + }, }, }, { diff --git a/controllers/util/util.go b/controllers/util/util.go index ad53be14..24785e8e 100644 --- a/controllers/util/util.go +++ b/controllers/util/util.go @@ -17,6 +17,7 @@ package util import ( + "fmt" "os" "sort" "strconv" @@ -24,9 +25,51 @@ import ( "sync" "time" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/equality" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime" "k8s.io/client-go/discovery" ) +type TemplateValueRef struct { + Required bool `json:"required,omitempty"` + Default *DefaultObjectRef `json:"default,omitempty"` + ConfigMapKeyRef *ConfigMapRef `json:"configMapKeyRef,omitempty"` + SecretRef *SecretRef `json:"secretKeyRef,omitempty"` + // RouteRef *RouteRef `json:"routePathRef,omitempty"` + ObjectRef *ObjectRef `json:"objectRef,omitempty"` +} + +type DefaultObjectRef struct { + Required bool `json:"required,omitempty"` + ConfigMapKeyRef *ConfigMapRef `json:"configMapKeyRef,omitempty"` + SecretRef *SecretRef `json:"secretKeyRef,omitempty"` + // RouteRef *RouteRef `json:"routePathRef,omitempty"` + ObjectRef *ObjectRef `json:"objectRef,omitempty"` + DefaultValue string `json:"defaultValue,omitempty"` +} + +type ConfigMapRef struct { + Name string `json:"name"` + Namespace string `json:"namespace"` + Key string `json:"key"` +} + +type SecretRef struct { + Name string `json:"name"` + Namespace string `json:"namespace"` + Key string `json:"key"` +} + +type ObjectRef struct { + Name string `json:"name"` + Namespace string `json:"namespace"` + Path string `json:"path"` + APIVersion string `json:"apiVersion"` + Kind string `json:"kind"` +} + // GetOperatorNamespace returns the Namespace of the operator func GetOperatorNamespace() string { ns, found := os.LookupEnv("OPERATOR_NAMESPACE") @@ -188,3 +231,39 @@ func Contains(list []string, s string) bool { } return false } + +func ObjectToNewUnstructured(obj interface{}) (*unstructured.Unstructured, error) { + content, err := runtime.DefaultUnstructuredConverter.ToUnstructured(obj) + if err != nil { + return nil, fmt.Errorf("could not convert Object to Unstructured resource: %v", err) + } + newUnstr := &unstructured.Unstructured{} + newUnstr.SetUnstructuredContent(content) + return newUnstr, nil +} + +func EnsureLabelsForSecret(secret *corev1.Secret, labels map[string]string) { + if secret.Labels == nil { + secret.Labels = make(map[string]string) + } + for k, v := range labels { + secret.Labels[k] = v + } +} + +func EnsureLabelsForConfigMap(cm *corev1.ConfigMap, labels map[string]string) { + if cm.Labels == nil { + cm.Labels = make(map[string]string) + } + for k, v := range labels { + cm.Labels[k] = v + } +} + +func CompareSecret(secret *corev1.Secret, existingSecret *corev1.Secret) (needUpdate bool) { + return !equality.Semantic.DeepEqual(secret.GetLabels(), existingSecret.GetLabels()) || !equality.Semantic.DeepEqual(secret.Type, existingSecret.Type) || !equality.Semantic.DeepEqual(secret.Data, existingSecret.Data) || !equality.Semantic.DeepEqual(secret.StringData, existingSecret.StringData) +} + +func CompareConfigMap(configMap *corev1.ConfigMap, existingConfigMap *corev1.ConfigMap) (needUpdate bool) { + return !equality.Semantic.DeepEqual(configMap.GetLabels(), existingConfigMap.GetLabels()) || !equality.Semantic.DeepEqual(configMap.Data, existingConfigMap.Data) || !equality.Semantic.DeepEqual(configMap.BinaryData, existingConfigMap.BinaryData) +} diff --git a/go.mod b/go.mod index acfd297c..1a2e313b 100644 --- a/go.mod +++ b/go.mod @@ -16,6 +16,7 @@ require ( github.com/pkg/errors v0.9.1 golang.org/x/mod v0.8.0 k8s.io/api v0.24.3 + k8s.io/apiextensions-apiserver v0.24.2 k8s.io/apimachinery v0.24.3 k8s.io/client-go v0.24.3 k8s.io/klog v1.0.0 @@ -94,7 +95,6 @@ require ( gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/apiextensions-apiserver v0.24.2 // indirect k8s.io/component-base v0.24.2 // indirect k8s.io/klog/v2 v2.60.1 // indirect k8s.io/kube-openapi v0.0.0-20220627174259-011e075b9cb8 // indirect diff --git a/main.go b/main.go index 8178733d..17b3658b 100644 --- a/main.go +++ b/main.go @@ -84,10 +84,10 @@ func main() { gvkLabelMap := map[schema.GroupVersionKind]cache.Selector{ corev1.SchemeGroupVersion.WithKind("Secret"): { - LabelSelector: constant.OpbiTypeLabel, + LabelSelector: constant.ODLMWatchedLabel, }, corev1.SchemeGroupVersion.WithKind("ConfigMap"): { - LabelSelector: constant.OpbiTypeLabel, + LabelSelector: constant.ODLMWatchedLabel, }, appsv1.SchemeGroupVersion.WithKind("Deployment"): { LabelSelector: constant.BindInfoRefreshLabel, From 947c757e7fc860db9a08019a355f2b9bee965700 Mon Sep 17 00:00:00 2001 From: Ben Luzarraga <31223504+bluzarraga@users.noreply.github.com> Date: Thu, 2 Nov 2023 10:42:52 -0500 Subject: [PATCH 059/179] update grpc pkg (#991) --- go.mod | 14 +++++++------- go.sum | 26 +++++++++++++------------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/go.mod b/go.mod index 1a2e313b..d76c464e 100644 --- a/go.mod +++ b/go.mod @@ -16,7 +16,6 @@ require ( github.com/pkg/errors v0.9.1 golang.org/x/mod v0.8.0 k8s.io/api v0.24.3 - k8s.io/apiextensions-apiserver v0.24.2 k8s.io/apimachinery v0.24.3 k8s.io/client-go v0.24.3 k8s.io/klog v1.0.0 @@ -25,7 +24,7 @@ require ( ) require ( - cloud.google.com/go/compute v1.19.1 // indirect + cloud.google.com/go/compute v1.23.0 // indirect cloud.google.com/go/compute/metadata v0.2.3 // indirect github.com/PuerkitoBio/purell v1.1.1 // indirect github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect @@ -48,7 +47,7 @@ require ( github.com/golang/protobuf v1.5.3 // indirect github.com/google/gnostic v0.6.9 // indirect github.com/google/gofuzz v1.1.0 // indirect - github.com/google/uuid v1.3.0 // indirect + github.com/google/uuid v1.3.1 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/imdario/mergo v0.3.12 // indirect github.com/josharian/intern v1.0.0 // indirect @@ -80,21 +79,22 @@ require ( go.uber.org/multierr v1.6.0 // indirect go.uber.org/zap v1.19.1 // indirect golang.org/x/net v0.17.0 // indirect - golang.org/x/oauth2 v0.7.0 // indirect + golang.org/x/oauth2 v0.11.0 // indirect golang.org/x/sys v0.13.0 // indirect golang.org/x/term v0.13.0 // indirect golang.org/x/text v0.13.0 // indirect golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19 // indirect - google.golang.org/grpc v1.57.1 // indirect - google.golang.org/protobuf v1.30.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d // indirect + google.golang.org/grpc v1.59.0 // indirect + google.golang.org/protobuf v1.31.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ini.v1 v1.66.4 // indirect gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect + k8s.io/apiextensions-apiserver v0.24.2 // indirect k8s.io/component-base v0.24.2 // indirect k8s.io/klog/v2 v2.60.1 // indirect k8s.io/kube-openapi v0.0.0-20220627174259-011e075b9cb8 // indirect diff --git a/go.sum b/go.sum index d6ac5795..8c4374fb 100644 --- a/go.sum +++ b/go.sum @@ -28,8 +28,8 @@ cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvf cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/compute v1.19.1 h1:am86mquDUgjGNWxiGn+5PGLbmgiWXlE/yNWpIpNvuXY= -cloud.google.com/go/compute v1.19.1/go.mod h1:6ylj3a05WF8leseCdIf77NK0g1ey+nj5IKd5/kvShxE= +cloud.google.com/go/compute v1.23.0 h1:tP41Zoavr8ptEqaW6j+LQOnyBBhO7OkOMAGrgLopTwY= +cloud.google.com/go/compute v1.23.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= @@ -497,8 +497,8 @@ github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm4 github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= -github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= +github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= @@ -1165,8 +1165,8 @@ golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.7.0 h1:qe6s0zUXlPX80/dITx3440hWZ7GwMwgDDyrSGTPJG/g= -golang.org/x/oauth2 v0.7.0/go.mod h1:hPLQkd9LyjfXTiRohC/41GhcFqxisoUQ99sCUOHO9x4= +golang.org/x/oauth2 v0.11.0 h1:vPL4xzxBM4niKCW6g9whtaWVXTJf1U5e4aZxxFx/gbU= +golang.org/x/oauth2 v0.11.0/go.mod h1:LdF7O/8bLR/qWK9DrpXmbHLTouvRHK0SgJl0GmDBchk= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1177,8 +1177,8 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/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-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1470,8 +1470,8 @@ google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaE google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= google.golang.org/genproto v0.0.0-20220107163113-42d7afdf6368/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19 h1:0nDDozoAU19Qb2HwhXadU8OcsiO/09cnTqhUtq2MEOM= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d h1:uvYuEyMHKNt+lT4K3bN6fGswmK8qSvcreM3BwjDh+y4= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M= google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= @@ -1499,8 +1499,8 @@ google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAG google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.57.1 h1:upNTNqv0ES+2ZOOqACwVtS3Il8M12/+Hz41RCPzAjQg= -google.golang.org/grpc v1.57.1/go.mod h1:Sd+9RMTACXwmub0zcNY2c4arhtrbBYD1AUHI/dt16Mo= +google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk= +google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= google.golang.org/grpc/cmd/protoc-gen-go-grpc v0.0.0-20200709232328-d8193ee9cc3e/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= 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= @@ -1515,8 +1515,8 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba 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.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= -google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= +google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= From 144e73b1e3f8f1fcc8f21929ffe7bbbff0f91df7 Mon Sep 17 00:00:00 2001 From: Henry Li Date: Fri, 3 Nov 2023 01:01:52 -0400 Subject: [PATCH 060/179] Add support for sharing Route data via ConfigMap with OperandBindInfo (#992) * renamed SecretConfigmap type to Bindable - because OperandConfig will be extended to handle more than just Secrets and Configmaps Signed-off-by: Henry H Li * added support to OperandBindInfo for route data - conditionally does it if Route API exists Signed-off-by: Henry H Li * removed unused routeKind variable Signed-off-by: Henry H Li * added restConfig to Reconciler for dependency injection when testing Signed-off-by: Henry H Li * fixed issue with controller always adding route bindable to OperandBindInfo because Route type was a struct and not a point, so could not be nil Signed-off-by: Henry H Li --------- Signed-off-by: Henry H Li --- Makefile | 2 +- api/v1alpha1/operandbindinfo_types.go | 28 +- api/v1alpha1/operandrequest_types.go | 2 +- api/v1alpha1/zz_generated.deepcopy.go | 43 +- bundle.Dockerfile | 2 +- ...fecycle-manager.clusterserviceversion.yaml | 563 +++++++++--------- .../operator.ibm.com_operandbindinfos.yaml | 22 +- .../operator.ibm.com_operandrequests.yaml | 27 +- bundle/metadata/annotations.yaml | 3 +- .../operator.ibm.com_operandbindinfos.yaml | 22 +- .../operator.ibm.com_operandrequests.yaml | 27 +- .../operator.ibm.com_operandbindinfos.yaml | 25 +- .../operator.ibm.com_operandrequests.yaml | 77 ++- .../operandbindinfo_controller.go | 231 ++++++- .../operandbindinfo_suite_test.go | 1 + controllers/testutil/test_util.go | 6 +- controllers/util/util.go | 10 + go.mod | 3 +- go.sum | 25 + main.go | 2 + test/e2e/helpers_test.go | 4 +- 21 files changed, 804 insertions(+), 321 deletions(-) diff --git a/Makefile b/Makefile index 9b453970..f588bec2 100644 --- a/Makefile +++ b/Makefile @@ -209,7 +209,7 @@ bundle-manifests: -q --overwrite --version $(OPERATOR_VERSION) $(BUNDLE_METADATA_OPTS) $(OPERATOR_SDK) bundle validate ./bundle $(YQ) eval-all -i '.spec.relatedImages = load("config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml").spec.relatedImages' bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml - # Need to replace fields this way to avoid changing PROJECT name and CSV file name, which may or may not impact CICD automation + @# Need to replace fields this way to avoid changing PROJECT name and CSV file name, which may or may not impact CICD automation $(YQ) e -i '.annotations["operators.operatorframework.io.bundle.package.v1"] = "ibm-odlm"' bundle/metadata/annotations.yaml sed -i'' s/operand-deployment-lifecycle-manager/ibm-odlm/ bundle.Dockerfile diff --git a/api/v1alpha1/operandbindinfo_types.go b/api/v1alpha1/operandbindinfo_types.go index 54f812aa..d7516360 100644 --- a/api/v1alpha1/operandbindinfo_types.go +++ b/api/v1alpha1/operandbindinfo_types.go @@ -38,7 +38,7 @@ const ( BindInfoFailed BindInfoPhase = "Failed" BindInfoInit BindInfoPhase = "Initialized" BindInfoUpdating BindInfoPhase = "Updating" - BindInfoWaiting BindInfoPhase = "Waiting for Secret and/or Configmap from provider" + BindInfoWaiting BindInfoPhase = "Waiting for Bindable resource from provider. One of: Secret, ConfigMap, Route, or Service" ) // OperandBindInfoSpec defines the desired state of OperandBindInfo. @@ -56,17 +56,37 @@ type OperandBindInfoSpec struct { Description string `json:"description,omitempty"` // The bindings section is used to specify information about the access/configuration data that is to be shared. // +optional - Bindings map[string]SecretConfigmap `json:"bindings,omitempty"` + Bindings map[string]Bindable `json:"bindings,omitempty"` } -// SecretConfigmap is a pair of Secret and/or Configmap. -type SecretConfigmap struct { +// Bindable is a Kubernetes resources to be shared from one namespace to another. +// List of supported resources are Secrets, Configmaps, Services, and Routes. +// Secrets and Configmaps will be copied such that a new Secret/Configmap with +// exactly the same data will be created in the target namespace. +// Services and Routes data will be copied into a configmap in the target +// namespace. +type Bindable struct { // The secret identifies an existing secret. if it exists, the ODLM will share to the namespace of the OperandRequest. // +optional Secret string `json:"secret,omitempty"` // The configmap identifies an existing configmap object. if it exists, the ODLM will share to the namespace of the OperandRequest. // +optional Configmap string `json:"configmap,omitempty"` + // Route data will shared by copying it into a configmap which is then + // created in the target namespace + // +optional + Route *Route `json:"route,omitempty"` +} + +// Route represents the name and data inside an OpenShift route. +type Route struct { + // Name is the name of the OpenShift Route resource + // +optional + Name string `json:"name"` + // Data is a key-value pair where the value is a YAML path to a value in the + // OpenShift Route, e.g. .spec.host or .spec.tls.termination + // +optional + Data map[string]string `json:"data"` } // OperandBindInfoStatus defines the observed state of OperandBindInfo. diff --git a/api/v1alpha1/operandrequest_types.go b/api/v1alpha1/operandrequest_types.go index d27a3bcb..349a57df 100644 --- a/api/v1alpha1/operandrequest_types.go +++ b/api/v1alpha1/operandrequest_types.go @@ -63,7 +63,7 @@ type Operand struct { Name string `json:"name"` // The bindings section is used to specify names of secret and/or configmap. // +optional - Bindings map[string]SecretConfigmap `json:"bindings,omitempty"` + Bindings map[string]Bindable `json:"bindings,omitempty"` // Kind is used when users want to deploy multiple custom resources. // Kind identifies the kind of the custom resource. // +optional diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 2e108765..8cfe54b7 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -26,6 +26,26 @@ import ( "k8s.io/apimachinery/pkg/runtime" ) +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Bindable) DeepCopyInto(out *Bindable) { + *out = *in + if in.Route != nil { + in, out := &in.Route, &out.Route + *out = new(Route) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Bindable. +func (in *Bindable) DeepCopy() *Bindable { + if in == nil { + return nil + } + out := new(Bindable) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Condition) DeepCopyInto(out *Condition) { *out = *in @@ -183,9 +203,9 @@ func (in *Operand) DeepCopyInto(out *Operand) { *out = *in if in.Bindings != nil { in, out := &in.Bindings, &out.Bindings - *out = make(map[string]SecretConfigmap, len(*in)) + *out = make(map[string]Bindable, len(*in)) for key, val := range *in { - (*out)[key] = val + (*out)[key] = *val.DeepCopy() } } if in.Spec != nil { @@ -269,9 +289,9 @@ func (in *OperandBindInfoSpec) DeepCopyInto(out *OperandBindInfoSpec) { *out = *in if in.Bindings != nil { in, out := &in.Bindings, &out.Bindings - *out = make(map[string]SecretConfigmap, len(*in)) + *out = make(map[string]Bindable, len(*in)) for key, val := range *in { - (*out)[key] = val + (*out)[key] = *val.DeepCopy() } } } @@ -765,16 +785,23 @@ func (in *ResourceStatus) DeepCopy() *ResourceStatus { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *SecretConfigmap) DeepCopyInto(out *SecretConfigmap) { +func (in *Route) DeepCopyInto(out *Route) { *out = *in + if in.Data != nil { + in, out := &in.Data, &out.Data + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecretConfigmap. -func (in *SecretConfigmap) DeepCopy() *SecretConfigmap { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Route. +func (in *Route) DeepCopy() *Route { if in == nil { return nil } - out := new(SecretConfigmap) + out := new(Route) in.DeepCopyInto(out) return out } diff --git a/bundle.Dockerfile b/bundle.Dockerfile index 3b1d7cf3..c12c2221 100644 --- a/bundle.Dockerfile +++ b/bundle.Dockerfile @@ -7,7 +7,7 @@ LABEL operators.operatorframework.io.bundle.metadata.v1=metadata/ LABEL operators.operatorframework.io.bundle.package.v1=ibm-odlm LABEL operators.operatorframework.io.bundle.channels.v1=v4.2 LABEL operators.operatorframework.io.bundle.channel.default.v1=v4.2 -LABEL operators.operatorframework.io.metrics.builder=operator-sdk-v1.32.0 +LABEL operators.operatorframework.io.metrics.builder=operator-sdk-v1.29.0 LABEL operators.operatorframework.io.metrics.mediatype.v1=metrics+v1 LABEL operators.operatorframework.io.metrics.project_layout=go.kubebuilder.io/v3 diff --git a/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml b/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml index a51b5818..709e8c9d 100644 --- a/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml +++ b/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml @@ -129,13 +129,12 @@ metadata: categories: Developer Tools, Monitoring, Logging & Tracing, Security certified: "false" containerImage: icr.io/cpopen/odlm:latest - createdAt: "2023-10-31T21:57:26Z" - description: The Operand Deployment Lifecycle Manager provides a Kubernetes CRD-based - API to manage the lifecycle of operands. + createdAt: "2023-11-02T22:53:11Z" + description: The Operand Deployment Lifecycle Manager provides a Kubernetes CRD-based API to manage the lifecycle of operands. nss.operator.ibm.com/managed-operators: ibm-odlm olm.skipRange: '>=1.2.0 <4.2.1' operators.openshift.io/infrastructure-features: '["disconnected"]' - operators.operatorframework.io/builder: operator-sdk-v1.32.0 + operators.operatorframework.io/builder: operator-sdk-v1.29.0 operators.operatorframework.io/project_layout: go.kubebuilder.io/v3 repository: https://github.com/IBM/operand-deployment-lifecycle-manager support: IBM @@ -150,72 +149,72 @@ spec: apiservicedefinitions: {} customresourcedefinitions: owned: - - description: OperandBindInfo is the Schema for the operandbindinfoes API. - displayName: OperandBindInfo - kind: OperandBindInfo - name: operandbindinfos.operator.ibm.com - statusDescriptors: - - description: Phase describes the overall phase of OperandBindInfo. - displayName: Phase - path: phase - x-descriptors: - - urn:alm:descriptor:io.kubernetes.phase - version: v1alpha1 - - description: OperandConfig is the Schema for the operandconfigs API. - displayName: OperandConfig - kind: OperandConfig - name: operandconfigs.operator.ibm.com - specDescriptors: - - description: Services is a list of configuration of service. - displayName: Operand Services Config List - path: services - statusDescriptors: - - description: Phase describes the overall phase of operands in the OperandConfig. - displayName: Phase - path: phase - x-descriptors: - - urn:alm:descriptor:io.kubernetes.phase - version: v1alpha1 - - description: OperandRegistry is the Schema for the operandregistries API. - displayName: OperandRegistry - kind: OperandRegistry - name: operandregistries.operator.ibm.com - specDescriptors: - - description: Operators is a list of operator OLM definition. - displayName: Operators Registry List - path: operators - statusDescriptors: - - description: Conditions represents the current state of the Request Service. - displayName: Conditions - path: conditions - x-descriptors: - - urn:alm:descriptor:io.kubernetes.conditions - - description: Phase describes the overall phase of operators in the OperandRegistry. - displayName: Phase - path: phase - x-descriptors: - - urn:alm:descriptor:io.kubernetes.phase - version: v1alpha1 - - description: OperandRequest is the Schema for the operandrequests API. - displayName: OperandRequest - kind: OperandRequest - name: operandrequests.operator.ibm.com - specDescriptors: - - description: Requests defines a list of operands installation. - displayName: Operators Request List - path: requests - statusDescriptors: - - description: Conditions represents the current state of the Request Service. - displayName: Conditions - path: conditions - x-descriptors: - - urn:alm:descriptor:io.kubernetes.conditions - - description: Phase is the cluster running phase. - displayName: Phase - path: phase - x-descriptors: - - urn:alm:descriptor:io.kubernetes.phase - version: v1alpha1 + - description: OperandBindInfo is the Schema for the operandbindinfoes API. Documentation For additional details regarding install parameters check https://ibm.biz/icpfs39install. License By installing this product you accept the license terms https://ibm.biz/icpfs39license + displayName: OperandBindInfo + kind: OperandBindInfo + name: operandbindinfos.operator.ibm.com + statusDescriptors: + - description: Phase describes the overall phase of OperandBindInfo. + displayName: Phase + path: phase + x-descriptors: + - urn:alm:descriptor:io.kubernetes.phase + version: v1alpha1 + - description: OperandConfig is the Schema for the operandconfigs API. Documentation For additional details regarding install parameters check https://ibm.biz/icpfs39install. License By installing this product you accept the license terms https://ibm.biz/icpfs39license + displayName: OperandConfig + kind: OperandConfig + name: operandconfigs.operator.ibm.com + specDescriptors: + - description: Services is a list of configuration of service. + displayName: Operand Services Config List + path: services + statusDescriptors: + - description: Phase describes the overall phase of operands in the OperandConfig. + displayName: Phase + path: phase + x-descriptors: + - urn:alm:descriptor:io.kubernetes.phase + version: v1alpha1 + - description: OperandRegistry is the Schema for the operandregistries API. Documentation For additional details regarding install parameters check https://ibm.biz/icpfs39install. License By installing this product you accept the license terms https://ibm.biz/icpfs39license + displayName: OperandRegistry + kind: OperandRegistry + name: operandregistries.operator.ibm.com + specDescriptors: + - description: Operators is a list of operator OLM definition. + displayName: Operators Registry List + path: operators + statusDescriptors: + - description: Conditions represents the current state of the Request Service. + displayName: Conditions + path: conditions + x-descriptors: + - urn:alm:descriptor:io.kubernetes.conditions + - description: Phase describes the overall phase of operators in the OperandRegistry. + displayName: Phase + path: phase + x-descriptors: + - urn:alm:descriptor:io.kubernetes.phase + version: v1alpha1 + - description: OperandRequest is the Schema for the operandrequests API. Documentation For additional details regarding install parameters check https://ibm.biz/icpfs39install. License By installing this product you accept the license terms https://ibm.biz/icpfs39license + displayName: OperandRequest + kind: OperandRequest + name: operandrequests.operator.ibm.com + specDescriptors: + - description: Requests defines a list of operands installation. + displayName: Operators Request List + path: requests + statusDescriptors: + - description: Conditions represents the current state of the Request Service. + displayName: Conditions + path: conditions + x-descriptors: + - urn:alm:descriptor:io.kubernetes.conditions + - description: Phase is the cluster running phase. + displayName: Phase + path: phase + x-descriptors: + - urn:alm:descriptor:io.kubernetes.phase + version: v1alpha1 description: |- # Introduction @@ -558,231 +557,231 @@ spec: The Operand Deployment Lifecycle Manager supports running under the OpenShift Container Platform default restricted security context constraints. displayName: Operand Deployment Lifecycle Manager icon: - - base64data: iVBORw0KGgoAAAANSUhEUgAAAK8AAACvCAMAAAC8TH5HAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAB1UExURQAAAJGS77CC4pCS75yM64uV8pSQ7puA85OV87OB4auF5Hyd+H2c936b9n6b94Ca9n+b9n+b9n+b9qOJ56SI55yM6qSI536b96aH5q2D45mN64OZ9ZWQ7oyU8XWg+6uG5oqg/p6L6m+k/ZuY+3mr/6qQ9LqM80D8C0oAAAAbdFJOUwA67R4KKxMBBP6ak6vZgVtJxG5ot+hQ7YDVkwC2C58AAAuSSURBVHja7ZyJerK8EoCDCSTKjoiIS13of/+XeGYm4NLKrvj1OYxt7aa8TiazJZGxSSaZZJJJJvmcSCn/Eq7Cz79DLJk0rb+kXdM9nz0m/4p2mZufz3lAZvEn1HsGye2J9128h7/Gezj8Nd7D3+I9/xu8SjWHrS76bfN8A+NsYxjowCvbPN+QSGB6kWi6QHteyQLPfx+wYsH2eHSthgu05lXMy/PceRcwxtnjdnts4mjLq5hBceVdcVsya71FMeov0JIXMuQwR+DoXX5EMgf0uz2GrDYbb8mrmE+4Z/NdvDCApN+jX3uFdrySqfW70wzFbFLwWtVNkXa8ONlIvfx9Dk0xSyvYq0NpxasYJ9o8emcUVCw6EjGvuUpLXgfVm9cP1fAZp1yyCKeGBf8pB96g9jUZ57c6s1vIIAUfjXqY9eFg1yiuKJnOECzeW+TJm0+rxRGGWfcP7/dld8bZwqcp/dJqIs9hrJIJ/JD2abV5j1StfJn1/pofo/Kx0ae1KfAO7/Vld7anfVpf28M5kKPDc9kYLRW4RDhIwYV/PozVUAF39Qre3BmrvsM04nisjHHyJlUjZEOefuBj8UIA81zHfGJ84BYeHAP9LKseP1r5LNnvOlHeXJgqRZbUPzT97PHvBVb48VCX09W54du2u3ZJwjD0It/gqmCue/yoolm4b7tQjmohh7cGAWzHC8x/qOFOZmBG4bbERDkQrVYyiGP7iPwPLGrgsAofYbePonEJ2CHxAuvjxEjLvfUj7J1BaP0irY3i888SA63l3alWgwKjbXueZztOSBoucOE33huIZdsWHChXRds72O069PyHhSEBDiOynbAEBiGreCGJKoa5zT8GVBzt4QNgXc+wbq4YvW+hSMkDYNa4EYihWqlYtmouSsYTo4XvgWezHKDcI+7xuPbMMp7JH0GEfhZGRMDIG5FRtLG1IGCNvTp/d9nFZhMx/DXYH/cgSBv6SscM+Tyf0P450Lw+iCmbOGAMonOeO/XlMyTjgAsfmWAN9Y53RFy0hDAovXBDSBFBVAIHDdUJ2lre3J6AVG9Hcln5NQyKCUcrd390g5/BtjpNR2KNGwTVpRDSmk6et6jwCv0ScVhpxopxl3DBIjzVjrYk5gVuEPAaw7UP+aFV+0ex5Aq8y/hTYhiE/UXjhibrlBUisUm8hmHwqujuH3IqQLA/0dT+Af8Q34hT8du3QXlR4nrdkxhJ0554nwAXhpvj+hLUo2u/zWoJM1aXy70ZP8e97APWJ+WGbN1AXNP8tedAasM96PLu4Ik2jhpHZLkqgdGM5TNjuKzNnhkiUmneH8CSCe9wpXV429HDlCu7GcV9JwemWoEbWr3rGZx2iMs5F4+T3S1p89DoYGvkUeLCKC67m+uBsVwVuGpI+QVohGtZ6rHrU+Cu/UaP/ps4KY3iWhlipwNwd4Arh1WLCIy4lpA/2yiF4XZ9ehgMuaRgt7r6FMWiC9DuL64YWtyCrQKuEOLe1iJsG+eO2W8eo+POdrvVtdULrgG0Dbg76xW1uCDcm5GCguzDAeNlz0qPqgfzGunJeAl4aOug6KYQ7l2WhI7DZEMqZ7L5a1uBZWTQF3/QVHvmUosOBX0ZVkbfkgNtDYCbDcDVsIKbQYCJBCY/gak7FHQh+bqiX7LwsnuYfr1gqUTCUsPWgsWdF1H2I1/ZoYBMSLs3o3/blyke+FRiEPE9c1Huq9dpV60GWQNmvybSIrCnee0SGIlDJzJfVzwrttTq7bfkUNCSzV71a19pScNOGHrmi9pWV/Uue6lXYpEcBFfgslSOPG0MBTASc/YK3455PEqvyYY5r0G4AeH6gWHqSCyVxQ2s9ksJw9B/ATBYVUy8fdRL6ZhhlPo1HpIyHelM38OmCuA6oWvzwTah69DTbiW6qxdMCdPdAIGLbrC8lyIimxHRgrhQcA+cdoqluxXc0u7qhcTGNBAYeKkB9CTASfJjVuTo7mvoRsO676Ci+LRanVbd91YgLggp2GI1/kpRq7MAXnuDjBhC8Qpkl3UepwIXgblseDQq2XBcUK8bru0hGgbni7ynzrMNs1xOuJDmNQMAsfAI2B0CjOaAvKuuK2aES8C8XU8Sn98H9SKw12/SwfwVzNyArOLOL1lxEpO37/lKFujlpW3UfTSZwpxaQCkXb+JVd3OAAg1xrQ4vFGzC0MDrbuvLSGtRiSVYuonjeNU5MxMWAVudZzct1azdLmUXzGZLV7BCySxG6Zrq4MsFXqv79A7WiLu1OwwLFgElr7VA3LQjLtZnCCx7+KNo7a4BuG3lhRmKWXQ0LME40Gbxsqt6BQH3arExZ+viCl67Ib1rGHFLQPIQL7JFnHTjRfUCb68whR1mXM3dttpjcWvIAS6uNCRxlmVxxypeCVJw3wjl0/LzmrfaVG4kBgFT6ge57wJ4M7OTfmlNS4j+McpB4G2rTfBGkhAwp2UcWfB2cw/FFogBKQvxrhtTLMnMZYJiFG4eeLM0zVLRg3dIzmJvAbfRgiXjS81rXfeBLIE3TTuVQneZeH8Fb4HXFQ0rcGKJcsNFXsRdduYdViSQBQNy0LCilaSIu+R3TeqP8KKLQAXXzjgw3hR5l3erFvoldOOVr9Cv5eK6v1tzXch0UZfLNGEPvGQi3fU7tMi1m45PgCtb4Nin974Lftmd9yUtJZ94q/NgUG9KvA9rWOjgwKATMTqv3mpcbcDgQxaLRbpYyp+89/5tLMF98GTAVZsP4LfpAuXRYnALBwof+0AxejR0EVVpO4ARbvpz96D1GV7FvNoJB4lNDLiQOKofIQSTicQcnzeq5ZUsxTpi8ctQJeVrJmNj8wbEWxHhYNxjXff8UiT1vww1Oq9R59Dgz1gGb5Kff5a62jA/4tD222Ml75J4zd+8uglmfcQB76s2nktsM2w2z8p2yamWG90eTNrd9ly/ALnAtlP8LO5a1FdSo9sv7h3cVvGqGHkXT9Sr+3ZcjO4faNNYUMErkHf2tIeuqBNhjc0bHXEDoVHBa20qeRm1liw1Mq9H29z68Ard+hs7f0BzWD/3S8g7q+TV3RohR8VVLqq34pgR2G8NL9O8alx3Rrvy7Cr3q2LkXTyPClrBY55JgPqCthFGVbxsgbxxRd2jxKCGTS/zpelW0beD8pB4NxVhVw7t2HSvj0m9lfUx5A/zzWw2q0yPHzYHjWEOuDXvWLnhAtL1Gah3XrWsImkL/WjAkoX7au+r00bQ7my+qFr4ekETpFvyUGsOKOAgZrNNZaE2InCx9XF/qVmFQwNGBVevs42n31K9+5oqFxw0GURc22UayXjBenHrY1Z7UJ/FpOCkRsFjWe+SNsLuef2xCm0QMfvwe60pxnGf5v7iNTR/xWZWb8GjWcOFgBtK3FLBM+uTCpatd5aigue1Pngs4yVcp8VphmT+YYuQGIhxm/Fu37w+j0mPBk4+BIy4ett8q52lGJTneJsbHwHGwx/FQYp2Q6wtogCWH8DNLtdt0S1Pi6RICx8JG1nFCluOV9yWLgrrjAI4HfVQNtYu5emw9ri0EyZGWpCNORYxvVuAGZeHgLIuEVZB5UnAqGLryfsLvDx31Gfa6czSSW+D7XRFVZgEyizlRfEm3yJFSaiM+HQ5Ee5ll3SNVgCczkvi+SJ5c+PMMtIV0BLu6RL32P8Lry8pcVHJcZoYlniDcCNJ49Xp+/uk5QK20PP0kLWYP8qsg2zuvl/VyAlQS1bQ7SnjfQ814O7WeF4jX/P/5l//fT2V77svePeNd/gFNam/FN/eZPd9io0B/ojOwMWVsA8/wO1RZvc/nOgTbqfi7okAfDbUe+KDjcVsPq9X81eJPK/g/So476kfWUG1S6vjmcIqYpGkGwT7r4t8FfffdIP7ajmdNlnC2Qto2fWNtixjudRr4a+VLF0uTa4vJF8XKuXbg/Hr33TjffKn3gp/kkkmmWSSSSaZZJJJJplkkkkmmWSS/yf5H6HANgUotAMHAAAAAElFTkSuQmCC - mediatype: image/png + - base64data: iVBORw0KGgoAAAANSUhEUgAAAK8AAACvCAMAAAC8TH5HAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAB1UExURQAAAJGS77CC4pCS75yM64uV8pSQ7puA85OV87OB4auF5Hyd+H2c936b9n6b94Ca9n+b9n+b9n+b9qOJ56SI55yM6qSI536b96aH5q2D45mN64OZ9ZWQ7oyU8XWg+6uG5oqg/p6L6m+k/ZuY+3mr/6qQ9LqM80D8C0oAAAAbdFJOUwA67R4KKxMBBP6ak6vZgVtJxG5ot+hQ7YDVkwC2C58AAAuSSURBVHja7ZyJerK8EoCDCSTKjoiIS13of/+XeGYm4NLKrvj1OYxt7aa8TiazJZGxSSaZZJJJJvmcSCn/Eq7Cz79DLJk0rb+kXdM9nz0m/4p2mZufz3lAZvEn1HsGye2J9128h7/Gezj8Nd7D3+I9/xu8SjWHrS76bfN8A+NsYxjowCvbPN+QSGB6kWi6QHteyQLPfx+wYsH2eHSthgu05lXMy/PceRcwxtnjdnts4mjLq5hBceVdcVsya71FMeov0JIXMuQwR+DoXX5EMgf0uz2GrDYbb8mrmE+4Z/NdvDCApN+jX3uFdrySqfW70wzFbFLwWtVNkXa8ONlIvfx9Dk0xSyvYq0NpxasYJ9o8emcUVCw6EjGvuUpLXgfVm9cP1fAZp1yyCKeGBf8pB96g9jUZ57c6s1vIIAUfjXqY9eFg1yiuKJnOECzeW+TJm0+rxRGGWfcP7/dld8bZwqcp/dJqIs9hrJIJ/JD2abV5j1StfJn1/pofo/Kx0ae1KfAO7/Vld7anfVpf28M5kKPDc9kYLRW4RDhIwYV/PozVUAF39Qre3BmrvsM04nisjHHyJlUjZEOefuBj8UIA81zHfGJ84BYeHAP9LKseP1r5LNnvOlHeXJgqRZbUPzT97PHvBVb48VCX09W54du2u3ZJwjD0It/gqmCue/yoolm4b7tQjmohh7cGAWzHC8x/qOFOZmBG4bbERDkQrVYyiGP7iPwPLGrgsAofYbePonEJ2CHxAuvjxEjLvfUj7J1BaP0irY3i888SA63l3alWgwKjbXueZztOSBoucOE33huIZdsWHChXRds72O069PyHhSEBDiOynbAEBiGreCGJKoa5zT8GVBzt4QNgXc+wbq4YvW+hSMkDYNa4EYihWqlYtmouSsYTo4XvgWezHKDcI+7xuPbMMp7JH0GEfhZGRMDIG5FRtLG1IGCNvTp/d9nFZhMx/DXYH/cgSBv6SscM+Tyf0P450Lw+iCmbOGAMonOeO/XlMyTjgAsfmWAN9Y53RFy0hDAovXBDSBFBVAIHDdUJ2lre3J6AVG9Hcln5NQyKCUcrd390g5/BtjpNR2KNGwTVpRDSmk6et6jwCv0ScVhpxopxl3DBIjzVjrYk5gVuEPAaw7UP+aFV+0ex5Aq8y/hTYhiE/UXjhibrlBUisUm8hmHwqujuH3IqQLA/0dT+Af8Q34hT8du3QXlR4nrdkxhJ0554nwAXhpvj+hLUo2u/zWoJM1aXy70ZP8e97APWJ+WGbN1AXNP8tedAasM96PLu4Ik2jhpHZLkqgdGM5TNjuKzNnhkiUmneH8CSCe9wpXV429HDlCu7GcV9JwemWoEbWr3rGZx2iMs5F4+T3S1p89DoYGvkUeLCKC67m+uBsVwVuGpI+QVohGtZ6rHrU+Cu/UaP/ps4KY3iWhlipwNwd4Arh1WLCIy4lpA/2yiF4XZ9ehgMuaRgt7r6FMWiC9DuL64YWtyCrQKuEOLe1iJsG+eO2W8eo+POdrvVtdULrgG0Dbg76xW1uCDcm5GCguzDAeNlz0qPqgfzGunJeAl4aOug6KYQ7l2WhI7DZEMqZ7L5a1uBZWTQF3/QVHvmUosOBX0ZVkbfkgNtDYCbDcDVsIKbQYCJBCY/gak7FHQh+bqiX7LwsnuYfr1gqUTCUsPWgsWdF1H2I1/ZoYBMSLs3o3/blyke+FRiEPE9c1Huq9dpV60GWQNmvybSIrCnee0SGIlDJzJfVzwrttTq7bfkUNCSzV71a19pScNOGHrmi9pWV/Uue6lXYpEcBFfgslSOPG0MBTASc/YK3455PEqvyYY5r0G4AeH6gWHqSCyVxQ2s9ksJw9B/ATBYVUy8fdRL6ZhhlPo1HpIyHelM38OmCuA6oWvzwTah69DTbiW6qxdMCdPdAIGLbrC8lyIimxHRgrhQcA+cdoqluxXc0u7qhcTGNBAYeKkB9CTASfJjVuTo7mvoRsO676Ci+LRanVbd91YgLggp2GI1/kpRq7MAXnuDjBhC8Qpkl3UepwIXgblseDQq2XBcUK8bru0hGgbni7ynzrMNs1xOuJDmNQMAsfAI2B0CjOaAvKuuK2aES8C8XU8Sn98H9SKw12/SwfwVzNyArOLOL1lxEpO37/lKFujlpW3UfTSZwpxaQCkXb+JVd3OAAg1xrQ4vFGzC0MDrbuvLSGtRiSVYuonjeNU5MxMWAVudZzct1azdLmUXzGZLV7BCySxG6Zrq4MsFXqv79A7WiLu1OwwLFgElr7VA3LQjLtZnCCx7+KNo7a4BuG3lhRmKWXQ0LME40Gbxsqt6BQH3arExZ+viCl67Ib1rGHFLQPIQL7JFnHTjRfUCb68whR1mXM3dttpjcWvIAS6uNCRxlmVxxypeCVJw3wjl0/LzmrfaVG4kBgFT6ge57wJ4M7OTfmlNS4j+McpB4G2rTfBGkhAwp2UcWfB2cw/FFogBKQvxrhtTLMnMZYJiFG4eeLM0zVLRg3dIzmJvAbfRgiXjS81rXfeBLIE3TTuVQneZeH8Fb4HXFQ0rcGKJcsNFXsRdduYdViSQBQNy0LCilaSIu+R3TeqP8KKLQAXXzjgw3hR5l3erFvoldOOVr9Cv5eK6v1tzXch0UZfLNGEPvGQi3fU7tMi1m45PgCtb4Nin974Lftmd9yUtJZ94q/NgUG9KvA9rWOjgwKATMTqv3mpcbcDgQxaLRbpYyp+89/5tLMF98GTAVZsP4LfpAuXRYnALBwof+0AxejR0EVVpO4ARbvpz96D1GV7FvNoJB4lNDLiQOKofIQSTicQcnzeq5ZUsxTpi8ctQJeVrJmNj8wbEWxHhYNxjXff8UiT1vww1Oq9R59Dgz1gGb5Kff5a62jA/4tD222Ml75J4zd+8uglmfcQB76s2nktsM2w2z8p2yamWG90eTNrd9ly/ALnAtlP8LO5a1FdSo9sv7h3cVvGqGHkXT9Sr+3ZcjO4faNNYUMErkHf2tIeuqBNhjc0bHXEDoVHBa20qeRm1liw1Mq9H29z68Ard+hs7f0BzWD/3S8g7q+TV3RohR8VVLqq34pgR2G8NL9O8alx3Rrvy7Cr3q2LkXTyPClrBY55JgPqCthFGVbxsgbxxRd2jxKCGTS/zpelW0beD8pB4NxVhVw7t2HSvj0m9lfUx5A/zzWw2q0yPHzYHjWEOuDXvWLnhAtL1Gah3XrWsImkL/WjAkoX7au+r00bQ7my+qFr4ekETpFvyUGsOKOAgZrNNZaE2InCx9XF/qVmFQwNGBVevs42n31K9+5oqFxw0GURc22UayXjBenHrY1Z7UJ/FpOCkRsFjWe+SNsLuef2xCm0QMfvwe60pxnGf5v7iNTR/xWZWb8GjWcOFgBtK3FLBM+uTCpatd5aigue1Pngs4yVcp8VphmT+YYuQGIhxm/Fu37w+j0mPBk4+BIy4ett8q52lGJTneJsbHwHGwx/FQYp2Q6wtogCWH8DNLtdt0S1Pi6RICx8JG1nFCluOV9yWLgrrjAI4HfVQNtYu5emw9ri0EyZGWpCNORYxvVuAGZeHgLIuEVZB5UnAqGLryfsLvDx31Gfa6czSSW+D7XRFVZgEyizlRfEm3yJFSaiM+HQ5Ee5ll3SNVgCczkvi+SJ5c+PMMtIV0BLu6RL32P8Lry8pcVHJcZoYlniDcCNJ49Xp+/uk5QK20PP0kLWYP8qsg2zuvl/VyAlQS1bQ7SnjfQ814O7WeF4jX/P/5l//fT2V77svePeNd/gFNam/FN/eZPd9io0B/ojOwMWVsA8/wO1RZvc/nOgTbqfi7okAfDbUe+KDjcVsPq9X81eJPK/g/So476kfWUG1S6vjmcIqYpGkGwT7r4t8FfffdIP7ajmdNlnC2Qto2fWNtixjudRr4a+VLF0uTa4vJF8XKuXbg/Hr33TjffKn3gp/kkkmmWSSSSaZZJJJJplkkkkmmWSS/yf5H6HANgUotAMHAAAAAElFTkSuQmCC + mediatype: image/png install: spec: clusterPermissions: - - rules: - - apiGroups: - - operators.coreos.com - resources: - - catalogsources - verbs: - - get - serviceAccountName: operand-deployment-lifecycle-manager + - rules: + - apiGroups: + - operators.coreos.com + resources: + - catalogsources + verbs: + - get + serviceAccountName: operand-deployment-lifecycle-manager deployments: - - label: - app.kubernetes.io/instance: operand-deployment-lifecycle-manager - app.kubernetes.io/managed-by: operand-deployment-lifecycle-manager - app.kubernetes.io/name: operand-deployment-lifecycle-manager - productName: IBM_Cloud_Platform_Common_Services - name: operand-deployment-lifecycle-manager - spec: - replicas: 1 - selector: - matchLabels: - name: operand-deployment-lifecycle-manager - strategy: {} - template: - metadata: - annotations: - productID: 068a62892a1e4db39641342e592daa25 - productMetric: FREE - productName: IBM Cloud Platform Common Services - labels: - app.kubernetes.io/instance: operand-deployment-lifecycle-manager - app.kubernetes.io/managed-by: operand-deployment-lifecycle-manager - app.kubernetes.io/name: operand-deployment-lifecycle-manager - intent: projected-odlm + - label: + app.kubernetes.io/instance: operand-deployment-lifecycle-manager + app.kubernetes.io/managed-by: operand-deployment-lifecycle-manager + app.kubernetes.io/name: operand-deployment-lifecycle-manager + productName: IBM_Cloud_Platform_Common_Services + name: operand-deployment-lifecycle-manager + spec: + replicas: 1 + selector: + matchLabels: name: operand-deployment-lifecycle-manager - productName: IBM_Cloud_Platform_Common_Services - spec: - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/arch - operator: In - values: - - amd64 - - ppc64le - - s390x - containers: - - args: - - -v=1 - command: - - /manager - env: - - name: OPERATOR_NAMESPACE - valueFrom: - fieldRef: - apiVersion: v1 - fieldPath: metadata.namespace - - name: WATCH_NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.annotations['olm.targetNamespaces'] - image: icr.io/cpopen/odlm:latest - imagePullPolicy: IfNotPresent - livenessProbe: - failureThreshold: 10 - httpGet: - path: /readyz - port: 8081 - initialDelaySeconds: 120 - periodSeconds: 60 - timeoutSeconds: 10 - name: manager - readinessProbe: - failureThreshold: 10 - httpGet: - path: /healthz - port: 8081 - initialDelaySeconds: 5 - periodSeconds: 20 - timeoutSeconds: 3 - resources: - limits: - cpu: 500m - memory: 512Mi - requests: - cpu: 200m - ephemeral-storage: 256Mi - memory: 200Mi - securityContext: - allowPrivilegeEscalation: false - capabilities: - drop: - - ALL - privileged: false - readOnlyRootFilesystem: true - runAsNonRoot: true - serviceAccount: operand-deployment-lifecycle-manager - serviceAccountName: operand-deployment-lifecycle-manager - terminationGracePeriodSeconds: 10 + strategy: {} + template: + metadata: + annotations: + productID: 068a62892a1e4db39641342e592daa25 + productMetric: FREE + productName: IBM Cloud Platform Common Services + labels: + app.kubernetes.io/instance: operand-deployment-lifecycle-manager + app.kubernetes.io/managed-by: operand-deployment-lifecycle-manager + app.kubernetes.io/name: operand-deployment-lifecycle-manager + intent: projected-odlm + name: operand-deployment-lifecycle-manager + productName: IBM_Cloud_Platform_Common_Services + spec: + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: kubernetes.io/arch + operator: In + values: + - amd64 + - ppc64le + - s390x + containers: + - args: + - -v=1 + command: + - /manager + env: + - name: OPERATOR_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: WATCH_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.annotations['olm.targetNamespaces'] + image: icr.io/cpopen/odlm:latest + imagePullPolicy: IfNotPresent + livenessProbe: + failureThreshold: 10 + httpGet: + path: /readyz + port: 8081 + initialDelaySeconds: 120 + periodSeconds: 60 + timeoutSeconds: 10 + name: manager + readinessProbe: + failureThreshold: 10 + httpGet: + path: /healthz + port: 8081 + initialDelaySeconds: 5 + periodSeconds: 20 + timeoutSeconds: 3 + resources: + limits: + cpu: 500m + memory: 512Mi + requests: + cpu: 200m + ephemeral-storage: 256Mi + memory: 200Mi + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + privileged: false + readOnlyRootFilesystem: true + runAsNonRoot: true + serviceAccount: operand-deployment-lifecycle-manager + serviceAccountName: operand-deployment-lifecycle-manager + terminationGracePeriodSeconds: 10 permissions: - - rules: - - apiGroups: - - '*' - resources: - - '*' - verbs: - - create - - delete - - get - - list - - patch - - update - - watch - - apiGroups: - - operator.ibm.com - resources: - - operandconfigs - - operandconfigs/status - - operandconfigs/finalizers - - operandregistries - - operandregistries/status - - operandregistries/finalizers - - operandrequests - - operandrequests/status - - operandrequests/finalizers - - operandbindinfos - - operandbindinfos/status - - operandbindinfos/finalizers - verbs: - - create - - delete - - get - - list - - patch - - update - - watch - - apiGroups: - - "" - resources: - - configmaps - - secrets - - services - - namespaces - verbs: - - create - - delete - - get - - list - - patch - - update - - watch - - apiGroups: - - route.openshift.io - resources: - - routes - verbs: - - create - - delete - - get - - list - - patch - - update - - watch - - apiGroups: - - operators.coreos.com - resources: - - operatorgroups - - installplans - verbs: - - create - - delete - - get - - list - - patch - - update - - watch - - apiGroups: - - k8s.keycloak.org - resources: - - keycloaks - verbs: - - create - - delete - - get - - list - - patch - - update - - watch - - apiGroups: - - packages.operators.coreos.com - resources: - - packagemanifests - verbs: - - get - - list - - patch - - update - - watch - serviceAccountName: operand-deployment-lifecycle-manager + - rules: + - apiGroups: + - '*' + resources: + - '*' + verbs: + - create + - delete + - get + - list + - patch + - update + - watch + - apiGroups: + - operator.ibm.com + resources: + - operandconfigs + - operandconfigs/status + - operandconfigs/finalizers + - operandregistries + - operandregistries/status + - operandregistries/finalizers + - operandrequests + - operandrequests/status + - operandrequests/finalizers + - operandbindinfos + - operandbindinfos/status + - operandbindinfos/finalizers + verbs: + - create + - delete + - get + - list + - patch + - update + - watch + - apiGroups: + - "" + resources: + - configmaps + - secrets + - services + - namespaces + verbs: + - create + - delete + - get + - list + - patch + - update + - watch + - apiGroups: + - route.openshift.io + resources: + - routes + verbs: + - create + - delete + - get + - list + - patch + - update + - watch + - apiGroups: + - operators.coreos.com + resources: + - operatorgroups + - installplans + verbs: + - create + - delete + - get + - list + - patch + - update + - watch + - apiGroups: + - k8s.keycloak.org + resources: + - keycloaks + verbs: + - create + - delete + - get + - list + - patch + - update + - watch + - apiGroups: + - packages.operators.coreos.com + resources: + - packagemanifests + verbs: + - get + - list + - patch + - update + - watch + serviceAccountName: operand-deployment-lifecycle-manager strategy: deployment installModes: - - supported: true - type: OwnNamespace - - supported: true - type: SingleNamespace - - supported: true - type: MultiNamespace - - supported: true - type: AllNamespaces + - supported: true + type: OwnNamespace + - supported: true + type: SingleNamespace + - supported: true + type: MultiNamespace + - supported: true + type: AllNamespaces keywords: - - IBM - - Cloud + - IBM + - Cloud labels: name: operand-deployment-lifecycle-manager links: - - name: IBM Operand Deployment Lifecycle Manager Project - url: https://github.com/IBM/operand-deployment-lifecycle-manager + - name: IBM Operand Deployment Lifecycle Manager Project + url: https://github.com/IBM/operand-deployment-lifecycle-manager maintainers: - - email: support@ibm.com - name: IBM Support + - email: support@ibm.com + name: IBM Support maturity: stable minKubeVersion: 1.19.0 provider: diff --git a/bundle/manifests/operator.ibm.com_operandbindinfos.yaml b/bundle/manifests/operator.ibm.com_operandbindinfos.yaml index 5bc28cb6..822fc474 100644 --- a/bundle/manifests/operator.ibm.com_operandbindinfos.yaml +++ b/bundle/manifests/operator.ibm.com_operandbindinfos.yaml @@ -53,13 +53,33 @@ spec: properties: bindings: additionalProperties: - description: SecretConfigmap is a pair of Secret and/or Configmap. + description: Bindable is a Kubernetes resources to be shared from + one namespace to another. List of supported resources are Secrets, + Configmaps, Services, and Routes. Secrets and Configmaps will + be copied such that a new Secret/Configmap with exactly the same + data will be created in the target namespace. Services and Routes + data will be copied into a configmap in the target namespace. properties: configmap: description: The configmap identifies an existing configmap object. if it exists, the ODLM will share to the namespace of the OperandRequest. type: string + route: + description: Route data will shared by copying it into a configmap + which is then created in the target namespace + properties: + data: + additionalProperties: + type: string + description: Data is a key-value pair where the value is + a YAML path to a value in the OpenShift Route, e.g. .spec.host + or .spec.tls.termination + type: object + name: + description: Name is the name of the OpenShift Route resource + type: string + type: object secret: description: The secret identifies an existing secret. if it exists, the ODLM will share to the namespace of the OperandRequest. diff --git a/bundle/manifests/operator.ibm.com_operandrequests.yaml b/bundle/manifests/operator.ibm.com_operandrequests.yaml index 86bedad2..50fbab51 100644 --- a/bundle/manifests/operator.ibm.com_operandrequests.yaml +++ b/bundle/manifests/operator.ibm.com_operandrequests.yaml @@ -74,14 +74,37 @@ spec: type: string bindings: additionalProperties: - description: SecretConfigmap is a pair of Secret and/or - Configmap. + description: Bindable is a Kubernetes resources to be + shared from one namespace to another. List of supported + resources are Secrets, Configmaps, Services, and Routes. + Secrets and Configmaps will be copied such that a + new Secret/Configmap with exactly the same data will + be created in the target namespace. Services and Routes + data will be copied into a configmap in the target + namespace. properties: configmap: description: The configmap identifies an existing configmap object. if it exists, the ODLM will share to the namespace of the OperandRequest. type: string + route: + description: Route data will shared by copying it + into a configmap which is then created in the + target namespace + properties: + data: + additionalProperties: + type: string + description: Data is a key-value pair where + the value is a YAML path to a value in the + OpenShift Route, e.g. .spec.host or .spec.tls.termination + type: object + name: + description: Name is the name of the OpenShift + Route resource + type: string + type: object secret: description: The secret identifies an existing secret. if it exists, the ODLM will share to the namespace diff --git a/bundle/metadata/annotations.yaml b/bundle/metadata/annotations.yaml index 59d1fb06..55d60ed0 100644 --- a/bundle/metadata/annotations.yaml +++ b/bundle/metadata/annotations.yaml @@ -6,10 +6,9 @@ annotations: operators.operatorframework.io.bundle.package.v1: ibm-odlm operators.operatorframework.io.bundle.channels.v1: v4.2 operators.operatorframework.io.bundle.channel.default.v1: v4.2 - operators.operatorframework.io.metrics.builder: operator-sdk-v1.32.0 + operators.operatorframework.io.metrics.builder: operator-sdk-v1.29.0 operators.operatorframework.io.metrics.mediatype.v1: metrics+v1 operators.operatorframework.io.metrics.project_layout: go.kubebuilder.io/v3 - # Annotations for testing. operators.operatorframework.io.test.mediatype.v1: scorecard+v1 operators.operatorframework.io.test.config.v1: tests/scorecard/ diff --git a/config/crd/bases/operator.ibm.com_operandbindinfos.yaml b/config/crd/bases/operator.ibm.com_operandbindinfos.yaml index efceddf8..dc3deb6a 100644 --- a/config/crd/bases/operator.ibm.com_operandbindinfos.yaml +++ b/config/crd/bases/operator.ibm.com_operandbindinfos.yaml @@ -51,13 +51,33 @@ spec: properties: bindings: additionalProperties: - description: SecretConfigmap is a pair of Secret and/or Configmap. + description: Bindable is a Kubernetes resources to be shared from + one namespace to another. List of supported resources are Secrets, + Configmaps, Services, and Routes. Secrets and Configmaps will + be copied such that a new Secret/Configmap with exactly the same + data will be created in the target namespace. Services and Routes + data will be copied into a configmap in the target namespace. properties: configmap: description: The configmap identifies an existing configmap object. if it exists, the ODLM will share to the namespace of the OperandRequest. type: string + route: + description: Route data will shared by copying it into a configmap + which is then created in the target namespace + properties: + data: + additionalProperties: + type: string + description: Data is a key-value pair where the value is + a YAML path to a value in the OpenShift Route, e.g. .spec.host + or .spec.tls.termination + type: object + name: + description: Name is the name of the OpenShift Route resource + type: string + type: object secret: description: The secret identifies an existing secret. if it exists, the ODLM will share to the namespace of the OperandRequest. diff --git a/config/crd/bases/operator.ibm.com_operandrequests.yaml b/config/crd/bases/operator.ibm.com_operandrequests.yaml index 8fd2dd9d..c9ba0a55 100644 --- a/config/crd/bases/operator.ibm.com_operandrequests.yaml +++ b/config/crd/bases/operator.ibm.com_operandrequests.yaml @@ -72,14 +72,37 @@ spec: type: string bindings: additionalProperties: - description: SecretConfigmap is a pair of Secret and/or - Configmap. + description: Bindable is a Kubernetes resources to be + shared from one namespace to another. List of supported + resources are Secrets, Configmaps, Services, and Routes. + Secrets and Configmaps will be copied such that a + new Secret/Configmap with exactly the same data will + be created in the target namespace. Services and Routes + data will be copied into a configmap in the target + namespace. properties: configmap: description: The configmap identifies an existing configmap object. if it exists, the ODLM will share to the namespace of the OperandRequest. type: string + route: + description: Route data will shared by copying it + into a configmap which is then created in the + target namespace + properties: + data: + additionalProperties: + type: string + description: Data is a key-value pair where + the value is a YAML path to a value in the + OpenShift Route, e.g. .spec.host or .spec.tls.termination + type: object + name: + description: Name is the name of the OpenShift + Route resource + type: string + type: object secret: description: The secret identifies an existing secret. if it exists, the ODLM will share to the namespace diff --git a/config/e2e/crd/bases/operator.ibm.com_operandbindinfos.yaml b/config/e2e/crd/bases/operator.ibm.com_operandbindinfos.yaml index d2a048e7..78790021 100644 --- a/config/e2e/crd/bases/operator.ibm.com_operandbindinfos.yaml +++ b/config/e2e/crd/bases/operator.ibm.com_operandbindinfos.yaml @@ -51,18 +51,37 @@ spec: metadata: type: object spec: - x-kubernetes-preserve-unknown-fields: true description: OperandBindInfoSpec defines the desired state of OperandBindInfo. properties: bindings: additionalProperties: - description: SecretConfigmap is a pair of Secret and/or Configmap. + description: Bindable is a Kubernetes resources to be shared from + one namespace to another. List of supported resources are Secrets, + Configmaps, Services, and Routes. Secrets and Configmaps will + be copied such that a new Secret/Configmap with exactly the same + data will be created in the target namespace. Services and Routes + data will be copied into a configmap in the target namespace. properties: configmap: description: The configmap identifies an existing configmap object. if it exists, the ODLM will share to the namespace of the OperandRequest. type: string + route: + description: Route data will shared by copying it into a configmap + which is then created in the target namespace + properties: + data: + additionalProperties: + type: string + description: Data is a key-value pair where the value is + a YAML path to a value in the OpenShift Route, e.g. .spec.host + or .spec.tls.termination + type: object + name: + description: Name is the name of the OpenShift Route resource + type: string + type: object secret: description: The secret identifies an existing secret. if it exists, the ODLM will share to the namespace of the OperandRequest. @@ -90,6 +109,7 @@ spec: - operand - registry type: object + x-kubernetes-preserve-unknown-fields: true status: description: OperandBindInfoStatus defines the observed state of OperandBindInfo. properties: @@ -102,6 +122,7 @@ spec: type: string type: array type: object + x-kubernetes-preserve-unknown-fields: true type: object served: true storage: true diff --git a/config/e2e/crd/bases/operator.ibm.com_operandrequests.yaml b/config/e2e/crd/bases/operator.ibm.com_operandrequests.yaml index 4089c705..bf63d956 100644 --- a/config/e2e/crd/bases/operator.ibm.com_operandrequests.yaml +++ b/config/e2e/crd/bases/operator.ibm.com_operandrequests.yaml @@ -51,7 +51,6 @@ spec: metadata: type: object spec: - x-kubernetes-preserve-unknown-fields: true description: The OperandRequestSpec identifies one or more specific operands (from a specific Registry) that should actually be installed. properties: @@ -77,14 +76,37 @@ spec: type: string bindings: additionalProperties: - description: SecretConfigmap is a pair of Secret and/or - Configmap. + description: Bindable is a Kubernetes resources to be + shared from one namespace to another. List of supported + resources are Secrets, Configmaps, Services, and Routes. + Secrets and Configmaps will be copied such that a + new Secret/Configmap with exactly the same data will + be created in the target namespace. Services and Routes + data will be copied into a configmap in the target + namespace. properties: configmap: description: The configmap identifies an existing configmap object. if it exists, the ODLM will share to the namespace of the OperandRequest. type: string + route: + description: Route data will shared by copying it + into a configmap which is then created in the + target namespace + properties: + data: + additionalProperties: + type: string + description: Data is a key-value pair where + the value is a YAML path to a value in the + OpenShift Route, e.g. .spec.host or .spec.tls.termination + type: object + name: + description: Name is the name of the OpenShift + Route resource + type: string + type: object secret: description: The secret identifies an existing secret. if it exists, the ODLM will share to the namespace @@ -135,6 +157,7 @@ spec: required: - requests type: object + x-kubernetes-preserve-unknown-fields: true status: description: OperandRequestStatus defines the observed state of OperandRequest. properties: @@ -219,7 +242,55 @@ spec: phase: description: Phase is the cluster running phase. type: string + services: + description: Services reflect the status of operands beyond whether + they have been created + items: + properties: + namespace: + type: string + operatorName: + type: string + resources: + description: LastUpdateTime string `json:"lastTransitionTime,omitempty"` + items: + properties: + apiVersion: + type: string + kind: + type: string + managedResources: + description: Message string `json:"message,omitempty"` + items: + properties: + apiVersion: + type: string + kind: + type: string + namespace: + type: string + objectName: + type: string + status: + description: Type string `json:"type,omitempty"` + type: string + type: object + type: array + namespace: + type: string + objectName: + type: string + status: + type: string + type: object + type: array + status: + description: Type string `json:"type,omitempty"` + type: string + type: object + type: array type: object + x-kubernetes-preserve-unknown-fields: true type: object served: true storage: true diff --git a/controllers/operandbindinfo/operandbindinfo_controller.go b/controllers/operandbindinfo/operandbindinfo_controller.go index 9529f227..c4fab85d 100644 --- a/controllers/operandbindinfo/operandbindinfo_controller.go +++ b/controllers/operandbindinfo/operandbindinfo_controller.go @@ -24,17 +24,23 @@ import ( "strings" "time" + ocproute "github.com/openshift/api/route/v1" "github.com/pkg/errors" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" utilerrors "k8s.io/apimachinery/pkg/util/errors" + "k8s.io/client-go/discovery" + "k8s.io/client-go/rest" "k8s.io/klog" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/builder" "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/client/config" "sigs.k8s.io/controller-runtime/pkg/controller" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" "sigs.k8s.io/controller-runtime/pkg/event" @@ -53,12 +59,15 @@ import ( // Reconciler reconciles a OperandBindInfo object type Reconciler struct { *deploy.ODLMOperator + Config *rest.Config } var ( publicPrefix, _ = regexp.Compile(`^public(.*)$`) privatePrefix, _ = regexp.Compile(`^private(.*)$`) protectedPrefix, _ = regexp.Compile(`^protected(.*)$`) + routeGroupVersion = "route.openshift.io/v1" + isRouteAPI = false ) // Reconcile reads that state of the cluster for a OperandBindInfo object and makes changes based on the state read @@ -88,6 +97,12 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctrl.Re klog.V(1).Infof("Reconciling OperandBindInfo: %s", req.NamespacedName) + if isRouteAPI { + klog.Info("Route API enabled") + } else { + klog.Info("Route API disabled") + } + // If the finalizer is added, EnsureFinalizer() will return true. If the finalizer is already there, EnsureFinalizer() will return false if bindInfoInstance.EnsureFinalizer() { err := r.Patch(ctx, bindInfoInstance, client.MergeFrom(originalInstance)) @@ -194,6 +209,18 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctrl.Re continue } requeue = requeue || requeueCm + + if isRouteAPI { + // Copy Route data into configmap and share configmap + if binding.Route != nil { + requeueRoute, err := r.copyRoute(ctx, *binding.Route, "", operandNamespace, bindRequest.Namespace, key, bindInfoInstance, requestInstance) + if err != nil { + merr.Add(err) + continue + } + requeue = requeue || requeueRoute + } + } } } if len(merr.Errors) != 0 { @@ -400,6 +427,173 @@ func (r *Reconciler) copyConfigmap(ctx context.Context, sourceName, targetName, return false, nil } +func (r *Reconciler) copyRoute(ctx context.Context, route operatorv1alpha1.Route, targetName, sourceNs, targetNs, key string, + bindInfoInstance *operatorv1alpha1.OperandBindInfo, requestInstance *operatorv1alpha1.OperandRequest) (requeue bool, err error) { + if route.Name == "" || sourceNs == "" || targetNs == "" { + return false, nil + } + + if route.Name == targetName && sourceNs == targetNs { + return false, nil + } + + if targetName == "" { + if publicPrefix.MatchString(key) { + targetName = bindInfoInstance.Name + "-" + route.Name + } else { + return false, nil + } + } + + sourceRoute := &ocproute.Route{} + if err := r.Client.Get(ctx, types.NamespacedName{Name: route.Name, Namespace: sourceNs}, sourceRoute); err != nil { + if apierrors.IsNotFound(err) { + klog.V(3).Infof("Route %s/%s is not found", sourceNs, route.Name) + r.Recorder.Eventf(bindInfoInstance, corev1.EventTypeNormal, "NotFound", "No Route %s in the namespace %s", route.Name, sourceNs) + return true, nil + } + return false, errors.Wrapf(err, "failed to get Route %s/%s", sourceNs, route.Name) + } + // Create the ConfigMap to the OperandRequest namespace + labels := make(map[string]string) + // Copy from the original labels to the target labels + for k, v := range sourceRoute.Labels { + labels[k] = v + } + labels[bindInfoInstance.Namespace+"."+bindInfoInstance.Name+"/bindinfo"] = "true" + labels[constant.OpbiTypeLabel] = "copy" + + sanitizedData, err := sanitizeOdlmRouteData(route.Data, sourceRoute.Spec) + if err != nil { + return false, err + } + cmCopy := &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: targetName, + Namespace: targetNs, + Labels: labels, + }, + Data: sanitizedData, + } + // Set the OperandRequest as the controller of the configmap + if err := controllerutil.SetControllerReference(requestInstance, cmCopy, r.Scheme); err != nil { + return false, errors.Wrapf(err, "failed to set OperandRequest %s as the owner of ConfigMap %s", requestInstance.Name, route.Name) + } + + var podRefreshment bool + // Create the ConfigMap in the OperandRequest namespace + if err := r.Create(ctx, cmCopy); err != nil { + if apierrors.IsAlreadyExists(err) { + // If already exist, update the ConfigMap + existingCm := &corev1.ConfigMap{} + if err := r.Client.Get(ctx, types.NamespacedName{Namespace: targetNs, Name: targetName}, existingCm); err != nil { + return false, errors.Wrapf(err, "failed to get ConfigMap %s/%s", targetNs, targetName) + } + if needUpdate := util.CompareConfigMap(cmCopy, existingCm); needUpdate { + podRefreshment = true + if err := r.Update(ctx, cmCopy); err != nil { + return false, errors.Wrapf(err, "failed to update ConfigMap %s/%s", targetNs, route.Name) + } + } + } else { + return false, errors.Wrapf(err, "failed to create ConfigMap %s/%s", targetNs, route.Name) + } + } + + if podRefreshment { + if err := r.refreshPods(targetNs, targetName, "configmap"); err != nil { + return false, errors.Wrapf(err, "failed to refresh pods mounting ConfigMap %s/%s", targetNs, targetName) + } + } + + // Set the OperandBindInfo label for the ConfigMap + util.EnsureLabelsForRoute(sourceRoute, map[string]string{ + bindInfoInstance.Namespace + "." + bindInfoInstance.Name + "/bindinfo": "true", + constant.OpbiTypeLabel: "original", + }) + + // Update the operand Configmap + if err := r.Update(ctx, sourceRoute); err != nil { + return false, errors.Wrapf(err, "failed to update ConfigMap %s/%s", sourceRoute.Namespace, sourceRoute.Name) + } + klog.V(1).Infof("Route %s is copied from the namespace %s to the namespace %s", route.Name, sourceNs, targetNs) + + return false, nil +} + +// sanitizedOdlmRouteData takes a map, i.e. ODLM's Route.Data, and an OCP Route.Spec, +// and returns a map ready to be included into a ConfigMap's data. The ODLM's +// Route.Data is sanitized because the values are YAML path references +// in map because they correspond to YAML fields in a OCP Route. Ensures that: +// 1. the field actually exists, otherwise returns an error +// 2. extracts the value from the OCP Route's field, the value must be a basic +// type, which includes: int, float, bool, and strings. Anything else and +// an error is returned +func sanitizeOdlmRouteData(m map[string]string, route ocproute.RouteSpec) (map[string]string, error) { + sanitized := make(map[string]string, len(m)) + for k, v := range m { + fields := strings.Split(v, ".") + fields = fields[1:] + if fields[0] != "spec" { + return nil, errors.Errorf("Bindable Route.Data must only reference values from OCP Route.Spec") + } + fields = fields[1:] + + content, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&route) + if err != nil { + return nil, err + } + newUnstr := &unstructured.Unstructured{} + newUnstr.SetUnstructuredContent(content) + + trueValue, isExists, err := nestedBasicType(newUnstr.Object, fields...) + if err != nil { + return nil, err + } + if !isExists { + return nil, errors.Errorf("Bindable Route.Data references a field that does not exist: %s", v) + } + + sanitized[k] = trueValue + } + return sanitized, nil +} + +// nestedBasicType is a wrapper around the various unstructured.Nested methods +// used to extract values from nested fields. It takes the same arguments +// as the Nested methods and returns a string if some basic type value is found. +// Otherwise the bool and error values from the Nested functions will be +// returned. +// Basic types include: string, int64, float64, and bool +func nestedBasicType(obj map[string]interface{}, fields ...string) (string, bool, error) { + typeTest, isExists, err := unstructured.NestedFieldNoCopy(obj, fields...) + if err != nil { + return "", isExists, err + } + if !isExists { + return "", isExists, err + } + + switch fieldType := reflect.TypeOf(typeTest); fieldType.String() { + case "string": + return unstructured.NestedString(obj, fields...) + case "int", "int32", "int64": + var value int64 + value, isExists, err = unstructured.NestedInt64(obj, fields...) + return fmt.Sprintf("%d", value), isExists, err + case "float32", "float64": + var value float64 + value, isExists, err = unstructured.NestedFloat64(obj, fields...) + return fmt.Sprintf("%f", value), isExists, err + case "bool": + var value bool + value, isExists, err = unstructured.NestedBool(obj, fields...) + return fmt.Sprintf("%t", value), isExists, err + default: + return "", false, errors.Errorf("Path reference does not lead to an int, float, bool, or string: .spec.%s", strings.Join(fields, ".")) + } +} + func (r *Reconciler) cleanupCopies(ctx context.Context, bindInfoInstance *operatorv1alpha1.OperandBindInfo) error { secretList := &corev1.SecretList{} cmList := &corev1.ConfigMapList{} @@ -703,7 +897,7 @@ func (r *Reconciler) refreshPodsFromDaemonSet(ns, name, resourceType string) err // SetupWithManager adds OperandBindInfo controller to the manager. func (r *Reconciler) SetupWithManager(mgr ctrl.Manager) error { - cmSecretPredicates := predicate.Funcs{ + bindablePredicates := predicate.Funcs{ CreateFunc: func(e event.CreateEvent) bool { labels := e.Object.GetLabels() for labelKey, labelValue := range labels { @@ -748,18 +942,37 @@ func (r *Reconciler) SetupWithManager(mgr ctrl.Manager) error { MaxConcurrentReconciles: r.MaxConcurrentReconciles, // Set the desired value for max concurrent reconciles. } - return ctrl.NewControllerManagedBy(mgr). + var err error + if r.Config == nil { + r.Config, err = config.GetConfig() + if err != nil { + klog.Errorf("Failed to get config: %v", err) + return err + } + } + dc := discovery.NewDiscoveryClientForConfigOrDie(r.Config) + _, apiLists, err := dc.ServerGroupsAndResources() + if err != nil { + return err + } + for _, apiList := range apiLists { + if apiList.GroupVersion == routeGroupVersion { + isRouteAPI = true + } + } + + controller := ctrl.NewControllerManagedBy(mgr). WithOptions(options). For(&operatorv1alpha1.OperandBindInfo{}). Watches( &source.Kind{Type: &corev1.ConfigMap{}}, handler.EnqueueRequestsFromMapFunc(toOpbiRequest()), - builder.WithPredicates(cmSecretPredicates), + builder.WithPredicates(bindablePredicates), ). Watches( &source.Kind{Type: &corev1.Secret{}}, handler.EnqueueRequestsFromMapFunc(toOpbiRequest()), - builder.WithPredicates(cmSecretPredicates), + builder.WithPredicates(bindablePredicates), ). Watches( &source.Kind{Type: &operatorv1alpha1.OperandRequest{}}, @@ -770,5 +983,13 @@ func (r *Reconciler) SetupWithManager(mgr ctrl.Manager) error { &source.Kind{Type: &operatorv1alpha1.OperandRegistry{}}, handler.EnqueueRequestsFromMapFunc(r.getOperandRegistryToRequestMapper(mgr)), builder.WithPredicates(opregPredicates), - ).Complete(r) + ) + if isRouteAPI { + controller.Watches( + &source.Kind{Type: &ocproute.Route{}}, + handler.EnqueueRequestsFromMapFunc(toOpbiRequest()), + builder.WithPredicates(bindablePredicates), + ) + } + return controller.Complete(r) } diff --git a/controllers/operandbindinfo/operandbindinfo_suite_test.go b/controllers/operandbindinfo/operandbindinfo_suite_test.go index c321d3ec..d9c26cbe 100644 --- a/controllers/operandbindinfo/operandbindinfo_suite_test.go +++ b/controllers/operandbindinfo/operandbindinfo_suite_test.go @@ -106,6 +106,7 @@ var _ = BeforeSuite(func(done Done) { // Setup Manager with OperandBindInfo Controller err = (&Reconciler{ + Config: cfg, ODLMOperator: deploy.NewODLMOperator(k8sManager, "OperandBindInfo"), }).SetupWithManager(k8sManager) Expect(err).ToNot(HaveOccurred()) diff --git a/controllers/testutil/test_util.go b/controllers/testutil/test_util.go index 2e761d52..50b75900 100644 --- a/controllers/testutil/test_util.go +++ b/controllers/testutil/test_util.go @@ -238,7 +238,7 @@ func OperandRequestObj(registryName, registryNamespace, requestName, requestName }, { Name: "mongodb-atlas-kubernetes", - Bindings: map[string]apiv1alpha1.SecretConfigmap{ + Bindings: map[string]apiv1alpha1.Bindable{ "public": { Secret: "secret4", Configmap: "cm4", @@ -331,7 +331,7 @@ func OperandRequestObjWithProtected(registryName, registryNamespace, requestName }, { Name: "mongodb-atlas-kubernetes", - Bindings: map[string]apiv1alpha1.SecretConfigmap{ + Bindings: map[string]apiv1alpha1.Bindable{ "protected": { Secret: "secret5", Configmap: "cm5", @@ -356,7 +356,7 @@ func OperandBindInfoObj(name, namespace, registryName, registryNamespace string) Operand: "mongodb-atlas-kubernetes", Registry: registryName, RegistryNamespace: registryNamespace, - Bindings: map[string]apiv1alpha1.SecretConfigmap{ + Bindings: map[string]apiv1alpha1.Bindable{ "public": { Secret: "secret1", Configmap: "cm1", diff --git a/controllers/util/util.go b/controllers/util/util.go index 24785e8e..578b204a 100644 --- a/controllers/util/util.go +++ b/controllers/util/util.go @@ -25,6 +25,7 @@ import ( "sync" "time" + ocproute "github.com/openshift/api/route/v1" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/equality" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" @@ -260,6 +261,15 @@ func EnsureLabelsForConfigMap(cm *corev1.ConfigMap, labels map[string]string) { } } +func EnsureLabelsForRoute(r *ocproute.Route, labels map[string]string) { + if r.Labels == nil { + r.Labels = make(map[string]string) + } + for k, v := range labels { + r.Labels[k] = v + } +} + func CompareSecret(secret *corev1.Secret, existingSecret *corev1.Secret) (needUpdate bool) { return !equality.Semantic.DeepEqual(secret.GetLabels(), existingSecret.GetLabels()) || !equality.Semantic.DeepEqual(secret.Type, existingSecret.Type) || !equality.Semantic.DeepEqual(secret.Data, existingSecret.Data) || !equality.Semantic.DeepEqual(secret.StringData, existingSecret.StringData) } diff --git a/go.mod b/go.mod index d76c464e..1ca8530c 100644 --- a/go.mod +++ b/go.mod @@ -11,11 +11,13 @@ require ( github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 github.com/onsi/ginkgo v1.16.5 github.com/onsi/gomega v1.19.0 + github.com/openshift/api v0.0.0-20220124143425-d74727069f6f github.com/operator-framework/api v0.6.2 github.com/operator-framework/operator-lifecycle-manager v0.17.0 github.com/pkg/errors v0.9.1 golang.org/x/mod v0.8.0 k8s.io/api v0.24.3 + k8s.io/apiextensions-apiserver v0.24.2 k8s.io/apimachinery v0.24.3 k8s.io/client-go v0.24.3 k8s.io/klog v1.0.0 @@ -94,7 +96,6 @@ require ( gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/apiextensions-apiserver v0.24.2 // indirect k8s.io/component-base v0.24.2 // indirect k8s.io/klog/v2 v2.60.1 // indirect k8s.io/kube-openapi v0.0.0-20220627174259-011e075b9cb8 // indirect diff --git a/go.sum b/go.sum index 8c4374fb..2650bb04 100644 --- a/go.sum +++ b/go.sum @@ -224,6 +224,11 @@ github.com/cznic/ql v1.2.0/go.mod h1:FbpzhyZrqr0PVlK6ury+PoW3T0ODUV22OeWIxcaOrSE github.com/cznic/sortutil v0.0.0-20150617083342-4c7342852e65/go.mod h1:q2w6Bg5jeox1B+QkJ6Wp/+Vn0G/bo3f1uY7Fn3vivIQ= github.com/cznic/strutil v0.0.0-20171016134553-529a34b1c186/go.mod h1:AHHPPPXTw0h6pVabbcbyGRK1DckRn7r/STdZEeIDzZc= github.com/cznic/zappy v0.0.0-20160723133515-2533cb5b45cc/go.mod h1:Y1SNZ4dRUOKXshKUbwUapqNncRrho4mkjQebgEHZLj8= +github.com/dave/dst v0.26.2/go.mod h1:UMDJuIRPfyUCC78eFuB+SV/WI8oDeyFDvM/JR6NI3IU= +github.com/dave/gopackages v0.0.0-20170318123100-46e7023ec56e/go.mod h1:i00+b/gKdIDIxuLDFob7ustLAVqhsZRk2qVZrArELGQ= +github.com/dave/jennifer v1.2.0/go.mod h1:fIb+770HOpJ2fmN9EPPKOqm1vMGhB+TwXKMZhrIygKg= +github.com/dave/kerr v0.0.0-20170318121727-bc25dd6abe8e/go.mod h1:qZqlPyPvfsDJt+3wHJ1EvSXDuVjFTK0j2p/ca+gtsb8= +github.com/dave/rebecca v0.9.1/go.mod h1:N6XYdMD/OKw3lkF3ywh8Z6wPGuwNFDNtWYEMFWEmXBA= github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -481,6 +486,7 @@ github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/ github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/pprof v0.0.0-20181127221834-b4f47329b966/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= @@ -506,6 +512,7 @@ github.com/googleapis/gnostic v0.1.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTV github.com/googleapis/gnostic v0.3.1/go.mod h1:on+2t9HRStVgn95RSsFWFz+6Q0Snyqv1awfrALZdbtU= github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU= +github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= @@ -751,7 +758,10 @@ github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700/go.m github.com/opencontainers/runtime-tools v0.0.0-20181011054405-1d69bd0f9c39/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs= github.com/openshift/api v0.0.0-20200326152221-912866ddb162/go.mod h1:RKMJ5CBnljLfnej+BJ/xnOWc3kZDvJUaIAEq2oKSPtE= github.com/openshift/api v0.0.0-20200331152225-585af27e34fd/go.mod h1:RKMJ5CBnljLfnej+BJ/xnOWc3kZDvJUaIAEq2oKSPtE= +github.com/openshift/api v0.0.0-20220124143425-d74727069f6f h1:iOTv1WudhVm2UsoST+L+ZrA5A9w57h9vmQsdlBuqG6g= +github.com/openshift/api v0.0.0-20220124143425-d74727069f6f/go.mod h1:F/eU6jgr6Q2VhMu1mSpMmygxAELd7+BUxs3NHZ25jV4= github.com/openshift/build-machinery-go v0.0.0-20200211121458-5e3d6e570160/go.mod h1:1CkcsT3aVebzRBzVTSbiKSkJMsC/CASqxesfqEMfJEc= +github.com/openshift/build-machinery-go v0.0.0-20211213093930-7e33a7eb4ce3/go.mod h1:b1BuldmJlbA/xYtdZvKi+7j5YGB44qJUJDZ9zwiNCfE= github.com/openshift/client-go v0.0.0-20200326155132-2a6cd50aedd0/go.mod h1:uUQ4LClRO+fg5MF/P6QxjMCb1C9f7Oh4RKepftDnEJE= github.com/openshift/elasticsearch-operator v0.0.0-20220708171007-a87102296ded h1:TJJaeg/XIFV0Vr25vjAZISU/kMr5QUKk3vBLXLhmRQE= github.com/openshift/elasticsearch-operator v0.0.0-20220708171007-a87102296ded/go.mod h1:6dxhWPY3Wr/0b0eGrFpV7gcyeS+ne48Mo9OQ9dxrLNI= @@ -948,6 +958,7 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.1.32/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= +github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs= github.com/yvasiyarov/go-metrics v0.0.0-20150112132944-c25f46c4b940 h1:p7OofyZ509h8DmPLh8Hn+EIIZm/xYhdZHJ9GnXHdr6U= @@ -1022,6 +1033,7 @@ go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= go.uber.org/zap v1.19.1 h1:ue41HOKd1vGURxrmeKIgELGb3jPW9DMUDGtsinblHwI= go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= +golang.org/x/arch v0.0.0-20180920145803-b19384d3c130/go.mod h1:cYlCBUl1MsqxdiKgmc4uh7TxZfWSFLOGSRR090WDxt8= golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -1182,6 +1194,7 @@ golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180903190138-2b024373dcd9/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1264,6 +1277,7 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -1351,6 +1365,7 @@ golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWc golang.org/x/tools v0.0.0-20200403190813-44a64ad78b9b/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200509030707-2212a7e161a5/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200616133436-c1934b75d054/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= @@ -1371,6 +1386,7 @@ golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.6-0.20210820212750-d4cc65f0b2ff/go.mod h1:YD9qOF0M9xpSpdWTBbzEl5e/RnCefISl8E5Noe10jFM= golang.org/x/tools v0.1.10-0.20220218145154-897bd77cd717/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1541,6 +1557,7 @@ gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24 gopkg.in/op/go-logging.v1 v1.0.0-20160211212156-b2cb9fa56473/go.mod h1:N1eN2tsCx0Ydtgjl4cqmbRCsY4/+z4cYDeqwZTk6zog= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/src-d/go-billy.v4 v4.3.0/go.mod h1:tm33zBoOwxjYHZIE+OV8bxTWFMJLrconzFMd38aARFk= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= @@ -1579,6 +1596,7 @@ k8s.io/api v0.18.0/go.mod h1:q2HRQkfDzHMBZL9l/y9rH63PkQl4vae0xRT+8prbrK8= k8s.io/api v0.18.2/go.mod h1:SJCWI7OLzhZSvbY7U8zwNl9UA4o1fizoug34OV/2r78= k8s.io/api v0.18.9/go.mod h1:9u/h6sUh6FxfErv7QqetX1EB3yBMIYOBXzdcf0Gf0rc= k8s.io/api v0.20.1/go.mod h1:KqwcCVogGxQY3nBlRpwt+wpAMF/KjaCc7RpywacvqUo= +k8s.io/api v0.23.0/go.mod h1:8wmDdLBHBNxtOIytwLstXt5E9PddnZb0GaMcqsvDBpg= k8s.io/api v0.24.2/go.mod h1:AHqbSkTm6YrQ0ObxjO3Pmp/ubFF/KuM7jU+3khoBsOg= k8s.io/api v0.24.3 h1:tt55QEmKd6L2k5DP6G/ZzdMQKvG5ro4H4teClqm0sTY= k8s.io/api v0.24.3/go.mod h1:elGR/XSZrS7z7cSZPzVWaycpJuGIw57j9b95/1PdJNI= @@ -1594,6 +1612,7 @@ k8s.io/apimachinery v0.18.0/go.mod h1:9SnR/e11v5IbyPCGbvJViimtJ0SwHG4nfZFjU77ftc k8s.io/apimachinery v0.18.2/go.mod h1:9SnR/e11v5IbyPCGbvJViimtJ0SwHG4nfZFjU77ftcA= k8s.io/apimachinery v0.18.9/go.mod h1:PF5taHbXgTEJLU+xMypMmYTXTWPJ5LaW8bfsisxnEXk= k8s.io/apimachinery v0.20.1/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= +k8s.io/apimachinery v0.23.0/go.mod h1:fFCTTBKvKcwTPFzjlcxp91uPFZr+JA0FubU4fLzzFYc= k8s.io/apimachinery v0.24.2/go.mod h1:82Bi4sCzVBdpYjyI4jY6aHX+YCUchUIrZrXKedjd2UM= k8s.io/apimachinery v0.24.3 h1:hrFiNSA2cBZqllakVYyH/VyEh4B581bQRmqATJSeQTg= k8s.io/apimachinery v0.24.3/go.mod h1:82Bi4sCzVBdpYjyI4jY6aHX+YCUchUIrZrXKedjd2UM= @@ -1617,6 +1636,7 @@ k8s.io/code-generator v0.18.0/go.mod h1:+UHX5rSbxmR8kzS+FAv7um6dtYrZokQvjHpDSYRV k8s.io/code-generator v0.18.2/go.mod h1:+UHX5rSbxmR8kzS+FAv7um6dtYrZokQvjHpDSYRVkTc= k8s.io/code-generator v0.18.9/go.mod h1:TgNEVx9hCyPGpdtCWA34olQYLkh3ok9ar7XfSsr8b6c= k8s.io/code-generator v0.20.1/go.mod h1:UsqdF+VX4PU2g46NC2JRs4gc+IfrctnwHb76RNbWHJg= +k8s.io/code-generator v0.23.0/go.mod h1:vQvOhDXhuzqiVfM/YHp+dmg10WDZCchJVObc9MvowsE= k8s.io/code-generator v0.24.2/go.mod h1:dpVhs00hTuTdTY6jvVxvTFCk6gSMrtfRydbhZwHI15w= k8s.io/component-base v0.17.2/go.mod h1:zMPW3g5aH7cHJpKYQ/ZsGMcgbsA/VyhEugF3QT1awLs= k8s.io/component-base v0.18.0/go.mod h1:u3BCg0z1uskkzrnAKFzulmYaEpZF7XC9Pf/uFyb1v2c= @@ -1639,6 +1659,7 @@ k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= k8s.io/klog/v2 v2.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= +k8s.io/klog/v2 v2.30.0/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= k8s.io/klog/v2 v2.60.1 h1:VW25q3bZx9uE3vvdL6M8ezOX79vA2Aq1nEWLqNQclHc= k8s.io/klog/v2 v2.60.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= k8s.io/kube-aggregator v0.18.9/go.mod h1:ik5Mf6JaP2M9XbWZR/AYgXx2Nj4EDBrHyakUx7C8cdw= @@ -1646,6 +1667,7 @@ k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKf k8s.io/kube-openapi v0.0.0-20200121204235-bf4fb3bd569c/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E= k8s.io/kube-openapi v0.0.0-20200410145947-61e04a5be9a6/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E= k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd/go.mod h1:WOJ3KddDSol4tAGcJo0Tvi+dK12EcqSLqcWsryKMpfM= +k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65/go.mod h1:sX9MT8g7NVZM5lVL/j8QyCCJe8YSMW30QvGZWaCIDIk= k8s.io/kube-openapi v0.0.0-20220328201542-3ee0da9b0b42/go.mod h1:Z/45zLw8lUo4wdiUkI+v/ImEGAvu3WatcZl3lPMR4Rk= k8s.io/kube-openapi v0.0.0-20220627174259-011e075b9cb8 h1:yEQKdMCjzAOvGeiTwG4hO/hNVNtDOuUFvMUZ0OlaIzs= k8s.io/kube-openapi v0.0.0-20220627174259-011e075b9cb8/go.mod h1:mbJ+NSUoAhuR14N0S63bPkh8MGVSo3VYSGZtH/mfMe0= @@ -1658,6 +1680,7 @@ k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/utils v0.0.0-20210930125809-cb0fa318a74b/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9 h1:HNSDgDCrr/6Ly3WEGKZftiE7IY19Vz2GdbOCyI4qqhc= k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw= @@ -1679,6 +1702,7 @@ sigs.k8s.io/controller-runtime v0.12.3 h1:FCM8xeY/FI8hoAfh/V4XbbYMY20gElh9yh+A98 sigs.k8s.io/controller-runtime v0.12.3/go.mod h1:qKsk4WE6zW2Hfj0G4v10EnNB2jMG1C+NTb8h+DwCoU0= sigs.k8s.io/controller-tools v0.3.0/go.mod h1:enhtKGfxZD1GFEoMgP8Fdbu+uKQ/cq1/WGJhdVChfvI= sigs.k8s.io/controller-tools v0.4.1/go.mod h1:G9rHdZMVlBDocIxGkK3jHLWqcTMNvveypYJwrvYKjWU= +sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6/go.mod h1:p4QtZmO4uMYipTQNzagwnNoseA6OxSUutVw05NhYDRs= sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2 h1:kDi4JBNAsJWfz1aEXhO8Jg87JJaPNLh5tIzYHgStQ9Y= sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2/go.mod h1:B+TnT182UBxE84DiCz4CVE26eOSDAeYCpfDnC2kdKMY= sigs.k8s.io/kind v0.7.0/go.mod h1:An/AbWHT6pA/Lm0Og8j3ukGhfJP3RiVN/IBU6Lo3zl8= @@ -1690,6 +1714,7 @@ sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06/go.mod h1 sigs.k8s.io/structured-merge-diff/v3 v3.0.0-20200116222232-67a7b8c61874/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= sigs.k8s.io/structured-merge-diff/v3 v3.0.0/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/structured-merge-diff/v4 v4.1.2/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= sigs.k8s.io/structured-merge-diff/v4 v4.2.1 h1:bKCqE9GvQ5tiVHn5rfn1r+yao3aLQEaLzkkmAkf+A6Y= sigs.k8s.io/structured-merge-diff/v4 v4.2.1/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= diff --git a/main.go b/main.go index 17b3658b..0b53313b 100644 --- a/main.go +++ b/main.go @@ -21,6 +21,7 @@ import ( "os" "strings" + ocproute "github.com/openshift/api/route/v1" olmv1 "github.com/operator-framework/api/pkg/operators/v1" olmv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1" operatorsv1 "github.com/operator-framework/operator-lifecycle-manager/pkg/package-server/apis/operators/v1" @@ -64,6 +65,7 @@ func init() { utilruntime.Must(operatorv1alpha1.AddToScheme(scheme)) utilruntime.Must(operatorsv1.AddToScheme(scheme)) + utilruntime.Must(ocproute.AddToScheme(scheme)) // +kubebuilder:scaffold:scheme } diff --git a/test/e2e/helpers_test.go b/test/e2e/helpers_test.go index 191130e7..24f5a482 100644 --- a/test/e2e/helpers_test.go +++ b/test/e2e/helpers_test.go @@ -791,7 +791,7 @@ func newOperandRequestWithBindinfo(name, namespace, RegistryNamespace string) *v Operands: []v1alpha1.Operand{ { Name: "mongodb-atlas-kubernetes", - Bindings: map[string]v1alpha1.SecretConfigmap{ + Bindings: map[string]v1alpha1.Bindable{ "public": { Secret: "mongodb-secret", Configmap: "mongodb-configmap", @@ -817,7 +817,7 @@ func newOperandBindInfoCR(name, namespace, RegistryNamespace string) *v1alpha1.O Registry: OperandRegistryCrName, RegistryNamespace: RegistryNamespace, - Bindings: map[string]v1alpha1.SecretConfigmap{ + Bindings: map[string]v1alpha1.Bindable{ "public": { Secret: "mongodb-secret", Configmap: "mongodb-configmap", From b94e87370eee337f0c25043e3ac6516601a2531a Mon Sep 17 00:00:00 2001 From: Henry Li Date: Fri, 3 Nov 2023 18:59:52 -0400 Subject: [PATCH 061/179] Add support for sharing Service data via ConfigMap with OperandBindInfo (#993) * added new type ServiceData as a Bindable Signed-off-by: Henry H Li * added Service data copying to OperandBindInfo Signed-off-by: Henry H Li * fixed incorrect comment referring to Route when copying Service Signed-off-by: Henry H Li * added missing error handling when executing jsonpath parsing Signed-off-by: Henry H Li * fixed sanitized service data value concatenating across multiple keys by re-initializing trueValue for each key in service datax Signed-off-by: Henry H Li --------- Signed-off-by: Henry H Li --- api/v1alpha1/operandbindinfo_types.go | 17 +- api/v1alpha1/zz_generated.deepcopy.go | 27 ++++ ...fecycle-manager.clusterserviceversion.yaml | 2 +- .../operator.ibm.com_operandbindinfos.yaml | 20 ++- .../operator.ibm.com_operandrequests.yaml | 21 ++- .../operator.ibm.com_operandbindinfos.yaml | 20 ++- .../operator.ibm.com_operandrequests.yaml | 21 ++- .../operator.ibm.com_operandbindinfos.yaml | 20 ++- .../operator.ibm.com_operandrequests.yaml | 21 ++- .../operandbindinfo_controller.go | 145 +++++++++++++++++- controllers/util/util.go | 9 ++ 11 files changed, 308 insertions(+), 15 deletions(-) diff --git a/api/v1alpha1/operandbindinfo_types.go b/api/v1alpha1/operandbindinfo_types.go index d7516360..35cb293b 100644 --- a/api/v1alpha1/operandbindinfo_types.go +++ b/api/v1alpha1/operandbindinfo_types.go @@ -72,10 +72,14 @@ type Bindable struct { // The configmap identifies an existing configmap object. if it exists, the ODLM will share to the namespace of the OperandRequest. // +optional Configmap string `json:"configmap,omitempty"` - // Route data will shared by copying it into a configmap which is then + // Route data will be shared by copying it into a configmap which is then // created in the target namespace // +optional Route *Route `json:"route,omitempty"` + // Service data will be shared by copying it into a configmap which is then + // created in the target namespace + // +optional + Service *ServiceData `json:"service,omitempty"` } // Route represents the name and data inside an OpenShift route. @@ -89,6 +93,17 @@ type Route struct { Data map[string]string `json:"data"` } +// ServiceData represents the name and data inside an Kubernetes Service. +type ServiceData struct { + // Name is the name of the Kubernetes Service resource + // +optional + Name string `json:"name"` + // Data is a key-value pair where the value is a YAML path to a value in the + // Kubernetes Service, e.g. .spec.ports[0]port + // +optional + Data map[string]string `json:"data"` +} + // OperandBindInfoStatus defines the observed state of OperandBindInfo. type OperandBindInfoStatus struct { // Phase describes the overall phase of OperandBindInfo. diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 8cfe54b7..531bb62f 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -34,6 +34,11 @@ func (in *Bindable) DeepCopyInto(out *Bindable) { *out = new(Route) (*in).DeepCopyInto(*out) } + if in.Service != nil { + in, out := &in.Service, &out.Service + *out = new(ServiceData) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Bindable. @@ -806,6 +811,28 @@ func (in *Route) DeepCopy() *Route { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ServiceData) DeepCopyInto(out *ServiceData) { + *out = *in + if in.Data != nil { + in, out := &in.Data, &out.Data + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServiceData. +func (in *ServiceData) DeepCopy() *ServiceData { + if in == nil { + return nil + } + out := new(ServiceData) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ServiceStatus) DeepCopyInto(out *ServiceStatus) { *out = *in diff --git a/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml b/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml index 709e8c9d..0b388dc0 100644 --- a/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml +++ b/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml @@ -129,7 +129,7 @@ metadata: categories: Developer Tools, Monitoring, Logging & Tracing, Security certified: "false" containerImage: icr.io/cpopen/odlm:latest - createdAt: "2023-11-02T22:53:11Z" + createdAt: "2023-11-03T17:30:05Z" description: The Operand Deployment Lifecycle Manager provides a Kubernetes CRD-based API to manage the lifecycle of operands. nss.operator.ibm.com/managed-operators: ibm-odlm olm.skipRange: '>=1.2.0 <4.2.1' diff --git a/bundle/manifests/operator.ibm.com_operandbindinfos.yaml b/bundle/manifests/operator.ibm.com_operandbindinfos.yaml index 822fc474..ede2685f 100644 --- a/bundle/manifests/operator.ibm.com_operandbindinfos.yaml +++ b/bundle/manifests/operator.ibm.com_operandbindinfos.yaml @@ -66,8 +66,8 @@ spec: of the OperandRequest. type: string route: - description: Route data will shared by copying it into a configmap - which is then created in the target namespace + description: Route data will be shared by copying it into a + configmap which is then created in the target namespace properties: data: additionalProperties: @@ -84,6 +84,22 @@ spec: description: The secret identifies an existing secret. if it exists, the ODLM will share to the namespace of the OperandRequest. type: string + service: + description: Service data will be shared by copying it into + a configmap which is then created in the target namespace + properties: + data: + additionalProperties: + type: string + description: Data is a key-value pair where the value is + a YAML path to a value in the Kubernetes Service, e.g. + .spec.ports[0]port + type: object + name: + description: Name is the name of the Kubernetes Service + resource + type: string + type: object type: object description: The bindings section is used to specify information about the access/configuration data that is to be shared. diff --git a/bundle/manifests/operator.ibm.com_operandrequests.yaml b/bundle/manifests/operator.ibm.com_operandrequests.yaml index 50fbab51..f6109d5b 100644 --- a/bundle/manifests/operator.ibm.com_operandrequests.yaml +++ b/bundle/manifests/operator.ibm.com_operandrequests.yaml @@ -89,8 +89,8 @@ spec: share to the namespace of the OperandRequest. type: string route: - description: Route data will shared by copying it - into a configmap which is then created in the + description: Route data will be shared by copying + it into a configmap which is then created in the target namespace properties: data: @@ -110,6 +110,23 @@ spec: if it exists, the ODLM will share to the namespace of the OperandRequest. type: string + service: + description: Service data will be shared by copying + it into a configmap which is then created in the + target namespace + properties: + data: + additionalProperties: + type: string + description: Data is a key-value pair where + the value is a YAML path to a value in the + Kubernetes Service, e.g. .spec.ports[0]port + type: object + name: + description: Name is the name of the Kubernetes + Service resource + type: string + type: object type: object description: The bindings section is used to specify names of secret and/or configmap. diff --git a/config/crd/bases/operator.ibm.com_operandbindinfos.yaml b/config/crd/bases/operator.ibm.com_operandbindinfos.yaml index dc3deb6a..c9b0f10e 100644 --- a/config/crd/bases/operator.ibm.com_operandbindinfos.yaml +++ b/config/crd/bases/operator.ibm.com_operandbindinfos.yaml @@ -64,8 +64,8 @@ spec: of the OperandRequest. type: string route: - description: Route data will shared by copying it into a configmap - which is then created in the target namespace + description: Route data will be shared by copying it into a + configmap which is then created in the target namespace properties: data: additionalProperties: @@ -82,6 +82,22 @@ spec: description: The secret identifies an existing secret. if it exists, the ODLM will share to the namespace of the OperandRequest. type: string + service: + description: Service data will be shared by copying it into + a configmap which is then created in the target namespace + properties: + data: + additionalProperties: + type: string + description: Data is a key-value pair where the value is + a YAML path to a value in the Kubernetes Service, e.g. + .spec.ports[0]port + type: object + name: + description: Name is the name of the Kubernetes Service + resource + type: string + type: object type: object description: The bindings section is used to specify information about the access/configuration data that is to be shared. diff --git a/config/crd/bases/operator.ibm.com_operandrequests.yaml b/config/crd/bases/operator.ibm.com_operandrequests.yaml index c9ba0a55..b6935961 100644 --- a/config/crd/bases/operator.ibm.com_operandrequests.yaml +++ b/config/crd/bases/operator.ibm.com_operandrequests.yaml @@ -87,8 +87,8 @@ spec: share to the namespace of the OperandRequest. type: string route: - description: Route data will shared by copying it - into a configmap which is then created in the + description: Route data will be shared by copying + it into a configmap which is then created in the target namespace properties: data: @@ -108,6 +108,23 @@ spec: if it exists, the ODLM will share to the namespace of the OperandRequest. type: string + service: + description: Service data will be shared by copying + it into a configmap which is then created in the + target namespace + properties: + data: + additionalProperties: + type: string + description: Data is a key-value pair where + the value is a YAML path to a value in the + Kubernetes Service, e.g. .spec.ports[0]port + type: object + name: + description: Name is the name of the Kubernetes + Service resource + type: string + type: object type: object description: The bindings section is used to specify names of secret and/or configmap. diff --git a/config/e2e/crd/bases/operator.ibm.com_operandbindinfos.yaml b/config/e2e/crd/bases/operator.ibm.com_operandbindinfos.yaml index 78790021..0b560cde 100644 --- a/config/e2e/crd/bases/operator.ibm.com_operandbindinfos.yaml +++ b/config/e2e/crd/bases/operator.ibm.com_operandbindinfos.yaml @@ -68,8 +68,8 @@ spec: of the OperandRequest. type: string route: - description: Route data will shared by copying it into a configmap - which is then created in the target namespace + description: Route data will be shared by copying it into a + configmap which is then created in the target namespace properties: data: additionalProperties: @@ -86,6 +86,22 @@ spec: description: The secret identifies an existing secret. if it exists, the ODLM will share to the namespace of the OperandRequest. type: string + service: + description: Service data will be shared by copying it into + a configmap which is then created in the target namespace + properties: + data: + additionalProperties: + type: string + description: Data is a key-value pair where the value is + a YAML path to a value in the Kubernetes Service, e.g. + .spec.ports[0]port + type: object + name: + description: Name is the name of the Kubernetes Service + resource + type: string + type: object type: object description: The bindings section is used to specify information about the access/configuration data that is to be shared. diff --git a/config/e2e/crd/bases/operator.ibm.com_operandrequests.yaml b/config/e2e/crd/bases/operator.ibm.com_operandrequests.yaml index bf63d956..770a90e7 100644 --- a/config/e2e/crd/bases/operator.ibm.com_operandrequests.yaml +++ b/config/e2e/crd/bases/operator.ibm.com_operandrequests.yaml @@ -91,8 +91,8 @@ spec: share to the namespace of the OperandRequest. type: string route: - description: Route data will shared by copying it - into a configmap which is then created in the + description: Route data will be shared by copying + it into a configmap which is then created in the target namespace properties: data: @@ -112,6 +112,23 @@ spec: if it exists, the ODLM will share to the namespace of the OperandRequest. type: string + service: + description: Service data will be shared by copying + it into a configmap which is then created in the + target namespace + properties: + data: + additionalProperties: + type: string + description: Data is a key-value pair where + the value is a YAML path to a value in the + Kubernetes Service, e.g. .spec.ports[0]port + type: object + name: + description: Name is the name of the Kubernetes + Service resource + type: string + type: object type: object description: The bindings section is used to specify names of secret and/or configmap. diff --git a/controllers/operandbindinfo/operandbindinfo_controller.go b/controllers/operandbindinfo/operandbindinfo_controller.go index c4fab85d..66067532 100644 --- a/controllers/operandbindinfo/operandbindinfo_controller.go +++ b/controllers/operandbindinfo/operandbindinfo_controller.go @@ -17,6 +17,7 @@ package operandbindinfo import ( + "bytes" "context" "fmt" "reflect" @@ -36,6 +37,7 @@ import ( utilerrors "k8s.io/apimachinery/pkg/util/errors" "k8s.io/client-go/discovery" "k8s.io/client-go/rest" + "k8s.io/client-go/util/jsonpath" "k8s.io/klog" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/builder" @@ -221,6 +223,15 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctrl.Re requeue = requeue || requeueRoute } } + // Copy Service data into configmap and share configmap + if binding.Service != nil { + requeueService, err := r.copyService(ctx, *binding.Service, "", operandNamespace, bindRequest.Namespace, key, bindInfoInstance, requestInstance) + if err != nil { + merr.Add(err) + continue + } + requeue = requeue || requeueService + } } } if len(merr.Errors) != 0 { @@ -427,6 +438,8 @@ func (r *Reconciler) copyConfigmap(ctx context.Context, sourceName, targetName, return false, nil } +// copyRoute reads the data map and copies OCP Route data as specified by the +// field path in the data map values func (r *Reconciler) copyRoute(ctx context.Context, route operatorv1alpha1.Route, targetName, sourceNs, targetNs, key string, bindInfoInstance *operatorv1alpha1.OperandBindInfo, requestInstance *operatorv1alpha1.OperandRequest) (requeue bool, err error) { if route.Name == "" || sourceNs == "" || targetNs == "" { @@ -521,7 +534,103 @@ func (r *Reconciler) copyRoute(ctx context.Context, route operatorv1alpha1.Route return false, nil } -// sanitizedOdlmRouteData takes a map, i.e. ODLM's Route.Data, and an OCP Route.Spec, +// copyRoute reads the data map and copies K8s Service data as specified by the +// field path in the data map values +func (r *Reconciler) copyService(ctx context.Context, service operatorv1alpha1.ServiceData, targetName, sourceNs, targetNs, key string, + bindInfoInstance *operatorv1alpha1.OperandBindInfo, requestInstance *operatorv1alpha1.OperandRequest) (requeue bool, err error) { + if service.Name == "" || sourceNs == "" || targetNs == "" { + return false, nil + } + + if service.Name == targetName && sourceNs == targetNs { + return false, nil + } + + if targetName == "" { + if publicPrefix.MatchString(key) { + targetName = bindInfoInstance.Name + "-" + service.Name + } else { + return false, nil + } + } + + sourceService := &corev1.Service{} + if err := r.Client.Get(ctx, types.NamespacedName{Name: service.Name, Namespace: sourceNs}, sourceService); err != nil { + if apierrors.IsNotFound(err) { + klog.V(3).Infof("Route %s/%s is not found", sourceNs, service.Name) + r.Recorder.Eventf(bindInfoInstance, corev1.EventTypeNormal, "NotFound", "No Service %s in the namespace %s", service.Name, sourceNs) + return true, nil + } + return false, errors.Wrapf(err, "failed to get Service %s/%s", sourceNs, service.Name) + } + // Create the ConfigMap to the OperandRequest namespace + labels := make(map[string]string) + // Copy from the original labels to the target labels + for k, v := range sourceService.Labels { + labels[k] = v + } + labels[bindInfoInstance.Namespace+"."+bindInfoInstance.Name+"/bindinfo"] = "true" + labels[constant.OpbiTypeLabel] = "copy" + + sanitizedData, err := sanitizeServiceData(service.Data, *sourceService) + if err != nil { + return false, err + } + cmCopy := &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: targetName, + Namespace: targetNs, + Labels: labels, + }, + Data: sanitizedData, + } + // Set the OperandRequest as the controller of the configmap + if err := controllerutil.SetControllerReference(requestInstance, cmCopy, r.Scheme); err != nil { + return false, errors.Wrapf(err, "failed to set OperandRequest %s as the owner of ConfigMap %s", requestInstance.Name, service.Name) + } + + var podRefreshment bool + // Create the ConfigMap in the OperandRequest namespace + if err := r.Create(ctx, cmCopy); err != nil { + if apierrors.IsAlreadyExists(err) { + // If already exist, update the ConfigMap + existingCm := &corev1.ConfigMap{} + if err := r.Client.Get(ctx, types.NamespacedName{Namespace: targetNs, Name: targetName}, existingCm); err != nil { + return false, errors.Wrapf(err, "failed to get ConfigMap %s/%s", targetNs, targetName) + } + if needUpdate := util.CompareConfigMap(cmCopy, existingCm); needUpdate { + podRefreshment = true + if err := r.Update(ctx, cmCopy); err != nil { + return false, errors.Wrapf(err, "failed to update ConfigMap %s/%s", targetNs, service.Name) + } + } + } else { + return false, errors.Wrapf(err, "failed to create ConfigMap %s/%s", targetNs, service.Name) + } + } + + if podRefreshment { + if err := r.refreshPods(targetNs, targetName, "configmap"); err != nil { + return false, errors.Wrapf(err, "failed to refresh pods mounting ConfigMap %s/%s", targetNs, targetName) + } + } + + // Set the OperandBindInfo label for the ConfigMap + util.EnsureLabelsForService(sourceService, map[string]string{ + bindInfoInstance.Namespace + "." + bindInfoInstance.Name + "/bindinfo": "true", + constant.OpbiTypeLabel: "original", + }) + + // Update the operand Configmap + if err := r.Update(ctx, sourceService); err != nil { + return false, errors.Wrapf(err, "failed to update ConfigMap %s/%s", sourceService.Namespace, sourceService.Name) + } + klog.V(1).Infof("Service %s is copied from the namespace %s to the namespace %s", service.Name, sourceNs, targetNs) + + return false, nil +} + +// sanitizeOdlmRouteData takes a map, i.e. ODLM's Route.Data, and an OCP Route.Spec, // and returns a map ready to be included into a ConfigMap's data. The ODLM's // Route.Data is sanitized because the values are YAML path references // in map because they correspond to YAML fields in a OCP Route. Ensures that: @@ -559,6 +668,40 @@ func sanitizeOdlmRouteData(m map[string]string, route ocproute.RouteSpec) (map[s return sanitized, nil } +// sanitizeServiceData takes a map, i.e. ODLM's Service.Data, and a K8s Service object +// and returns a map ready to be included into a ConfigMap's data. The ODLM's +// Service.Data is sanitized because the values are YAML fields in a K8s Service. +// Ensures that: +// 1. the field actually exists, otherwise returns an error +// 2. extracts the value from the K8s Service's field, the value will be +// stringified +func sanitizeServiceData(m map[string]string, service corev1.Service) (map[string]string, error) { + sanitized := make(map[string]string, len(m)) + jpath := jsonpath.New("sanitizeServiceData") + for k, v := range m { + trueValue := "" + stringParts := strings.Split(v, "+") + for _, s := range stringParts { + actual := s + if strings.HasPrefix(s, ".") { + if len(s) > 1 { + if err := jpath.Parse("{" + s + "}"); err != nil { + return nil, err + } + buf := new(bytes.Buffer) + if err := jpath.Execute(buf, service); err != nil { + return nil, err + } + actual = buf.String() + } + } + trueValue += actual + } + sanitized[k] = trueValue + } + return sanitized, nil +} + // nestedBasicType is a wrapper around the various unstructured.Nested methods // used to extract values from nested fields. It takes the same arguments // as the Nested methods and returns a string if some basic type value is found. diff --git a/controllers/util/util.go b/controllers/util/util.go index 578b204a..a17bf799 100644 --- a/controllers/util/util.go +++ b/controllers/util/util.go @@ -270,6 +270,15 @@ func EnsureLabelsForRoute(r *ocproute.Route, labels map[string]string) { } } +func EnsureLabelsForService(s *corev1.Service, labels map[string]string) { + if s.Labels == nil { + s.Labels = make(map[string]string) + } + for k, v := range labels { + s.Labels[k] = v + } +} + func CompareSecret(secret *corev1.Secret, existingSecret *corev1.Secret) (needUpdate bool) { return !equality.Semantic.DeepEqual(secret.GetLabels(), existingSecret.GetLabels()) || !equality.Semantic.DeepEqual(secret.Type, existingSecret.Type) || !equality.Semantic.DeepEqual(secret.Data, existingSecret.Data) || !equality.Semantic.DeepEqual(secret.StringData, existingSecret.StringData) } From ff4546c6f550c039e433c9afe7c705aa81984eef Mon Sep 17 00:00:00 2001 From: Daniel Fan Date: Tue, 7 Nov 2023 00:25:54 -0500 Subject: [PATCH 062/179] Support jsonpath in OperandConfig value reference (#994) Signed-off-by: Daniel Fan --- .../operandbindinfo_controller.go | 23 ++----------- controllers/operator/manager.go | 8 ++--- controllers/util/util.go | 32 +++++++++++++++++++ 3 files changed, 38 insertions(+), 25 deletions(-) diff --git a/controllers/operandbindinfo/operandbindinfo_controller.go b/controllers/operandbindinfo/operandbindinfo_controller.go index 66067532..2c1bab9c 100644 --- a/controllers/operandbindinfo/operandbindinfo_controller.go +++ b/controllers/operandbindinfo/operandbindinfo_controller.go @@ -17,7 +17,6 @@ package operandbindinfo import ( - "bytes" "context" "fmt" "reflect" @@ -37,7 +36,6 @@ import ( utilerrors "k8s.io/apimachinery/pkg/util/errors" "k8s.io/client-go/discovery" "k8s.io/client-go/rest" - "k8s.io/client-go/util/jsonpath" "k8s.io/klog" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/builder" @@ -677,25 +675,10 @@ func sanitizeOdlmRouteData(m map[string]string, route ocproute.RouteSpec) (map[s // stringified func sanitizeServiceData(m map[string]string, service corev1.Service) (map[string]string, error) { sanitized := make(map[string]string, len(m)) - jpath := jsonpath.New("sanitizeServiceData") for k, v := range m { - trueValue := "" - stringParts := strings.Split(v, "+") - for _, s := range stringParts { - actual := s - if strings.HasPrefix(s, ".") { - if len(s) > 1 { - if err := jpath.Parse("{" + s + "}"); err != nil { - return nil, err - } - buf := new(bytes.Buffer) - if err := jpath.Execute(buf, service); err != nil { - return nil, err - } - actual = buf.String() - } - } - trueValue += actual + trueValue, err := util.SanitizeObjectString(v, service) + if err != nil { + return nil, err } sanitized[k] = trueValue } diff --git a/controllers/operator/manager.go b/controllers/operator/manager.go index 3dbb3115..4848d98c 100644 --- a/controllers/operator/manager.go +++ b/controllers/operator/manager.go @@ -672,13 +672,11 @@ func (m *ODLMOperator) GetValueRefFromObject(ctx context.Context, instanceType, return "", nil } - value, ok, err := unstructured.NestedString(obj.Object, strings.Split(path, ".")...) + sanitizedString, err := util.SanitizeObjectString(path, obj.Object) if err != nil { return "", errors.Wrapf(err, "failed to parse path %v from %s %s/%s", path, obj.GetKind(), obj.GetNamespace(), obj.GetName()) - } else if !ok { - return "", errors.Errorf("failed to get path %v from %s %s/%s, the value is not found", path, obj.GetKind(), obj.GetNamespace(), obj.GetName()) } - klog.V(2).Infof("Get value %s from %s %s/%s", value, objKind, obj.GetNamespace(), obj.GetName()) - return value, nil + klog.V(2).Infof("Get value %s from %s %s/%s", sanitizedString, objKind, obj.GetNamespace(), obj.GetName()) + return sanitizedString, nil } diff --git a/controllers/util/util.go b/controllers/util/util.go index a17bf799..5846d374 100644 --- a/controllers/util/util.go +++ b/controllers/util/util.go @@ -17,6 +17,7 @@ package util import ( + "bytes" "fmt" "os" "sort" @@ -31,6 +32,7 @@ import ( "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" "k8s.io/client-go/discovery" + "k8s.io/client-go/util/jsonpath" ) type TemplateValueRef struct { @@ -286,3 +288,33 @@ func CompareSecret(secret *corev1.Secret, existingSecret *corev1.Secret) (needUp func CompareConfigMap(configMap *corev1.ConfigMap, existingConfigMap *corev1.ConfigMap) (needUpdate bool) { return !equality.Semantic.DeepEqual(configMap.GetLabels(), existingConfigMap.GetLabels()) || !equality.Semantic.DeepEqual(configMap.Data, existingConfigMap.Data) || !equality.Semantic.DeepEqual(configMap.BinaryData, existingConfigMap.BinaryData) } + +// SanitizeObjectString takes a string, i.e. .metadata.namespace, and a K8s object +// and returns a string got from K8s object. The required string +// is sanitized because the values are YAML fields in a K8s object. +// Ensures that: +// 1. the field actually exists, otherwise returns an error +// 2. extracts the value from the K8s Service's field, the value will be +// stringified +func SanitizeObjectString(jsonPath string, data interface{}) (string, error) { + jpath := jsonpath.New("sanitizeObjectData") + stringParts := strings.Split(jsonPath, "+") + sanitized := "" + for _, s := range stringParts { + actual := s + if strings.HasPrefix(s, ".") { + if len(s) > 1 { + if err := jpath.Parse("{" + s + "}"); err != nil { + return "", err + } + buf := new(bytes.Buffer) + if err := jpath.Execute(buf, data); err != nil { + return "", err + } + actual = buf.String() + } + } + sanitized += actual + } + return sanitized, nil +} From 8facf587d9ff6dd90864e8811ca8afc7054e411b Mon Sep 17 00:00:00 2001 From: Daniel Fan Date: Wed, 22 Nov 2023 12:08:20 -0500 Subject: [PATCH 063/179] Bump ODLM to 4.2.2 (#998) Signed-off-by: Daniel Fan --- Makefile | 2 +- ...eployment-lifecycle-manager.clusterserviceversion.yaml | 8 ++++---- common/scripts/next-csv.sh | 2 ++ ...eployment-lifecycle-manager.clusterserviceversion.yaml | 4 ++-- version/version.go | 2 +- 5 files changed, 10 insertions(+), 8 deletions(-) diff --git a/Makefile b/Makefile index f588bec2..3e59982f 100644 --- a/Makefile +++ b/Makefile @@ -84,7 +84,7 @@ OPERATOR_IMAGE_NAME ?= odlm # Current Operator bundle image name BUNDLE_IMAGE_NAME ?= odlm-operator-bundle # Current Operator version -OPERATOR_VERSION ?= 4.2.1 +OPERATOR_VERSION ?= 4.2.2 # Kind cluster name KIND_CLUSTER_NAME ?= "odlm" diff --git a/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml b/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml index 0b388dc0..ca8773ff 100644 --- a/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml +++ b/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml @@ -132,7 +132,7 @@ metadata: createdAt: "2023-11-03T17:30:05Z" description: The Operand Deployment Lifecycle Manager provides a Kubernetes CRD-based API to manage the lifecycle of operands. nss.operator.ibm.com/managed-operators: ibm-odlm - olm.skipRange: '>=1.2.0 <4.2.1' + olm.skipRange: '>=1.2.0 <4.2.2' operators.openshift.io/infrastructure-features: '["disconnected"]' operators.operatorframework.io/builder: operator-sdk-v1.29.0 operators.operatorframework.io/project_layout: go.kubebuilder.io/v3 @@ -143,7 +143,7 @@ metadata: operatorframework.io/arch.ppc64le: supported operatorframework.io/arch.s390x: supported operatorframework.io/os.linux: supported - name: operand-deployment-lifecycle-manager.v4.2.1 + name: operand-deployment-lifecycle-manager.v4.2.2 namespace: placeholder spec: apiservicedefinitions: {} @@ -786,7 +786,7 @@ spec: minKubeVersion: 1.19.0 provider: name: IBM - version: 4.2.1 + version: 4.2.2 relatedImages: - - image: icr.io/cpopen/odlm:4.2.1 + - image: icr.io/cpopen/odlm:4.2.2 name: ODLM_IMAGE diff --git a/common/scripts/next-csv.sh b/common/scripts/next-csv.sh index f0783e51..12279c24 100755 --- a/common/scripts/next-csv.sh +++ b/common/scripts/next-csv.sh @@ -35,6 +35,7 @@ if [[ "$OSTYPE" == "linux-gnu"* ]]; then # Update config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml sed -i "/olm.skipRange/s/$CURRENT_DEV_CSV/$NEW_DEV_CSV/g" config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml + sed -i "s/odlm:$CURRENT_DEV_CSV/odlm:$NEW_DEV_CSV/g" config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml echo "Updated the config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml" sed -i "s/OPERATOR_VERSION ?= $CURRENT_DEV_CSV/OPERATOR_VERSION ?= $NEW_DEV_CSV/g" Makefile @@ -54,6 +55,7 @@ elif [[ "$OSTYPE" == "darwin"* ]]; then # Update config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml sed -i "" "/olm.skipRange/s/$CURRENT_DEV_CSV/$NEW_DEV_CSV/g" config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml + sed -i "" "s/odlm:$CURRENT_DEV_CSV/odlm:$NEW_DEV_CSV/g" config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml echo "Updated the config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml" sed -i "" "s/OPERATOR_VERSION ?= $CURRENT_DEV_CSV/OPERATOR_VERSION ?= $NEW_DEV_CSV/g" Makefile diff --git a/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml b/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml index 88d5602e..12b80865 100644 --- a/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml +++ b/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml @@ -11,7 +11,7 @@ metadata: description: The Operand Deployment Lifecycle Manager provides a Kubernetes CRD-based API to manage the lifecycle of operands. nss.operator.ibm.com/managed-operators: ibm-odlm - olm.skipRange: '>=1.2.0 <4.2.1' + olm.skipRange: '>=1.2.0 <4.2.2' operators.openshift.io/infrastructure-features: '["disconnected"]' operators.operatorframework.io/builder: operator-sdk-v1.2.0 operators.operatorframework.io/project_layout: go.kubebuilder.io/v2 @@ -467,6 +467,6 @@ spec: provider: name: IBM relatedImages: - - image: icr.io/cpopen/odlm:4.2.1 + - image: icr.io/cpopen/odlm:4.2.2 name: ODLM_IMAGE version: 0.0.0 diff --git a/version/version.go b/version/version.go index 2d5c3966..84c11b15 100644 --- a/version/version.go +++ b/version/version.go @@ -17,5 +17,5 @@ package version var ( - Version = "4.2.1" + Version = "4.2.2" ) From baf5923cfad8eeead4490788c1353bc01b431972 Mon Sep 17 00:00:00 2001 From: YuChen Shen <59578388+YCShen1010@users.noreply.github.com> Date: Tue, 28 Nov 2023 13:16:24 -0500 Subject: [PATCH 064/179] allow to add multiple owners to cm/secret (#999) * allow to add multiple owners to cm/secret Signed-off-by: YuChen * split the line to reduce its length Signed-off-by: YuChen --------- Signed-off-by: YuChen --- .../operandbindinfo_controller.go | 24 +++++++++++++++---- .../operandrequest/reconcile_operand.go | 2 +- controllers/util/util.go | 11 +++++++-- 3 files changed, 30 insertions(+), 7 deletions(-) diff --git a/controllers/operandbindinfo/operandbindinfo_controller.go b/controllers/operandbindinfo/operandbindinfo_controller.go index 2c1bab9c..11bd921d 100644 --- a/controllers/operandbindinfo/operandbindinfo_controller.go +++ b/controllers/operandbindinfo/operandbindinfo_controller.go @@ -296,8 +296,8 @@ func (r *Reconciler) copySecret(ctx context.Context, sourceName, targetName, sou Data: secret.Data, StringData: secret.StringData, } - // Set the OperandRequest as the controller of the Secret - if err := controllerutil.SetControllerReference(requestInstance, secretCopy, r.Scheme); err != nil { + // Set the OperandRequest as the owner of the Secret + if err := controllerutil.SetOwnerReference(requestInstance, secretCopy, r.Scheme); err != nil { return false, errors.Wrapf(err, "failed to set OperandRequest %s as the owner of Secret %s", requestInstance.Name, targetName) } @@ -310,6 +310,14 @@ func (r *Reconciler) copySecret(ctx context.Context, sourceName, targetName, sou if err := r.Client.Get(ctx, types.NamespacedName{Namespace: targetNs, Name: targetName}, existingSecret); err != nil { return false, errors.Wrapf(err, "failed to get secret %s/%s", targetNs, targetName) } + + // Copy the owner reference from the existing secret to the new secret + secretCopy.SetOwnerReferences(existingSecret.GetOwnerReferences()) + // Set the OperandRequest as the owner of the new Secret + if err := controllerutil.SetOwnerReference(requestInstance, secretCopy, r.Scheme); err != nil { + return false, errors.Wrapf(err, "failed to set OperandRequest %s as the owner of Secret %s", requestInstance.Name, targetName) + } + if needUpdate := util.CompareSecret(secretCopy, existingSecret); needUpdate { podRefreshment = true if err := r.Update(ctx, secretCopy); err != nil { @@ -389,8 +397,8 @@ func (r *Reconciler) copyConfigmap(ctx context.Context, sourceName, targetName, Data: cm.Data, BinaryData: cm.BinaryData, } - // Set the OperandRequest as the controller of the configmap - if err := controllerutil.SetControllerReference(requestInstance, cmCopy, r.Scheme); err != nil { + // Set OperandRequest as the owners of the configmap + if err := controllerutil.SetOwnerReference(requestInstance, cmCopy, r.Scheme); err != nil { return false, errors.Wrapf(err, "failed to set OperandRequest %s as the owner of ConfigMap %s", requestInstance.Name, sourceName) } @@ -403,6 +411,14 @@ func (r *Reconciler) copyConfigmap(ctx context.Context, sourceName, targetName, if err := r.Client.Get(ctx, types.NamespacedName{Namespace: targetNs, Name: targetName}, existingCm); err != nil { return false, errors.Wrapf(err, "failed to get ConfigMap %s/%s", targetNs, targetName) } + + // Copy the owner reference from the existing secret to the new configmap + cmCopy.SetOwnerReferences(existingCm.GetOwnerReferences()) + // Set the OperandRequest as the owner of the new configmap + if err := controllerutil.SetOwnerReference(requestInstance, cmCopy, r.Scheme); err != nil { + return false, errors.Wrapf(err, "failed to set OperandRequest %s as the owner of ConfigMap %s", requestInstance.Name, targetName) + } + if needUpdate := util.CompareConfigMap(cmCopy, existingCm); needUpdate { podRefreshment = true if err := r.Update(ctx, cmCopy); err != nil { diff --git a/controllers/operandrequest/reconcile_operand.go b/controllers/operandrequest/reconcile_operand.go index 1e8ffc43..28a3cff1 100644 --- a/controllers/operandrequest/reconcile_operand.go +++ b/controllers/operandrequest/reconcile_operand.go @@ -417,7 +417,7 @@ func (r *Reconciler) reconcileCRwithRequest(ctx context.Context, requestInstance crFromRequest.SetNamespace(requestKey.Namespace) crFromRequest.SetAPIVersion(operand.APIVersion) crFromRequest.SetKind(operand.Kind) - // Set the OperandRequest as the controller of the CR from request + // Set the OperandRequest as the owner of the CR from request if err := controllerutil.SetOwnerReference(requestInstance, &crFromRequest, r.Scheme); err != nil { merr.Add(errors.Wrapf(err, "failed to set ownerReference for custom resource %s/%s", requestKey.Namespace, name)) } diff --git a/controllers/util/util.go b/controllers/util/util.go index 5846d374..728e0f72 100644 --- a/controllers/util/util.go +++ b/controllers/util/util.go @@ -282,11 +282,18 @@ func EnsureLabelsForService(s *corev1.Service, labels map[string]string) { } func CompareSecret(secret *corev1.Secret, existingSecret *corev1.Secret) (needUpdate bool) { - return !equality.Semantic.DeepEqual(secret.GetLabels(), existingSecret.GetLabels()) || !equality.Semantic.DeepEqual(secret.Type, existingSecret.Type) || !equality.Semantic.DeepEqual(secret.Data, existingSecret.Data) || !equality.Semantic.DeepEqual(secret.StringData, existingSecret.StringData) + return !equality.Semantic.DeepEqual(secret.GetLabels(), existingSecret.GetLabels()) || + !equality.Semantic.DeepEqual(secret.Type, existingSecret.Type) || + !equality.Semantic.DeepEqual(secret.Data, existingSecret.Data) || + !equality.Semantic.DeepEqual(secret.StringData, existingSecret.StringData) || + !equality.Semantic.DeepEqual(secret.GetOwnerReferences(), existingSecret.GetOwnerReferences()) } func CompareConfigMap(configMap *corev1.ConfigMap, existingConfigMap *corev1.ConfigMap) (needUpdate bool) { - return !equality.Semantic.DeepEqual(configMap.GetLabels(), existingConfigMap.GetLabels()) || !equality.Semantic.DeepEqual(configMap.Data, existingConfigMap.Data) || !equality.Semantic.DeepEqual(configMap.BinaryData, existingConfigMap.BinaryData) + return !equality.Semantic.DeepEqual(configMap.GetLabels(), existingConfigMap.GetLabels()) || + !equality.Semantic.DeepEqual(configMap.Data, existingConfigMap.Data) || + !equality.Semantic.DeepEqual(configMap.BinaryData, existingConfigMap.BinaryData) || + !equality.Semantic.DeepEqual(configMap.GetOwnerReferences(), existingConfigMap.GetOwnerReferences()) } // SanitizeObjectString takes a string, i.e. .metadata.namespace, and a K8s object From f5da287557589f70ca3bda6f563ff7c85e69f81f Mon Sep 17 00:00:00 2001 From: Daniel Fan Date: Tue, 5 Dec 2023 13:52:30 -0500 Subject: [PATCH 065/179] Enhance error handling for uninstall procedure (#1002) Signed-off-by: Daniel Fan --- controllers/operandrequest/reconcile_operand.go | 10 ++++++++-- controllers/operandrequest/reconcile_operator.go | 1 + controllers/operator/manager.go | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/controllers/operandrequest/reconcile_operand.go b/controllers/operandrequest/reconcile_operand.go index 28a3cff1..ca4b1187 100644 --- a/controllers/operandrequest/reconcile_operand.go +++ b/controllers/operandrequest/reconcile_operand.go @@ -567,6 +567,7 @@ func (r *Reconciler) deleteAllCustomResource(ctx context.Context, csv *olmv1alph wg.Wait() if len(merr.Errors) != 0 { + klog.Errorf("Failed to delete custom resource from OperandRequest for operator %s", operandName) return merr } @@ -621,6 +622,7 @@ func (r *Reconciler) deleteAllCustomResource(ctx context.Context, csv *olmv1alph r.Mutex.Lock() defer r.Mutex.Unlock() merr.Add(err) + return } }() } @@ -631,6 +633,7 @@ func (r *Reconciler) deleteAllCustomResource(ctx context.Context, csv *olmv1alph } wg.Wait() if len(merr.Errors) != 0 { + klog.Errorf("Failed to delete custom resource from OperandConfig for operator %s", operandName) return merr } @@ -839,7 +842,7 @@ func (r *Reconciler) deleteCustomResource(ctx context.Context, existingCR unstru if strings.EqualFold(kind, "OperandRequest") { return true, nil } - klog.V(3).Infof("Waiting for CR %s is removed ...", kind) + klog.V(3).Infof("Waiting for CR %s to be removed ...", kind) err := r.Client.Get(ctx, types.NamespacedName{ Name: name, Namespace: namespace, @@ -1135,7 +1138,10 @@ func (r *Reconciler) deleteK8sResource(ctx context.Context, existingK8sRes unstr return errors.Wrapf(err, "failed to delete k8s resource -- Kind: %s, NamespacedName: %s/%s", kind, namespace, name) } err = wait.PollImmediate(constant.DefaultCRDeletePeriod, constant.DefaultCRDeleteTimeout, func() (bool, error) { - klog.V(3).Infof("Waiting for k8s resource %s is removed ...", kind) + if strings.EqualFold(kind, "OperandRequest") { + return true, nil + } + klog.V(3).Infof("Waiting for resource %s to be removed ...", kind) err := r.Client.Get(ctx, types.NamespacedName{ Name: name, Namespace: namespace, diff --git a/controllers/operandrequest/reconcile_operator.go b/controllers/operandrequest/reconcile_operator.go index 1a3832cd..0c237d79 100644 --- a/controllers/operandrequest/reconcile_operator.go +++ b/controllers/operandrequest/reconcile_operator.go @@ -519,6 +519,7 @@ func (r *Reconciler) absentOperatorsAndOperands(ctx context.Context, requestInst r.Mutex.Lock() defer r.Mutex.Unlock() merr.Add(err) + return // return here to avoid removing the operand from remainingOperands } requestInstance.RemoveServiceStatus(fmt.Sprintf("%v", o), &r.Mutex) (*remainingOperands).Remove(o) diff --git a/controllers/operator/manager.go b/controllers/operator/manager.go index 4848d98c..c4e57bd1 100644 --- a/controllers/operator/manager.go +++ b/controllers/operator/manager.go @@ -60,7 +60,7 @@ func NewODLMOperator(mgr manager.Manager, name string) *ODLMOperator { Config: mgr.GetConfig(), Recorder: mgr.GetEventRecorderFor(name), Scheme: mgr.GetScheme(), - MaxConcurrentReconciles: 5, + MaxConcurrentReconciles: 10, } } From 964c0ee93472377b9f9f6157c8c5a2264eebf459 Mon Sep 17 00:00:00 2001 From: Daniel Fan Date: Tue, 5 Dec 2023 14:09:29 -0500 Subject: [PATCH 066/179] Skip reconciling CRs for operators marked as no-op (#1001) Signed-off-by: Daniel Fan --- controllers/operandrequest/reconcile_operand.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/controllers/operandrequest/reconcile_operand.go b/controllers/operandrequest/reconcile_operand.go index ca4b1187..12585e50 100644 --- a/controllers/operandrequest/reconcile_operand.go +++ b/controllers/operandrequest/reconcile_operand.go @@ -31,6 +31,7 @@ import ( olmv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1" "github.com/pkg/errors" authorizationv1 "k8s.io/api/authorization/v1" + corev1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -78,6 +79,12 @@ func (r *Reconciler) reconcileOperand(ctx context.Context, requestInstance *oper continue } + if opdRegistry.InstallMode == operatorv1alpha1.InstallModeNoop { + requestInstance.SetNoSuitableRegistryCondition(registryKey.String(), opdRegistry.Name+" is in maintenance status", operatorv1alpha1.ResourceTypeOperandRegistry, corev1.ConditionTrue, &r.Mutex) + requestInstance.SetMemberStatus(operand.Name, operatorv1alpha1.OperatorRunning, operatorv1alpha1.ServiceRunning, &r.Mutex) + continue + } + operatorName := opdRegistry.Name klog.V(3).Info("Looking for csv for the operator: ", operatorName) From 095c558b7cc6e977af87841dbd304c5fcfa2cd95 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 12 Dec 2023 04:29:34 +0800 Subject: [PATCH 067/179] build(deps): bump golang from 1.21.3-bullseye to 1.21.5-bullseye (#1004) Bumps golang from 1.21.3-bullseye to 1.21.5-bullseye. --- updated-dependencies: - dependency-name: golang dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 0464784b..17296df6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # Build the manager binary -FROM golang:1.21.3-bullseye as builder +FROM golang:1.21.5-bullseye as builder ARG GOARCH WORKDIR /workspace From 918193f41d334d9d9713aaf9b0d633810647137d Mon Sep 17 00:00:00 2001 From: YuChen Shen <59578388+YCShen1010@users.noreply.github.com> Date: Mon, 11 Dec 2023 15:59:35 -0500 Subject: [PATCH 068/179] Bump ODLM to 4.2.3 for 4.4 release (#1005) Signed-off-by: YuChen --- Makefile | 2 +- ...eployment-lifecycle-manager.clusterserviceversion.yaml | 8 ++++---- ...eployment-lifecycle-manager.clusterserviceversion.yaml | 4 ++-- version/version.go | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Makefile b/Makefile index 3e59982f..45e770a4 100644 --- a/Makefile +++ b/Makefile @@ -84,7 +84,7 @@ OPERATOR_IMAGE_NAME ?= odlm # Current Operator bundle image name BUNDLE_IMAGE_NAME ?= odlm-operator-bundle # Current Operator version -OPERATOR_VERSION ?= 4.2.2 +OPERATOR_VERSION ?= 4.2.3 # Kind cluster name KIND_CLUSTER_NAME ?= "odlm" diff --git a/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml b/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml index ca8773ff..8d8b2cc4 100644 --- a/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml +++ b/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml @@ -132,7 +132,7 @@ metadata: createdAt: "2023-11-03T17:30:05Z" description: The Operand Deployment Lifecycle Manager provides a Kubernetes CRD-based API to manage the lifecycle of operands. nss.operator.ibm.com/managed-operators: ibm-odlm - olm.skipRange: '>=1.2.0 <4.2.2' + olm.skipRange: '>=1.2.0 <4.2.3' operators.openshift.io/infrastructure-features: '["disconnected"]' operators.operatorframework.io/builder: operator-sdk-v1.29.0 operators.operatorframework.io/project_layout: go.kubebuilder.io/v3 @@ -143,7 +143,7 @@ metadata: operatorframework.io/arch.ppc64le: supported operatorframework.io/arch.s390x: supported operatorframework.io/os.linux: supported - name: operand-deployment-lifecycle-manager.v4.2.2 + name: operand-deployment-lifecycle-manager.v4.2.3 namespace: placeholder spec: apiservicedefinitions: {} @@ -786,7 +786,7 @@ spec: minKubeVersion: 1.19.0 provider: name: IBM - version: 4.2.2 + version: 4.2.3 relatedImages: - - image: icr.io/cpopen/odlm:4.2.2 + - image: icr.io/cpopen/odlm:4.2.3 name: ODLM_IMAGE diff --git a/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml b/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml index 12b80865..62998b8a 100644 --- a/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml +++ b/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml @@ -11,7 +11,7 @@ metadata: description: The Operand Deployment Lifecycle Manager provides a Kubernetes CRD-based API to manage the lifecycle of operands. nss.operator.ibm.com/managed-operators: ibm-odlm - olm.skipRange: '>=1.2.0 <4.2.2' + olm.skipRange: '>=1.2.0 <4.2.3' operators.openshift.io/infrastructure-features: '["disconnected"]' operators.operatorframework.io/builder: operator-sdk-v1.2.0 operators.operatorframework.io/project_layout: go.kubebuilder.io/v2 @@ -467,6 +467,6 @@ spec: provider: name: IBM relatedImages: - - image: icr.io/cpopen/odlm:4.2.2 + - image: icr.io/cpopen/odlm:4.2.3 name: ODLM_IMAGE version: 0.0.0 diff --git a/version/version.go b/version/version.go index 84c11b15..16a1a631 100644 --- a/version/version.go +++ b/version/version.go @@ -17,5 +17,5 @@ package version var ( - Version = "4.2.2" + Version = "4.2.3" ) From 7f9f8d368a90ab9faff8a58fe54df79e7bad5888 Mon Sep 17 00:00:00 2001 From: Travis CI User Date: Tue, 2 Jan 2024 20:05:58 +0000 Subject: [PATCH 069/179] Trigger build with new base image --- base_images.json | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/base_images.json b/base_images.json index 0038c5ad..f75c851d 100644 --- a/base_images.json +++ b/base_images.json @@ -7,7 +7,7 @@ "destStage": "edge", "destNamespace": "build-images", "destImage": "ubi8", - "tag": "8.8-1067.1698056881", + "tag": "8.9-1028", "updatePackages": [] }, { @@ -18,7 +18,7 @@ "destStage": "edge", "destNamespace": "build-images", "destImage": "ubi8-minimal", - "tag": "8.8-1072.1697626218", + "tag": "8.9-1029", "updatePackages": [] }, { @@ -29,7 +29,7 @@ "destStage": "edge", "destNamespace": "build-images", "destImage": "ubi9-micro", - "tag": "9.2-15.1696515526", + "tag": "9.3-9", "updatePackages": [] }, { @@ -40,21 +40,28 @@ "destStage": "edge", "destNamespace": "build-images", "destImage": "helm-operator", - "tag": "v1.32.0", + "tag": "v1.33.0", "updatePackages": [] }, { "imageType": "node", "sourceImage": "ubi8-minimal", - "sourceTag": "8.8-1072.1697626218", + "sourceTag": "8.9-1029", "destImage": "node-v18-ubi8-minimal", - "nodeVersion": "18.18.2" + "nodeVersion": "18.19.0" + }, + { + "imageType": "node", + "sourceImage": "ubi8-minimal", + "sourceTag": "8.9-1029", + "destImage": "node-v20-ubi8-minimal", + "nodeVersion": "20.10.0" }, { "imageType": "liberty", "sourceImage": "node-v18-ubi8-minimal", - "sourceTag": "18.18.2_8.8-1072.1697626218", + "sourceTag": "18.18.2_8.9-1029", "destImage": "liberty11-ubi8-minimal", - "libertyVersion": "23.0.0.10" + "libertyVersion": "23.0.0.12" } ] From 3611ea59abe2b430f3d754e614ba2c1e7ce847ec Mon Sep 17 00:00:00 2001 From: Daniel Fan Date: Thu, 11 Jan 2024 11:27:38 -0500 Subject: [PATCH 070/179] Allow resources to be updated by ODLM when control label is specified (#1010) Signed-off-by: Daniel Fan --- controllers/operandrequest/reconcile_operand.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/controllers/operandrequest/reconcile_operand.go b/controllers/operandrequest/reconcile_operand.go index 12585e50..32fadb0c 100644 --- a/controllers/operandrequest/reconcile_operand.go +++ b/controllers/operandrequest/reconcile_operand.go @@ -269,7 +269,7 @@ func (r *Reconciler) reconcileCRwithConfig(ctx context.Context, service *operato merr.Add(err) } } else { - if r.CheckLabel(k8sRes, map[string]string{constant.OpreqLabel: "true"}) && res.Force { + if res.Force { // Update k8s resource klog.V(3).Info("Found existing k8s resource: " + res.Name) if err := r.updateK8sResource(ctx, k8sRes, res.Data, res.Labels, res.Annotations); err != nil { @@ -992,7 +992,7 @@ func (r *Reconciler) updateK8sResource(ctx context.Context, existingK8sRes unstr if err != nil { return errors.Wrapf(err, "failed to get k8s resource -- Kind: %s, NamespacedName: %s/%s", kind, namespace, name) } - if !r.CheckLabel(existingK8sRes, map[string]string{constant.OpreqLabel: "true"}) { + if !r.CheckLabel(existingK8sRes, map[string]string{constant.OpreqLabel: "true"}) && (newLabels == nil || newLabels[constant.OpreqLabel] != "true") { return nil } @@ -1050,7 +1050,7 @@ func (r *Reconciler) updateK8sResource(ctx context.Context, existingK8sRes unstr return false, errors.Wrapf(err, "failed to get k8s resource -- Kind: %s, NamespacedName: %s/%s", kind, namespace, name) } - if !r.CheckLabel(existingK8sRes, map[string]string{constant.OpreqLabel: "true"}) { + if !r.CheckLabel(existingK8sRes, map[string]string{constant.OpreqLabel: "true"}) && (newLabels == nil || newLabels[constant.OpreqLabel] != "true") { return true, nil } From 50a7c57a838bd62e37c8054307388cdc479b40ac Mon Sep 17 00:00:00 2001 From: Daniel Fan Date: Mon, 29 Jan 2024 17:36:18 -0500 Subject: [PATCH 071/179] Bump ODLM to 4.3.0 for CS 4.5 release (#1011) Signed-off-by: Daniel Fan --- Makefile | 2 +- ...eployment-lifecycle-manager.clusterserviceversion.yaml | 8 ++++---- ...eployment-lifecycle-manager.clusterserviceversion.yaml | 4 ++-- version/version.go | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Makefile b/Makefile index 45e770a4..49b1bd30 100644 --- a/Makefile +++ b/Makefile @@ -84,7 +84,7 @@ OPERATOR_IMAGE_NAME ?= odlm # Current Operator bundle image name BUNDLE_IMAGE_NAME ?= odlm-operator-bundle # Current Operator version -OPERATOR_VERSION ?= 4.2.3 +OPERATOR_VERSION ?= 4.3.0 # Kind cluster name KIND_CLUSTER_NAME ?= "odlm" diff --git a/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml b/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml index 8d8b2cc4..e08a5524 100644 --- a/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml +++ b/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml @@ -132,7 +132,7 @@ metadata: createdAt: "2023-11-03T17:30:05Z" description: The Operand Deployment Lifecycle Manager provides a Kubernetes CRD-based API to manage the lifecycle of operands. nss.operator.ibm.com/managed-operators: ibm-odlm - olm.skipRange: '>=1.2.0 <4.2.3' + olm.skipRange: '>=1.2.0 <4.3.0' operators.openshift.io/infrastructure-features: '["disconnected"]' operators.operatorframework.io/builder: operator-sdk-v1.29.0 operators.operatorframework.io/project_layout: go.kubebuilder.io/v3 @@ -143,7 +143,7 @@ metadata: operatorframework.io/arch.ppc64le: supported operatorframework.io/arch.s390x: supported operatorframework.io/os.linux: supported - name: operand-deployment-lifecycle-manager.v4.2.3 + name: operand-deployment-lifecycle-manager.v4.3.0 namespace: placeholder spec: apiservicedefinitions: {} @@ -786,7 +786,7 @@ spec: minKubeVersion: 1.19.0 provider: name: IBM - version: 4.2.3 + version: 4.3.0 relatedImages: - - image: icr.io/cpopen/odlm:4.2.3 + - image: icr.io/cpopen/odlm:4.3.0 name: ODLM_IMAGE diff --git a/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml b/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml index 62998b8a..bca8ebc5 100644 --- a/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml +++ b/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml @@ -11,7 +11,7 @@ metadata: description: The Operand Deployment Lifecycle Manager provides a Kubernetes CRD-based API to manage the lifecycle of operands. nss.operator.ibm.com/managed-operators: ibm-odlm - olm.skipRange: '>=1.2.0 <4.2.3' + olm.skipRange: '>=1.2.0 <4.3.0' operators.openshift.io/infrastructure-features: '["disconnected"]' operators.operatorframework.io/builder: operator-sdk-v1.2.0 operators.operatorframework.io/project_layout: go.kubebuilder.io/v2 @@ -467,6 +467,6 @@ spec: provider: name: IBM relatedImages: - - image: icr.io/cpopen/odlm:4.2.3 + - image: icr.io/cpopen/odlm:4.3.0 name: ODLM_IMAGE version: 0.0.0 diff --git a/version/version.go b/version/version.go index 16a1a631..d494af85 100644 --- a/version/version.go +++ b/version/version.go @@ -17,5 +17,5 @@ package version var ( - Version = "4.2.3" + Version = "4.3.0" ) From 79d96a893e9b1743a5aea6bb43e916ebbd779ed6 Mon Sep 17 00:00:00 2001 From: Travis CI User Date: Fri, 2 Feb 2024 14:58:49 +0000 Subject: [PATCH 072/179] Trigger build with new base image --- base_images.json | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/base_images.json b/base_images.json index f75c851d..bbd333b6 100644 --- a/base_images.json +++ b/base_images.json @@ -7,7 +7,7 @@ "destStage": "edge", "destNamespace": "build-images", "destImage": "ubi8", - "tag": "8.9-1028", + "tag": "8.9-1107.1706791207", "updatePackages": [] }, { @@ -18,7 +18,7 @@ "destStage": "edge", "destNamespace": "build-images", "destImage": "ubi8-minimal", - "tag": "8.9-1029", + "tag": "8.9-1108.1706691034", "updatePackages": [] }, { @@ -29,7 +29,7 @@ "destStage": "edge", "destNamespace": "build-images", "destImage": "ubi9-micro", - "tag": "9.3-9", + "tag": "9.3-13", "updatePackages": [] }, { @@ -46,22 +46,22 @@ { "imageType": "node", "sourceImage": "ubi8-minimal", - "sourceTag": "8.9-1029", + "sourceTag": "8.9-1108.1706691034", "destImage": "node-v18-ubi8-minimal", "nodeVersion": "18.19.0" }, { "imageType": "node", "sourceImage": "ubi8-minimal", - "sourceTag": "8.9-1029", + "sourceTag": "8.9-1108.1706691034", "destImage": "node-v20-ubi8-minimal", - "nodeVersion": "20.10.0" + "nodeVersion": "20.11.0" }, { "imageType": "liberty", "sourceImage": "node-v18-ubi8-minimal", - "sourceTag": "18.18.2_8.9-1029", + "sourceTag": "18.19.0_8.9-1108.1706691034", "destImage": "liberty11-ubi8-minimal", - "libertyVersion": "23.0.0.12" + "libertyVersion": "24.0.0.1" } ] From 547117d324d5d56a961bdb66b97fa9204ce541f0 Mon Sep 17 00:00:00 2001 From: Travis CI User Date: Wed, 7 Feb 2024 22:37:04 +0000 Subject: [PATCH 073/179] Trigger build with new base image --- base_images.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/base_images.json b/base_images.json index bbd333b6..f7c696ab 100644 --- a/base_images.json +++ b/base_images.json @@ -18,7 +18,7 @@ "destStage": "edge", "destNamespace": "build-images", "destImage": "ubi8-minimal", - "tag": "8.9-1108.1706691034", + "tag": "8.9-1108.1706795067", "updatePackages": [] }, { @@ -46,21 +46,21 @@ { "imageType": "node", "sourceImage": "ubi8-minimal", - "sourceTag": "8.9-1108.1706691034", + "sourceTag": "8.9-1108.1706795067", "destImage": "node-v18-ubi8-minimal", "nodeVersion": "18.19.0" }, { "imageType": "node", "sourceImage": "ubi8-minimal", - "sourceTag": "8.9-1108.1706691034", + "sourceTag": "8.9-1108.1706795067", "destImage": "node-v20-ubi8-minimal", "nodeVersion": "20.11.0" }, { "imageType": "liberty", "sourceImage": "node-v18-ubi8-minimal", - "sourceTag": "18.19.0_8.9-1108.1706691034", + "sourceTag": "18.19.0_8.9-1108.1706795067", "destImage": "liberty11-ubi8-minimal", "libertyVersion": "24.0.0.1" } From e07f5485a02302009c0e689177a2933f503cefa5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 9 Feb 2024 07:26:26 +0800 Subject: [PATCH 074/179] build(deps): bump golang from 1.21.5-bullseye to 1.22.0-bullseye (#1012) Bumps golang from 1.21.5-bullseye to 1.22.0-bullseye. --- updated-dependencies: - dependency-name: golang dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 17296df6..75de036b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # Build the manager binary -FROM golang:1.21.5-bullseye as builder +FROM golang:1.22.0-bullseye as builder ARG GOARCH WORKDIR /workspace From 01db7ee1b10647abd87d1555d3b1548ed9776445 Mon Sep 17 00:00:00 2001 From: Daniel Fan Date: Fri, 16 Feb 2024 14:12:42 -0500 Subject: [PATCH 075/179] Improve logs on Catalog discovery (#1015) Signed-off-by: Daniel Fan --- controllers/operator/manager.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/controllers/operator/manager.go b/controllers/operator/manager.go index c4e57bd1..30125202 100644 --- a/controllers/operator/manager.go +++ b/controllers/operator/manager.go @@ -130,7 +130,6 @@ func (s sortableCatalogSource) Less(i, j int) bool { } // Compare catalogsource priorities first, higher priority comes first iPriority, jPriority := s[i].Priority, s[j].Priority - klog.V(2).Infof("iPriority: %v, jPriority: %v", iPriority, jPriority) if iPriority != jPriority { return iPriority > jPriority } @@ -179,8 +178,12 @@ func (m *ODLMOperator) GetCatalogSourceFromPackage(ctx context.Context, packageN klog.Errorf("Not found PackageManifest %s in the namespace %s has channel %s", packageName, namespace, channel) return "", "", nil } + klog.V(2).Infof("Found %v CatalogSources for PackageManifest %s in the namespace %s has channel %s", len(catalogSourceCandidate), packageName, namespace, channel) // Sort CatalogSources by priority sort.Sort(sortableCatalogSource(catalogSourceCandidate)) + for i, c := range catalogSourceCandidate { + klog.V(2).Infof("The %vth sorted CatalogSource is %s in namespace %s with priority: %v", i, c.Name, c.Namespace, c.Priority) + } return catalogSourceCandidate[0].Name, catalogSourceCandidate[0].Namespace, nil } } From 0e8efe47d5f13e15e5e8df2f5e7ead376b67b241 Mon Sep 17 00:00:00 2001 From: Daniel Fan Date: Fri, 16 Feb 2024 14:35:42 -0500 Subject: [PATCH 076/179] Reduce CPU and Memory usage (#1009) Signed-off-by: Daniel Fan --- controllers/operator/manager.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/controllers/operator/manager.go b/controllers/operator/manager.go index 30125202..f558652e 100644 --- a/controllers/operator/manager.go +++ b/controllers/operator/manager.go @@ -60,7 +60,7 @@ func NewODLMOperator(mgr manager.Manager, name string) *ODLMOperator { Config: mgr.GetConfig(), Recorder: mgr.GetEventRecorderFor(name), Scheme: mgr.GetScheme(), - MaxConcurrentReconciles: 10, + MaxConcurrentReconciles: 3, } } @@ -369,7 +369,7 @@ func (m *ODLMOperator) GetClusterServiceVersion(ctx context.Context, sub *olmv1a Name: csvName, Namespace: csvNamespace, } - if err := m.Client.Get(ctx, csvKey, csv); err != nil { + if err := m.Reader.Get(ctx, csvKey, csv); err != nil { if apierrors.IsNotFound(err) { klog.V(3).Infof("ClusterServiceVersion %s is not ready. Will check it when it is stable", sub.Name) return nil, nil From a73dc9cb961ef991cf45e70fc66d89cf8fe1fd89 Mon Sep 17 00:00:00 2001 From: Daniel Fan Date: Tue, 20 Feb 2024 21:56:46 -0500 Subject: [PATCH 077/179] Prioritize the Catalog which ODLM is deployed from (#1016) Signed-off-by: Daniel Fan --- controllers/operator/manager.go | 55 +++++++++++++++++++++++++++------ 1 file changed, 46 insertions(+), 9 deletions(-) diff --git a/controllers/operator/manager.go b/controllers/operator/manager.go index f558652e..bffc1021 100644 --- a/controllers/operator/manager.go +++ b/controllers/operator/manager.go @@ -76,6 +76,20 @@ func (m *ODLMOperator) GetOperandRegistry(ctx context.Context, key types.Namespa if reg.Annotations != nil && reg.Annotations["excluded-catalogsource"] != "" { excludedCatalogSources = strings.Split(reg.Annotations["excluded-catalogsource"], ",") } + // Get catalog used by ODLM itself by check its own subscription + opts := []client.ListOption{ + client.MatchingLabels{fmt.Sprintf("operators.coreos.com/ibm-odlm.%s", util.GetOperatorNamespace()): ""}, + client.InNamespace(util.GetOperatorNamespace()), + } + odlmCatalog := "" + odlmCatalogNs := "" + odlmSubList := &olmv1alpha1.SubscriptionList{} + if err := m.Reader.List(ctx, odlmSubList, opts...); err != nil || len(odlmSubList.Items) == 0 { + klog.Warningf("No Subscription found for ibm-odlm in the namespace %s", util.GetOperatorNamespace()) + } else { + odlmCatalog = odlmSubList.Items[0].Spec.CatalogSource + odlmCatalogNs = odlmSubList.Items[0].Spec.CatalogSourceNamespace + } for i, o := range reg.Spec.Operators { if o.Scope == "" { @@ -91,7 +105,7 @@ func (m *ODLMOperator) GetOperandRegistry(ctx context.Context, key types.Namespa reg.Spec.Operators[i].Namespace = key.Namespace } if o.SourceName == "" || o.SourceNamespace == "" { - catalogSourceName, catalogSourceNs, err := m.GetCatalogSourceFromPackage(ctx, o.PackageName, reg.Spec.Operators[i].Namespace, o.Channel, key.Namespace, excludedCatalogSources) + catalogSourceName, catalogSourceNs, err := m.GetCatalogSourceFromPackage(ctx, o.PackageName, reg.Spec.Operators[i].Namespace, o.Channel, key.Namespace, odlmCatalog, odlmCatalogNs, excludedCatalogSources) if err != nil { return nil, err } @@ -107,11 +121,13 @@ func (m *ODLMOperator) GetOperandRegistry(ctx context.Context, key types.Namespa } type CatalogSource struct { - Name string - Namespace string - OpNamespace string - RegistryNamespace string - Priority int + Name string + Namespace string + OpNamespace string + RegistryNamespace string + Priority int + ODLMCatalog string + ODLMCatalogNamespace string } type sortableCatalogSource []CatalogSource @@ -120,7 +136,8 @@ func (s sortableCatalogSource) Len() int { return len(s) } func (s sortableCatalogSource) Swap(i, j int) { s[i], s[j] = s[j], s[i] } func (s sortableCatalogSource) Less(i, j int) bool { - // Check if the catalogsource is in the same namespace as operator + // Check if the catalogsource is in the same namespace as operator. + // CatalogSources in operator namespace (private CatalogSource) have a higher priority than those in other namespaces (global CatalogSource). inOpNsI, inOpNsJ := s[i].Namespace == s[i].OpNamespace, s[j].Namespace == s[j].OpNamespace if inOpNsI && !inOpNsJ { return true @@ -128,11 +145,23 @@ func (s sortableCatalogSource) Less(i, j int) bool { if !inOpNsI && inOpNsJ { return false } + // Compare catalogsource priorities first, higher priority comes first iPriority, jPriority := s[i].Priority, s[j].Priority if iPriority != jPriority { return iPriority > jPriority } + + // Check if the catalogsource is in the same catalog as ODLM itself. + // CatalogSources in the same catalog as ODLM have a higher priority than those in other catalogs. + inODLMNsI, inODLMNsJ := s[i].Name == s[i].ODLMCatalog && s[i].Namespace == s[i].ODLMCatalogNamespace, s[j].Name == s[j].ODLMCatalog && s[j].Namespace == s[j].ODLMCatalogNamespace + if inODLMNsI && !inODLMNsJ { + return true + } + if !inODLMNsI && inODLMNsJ { + return false + } + // If their namespaces are the same, then compare the name of the catalogsource if s[i].Namespace == s[j].Namespace { return s[i].Name < s[j].Name @@ -140,7 +169,7 @@ func (s sortableCatalogSource) Less(i, j int) bool { return s[i].Namespace < s[j].Namespace } -func (m *ODLMOperator) GetCatalogSourceFromPackage(ctx context.Context, packageName, namespace, channel, registryNs string, excludedCatalogSources []string) (catalogSourceName string, catalogSourceNs string, err error) { +func (m *ODLMOperator) GetCatalogSourceFromPackage(ctx context.Context, packageName, namespace, channel, registryNs, odlmCatalog, odlmCatalogNs string, excludedCatalogSources []string) (catalogSourceName string, catalogSourceNs string, err error) { packageManifestList := &operatorsv1.PackageManifestList{} opts := []client.ListOption{ client.MatchingFields{"metadata.name": packageName}, @@ -172,7 +201,15 @@ func (m *ODLMOperator) GetCatalogSourceFromPackage(ctx context.Context, packageN klog.Warning(err) continue } - catalogSourceCandidate = append(catalogSourceCandidate, CatalogSource{Name: pm.Status.CatalogSource, Namespace: pm.Status.CatalogSourceNamespace, OpNamespace: namespace, RegistryNamespace: registryNs, Priority: catalogsource.Spec.Priority}) + catalogSourceCandidate = append(catalogSourceCandidate, CatalogSource{ + Name: pm.Status.CatalogSource, + Namespace: pm.Status.CatalogSourceNamespace, + OpNamespace: namespace, + RegistryNamespace: registryNs, + Priority: catalogsource.Spec.Priority, + ODLMCatalog: odlmCatalog, + ODLMCatalogNamespace: odlmCatalogNs, + }) } if len(catalogSourceCandidate) == 0 { klog.Errorf("Not found PackageManifest %s in the namespace %s has channel %s", packageName, namespace, channel) From 0ff537d32a197103a635fc05c5b37afbc8a5aa43 Mon Sep 17 00:00:00 2001 From: Travis CI User Date: Wed, 21 Feb 2024 17:59:03 +0000 Subject: [PATCH 078/179] Trigger build with new base image --- base_images.json | 57 ++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 50 insertions(+), 7 deletions(-) diff --git a/base_images.json b/base_images.json index f7c696ab..b679ff09 100644 --- a/base_images.json +++ b/base_images.json @@ -7,7 +7,7 @@ "destStage": "edge", "destNamespace": "build-images", "destImage": "ubi8", - "tag": "8.9-1107.1706791207", + "tag": "8.9-1136", "updatePackages": [] }, { @@ -18,7 +18,7 @@ "destStage": "edge", "destNamespace": "build-images", "destImage": "ubi8-minimal", - "tag": "8.9-1108.1706795067", + "tag": "8.9-1137", "updatePackages": [] }, { @@ -32,6 +32,28 @@ "tag": "9.3-13", "updatePackages": [] }, + { + "imageType": "external", + "sourceRepo": "registry.access.redhat.com", + "sourceNamespace": "ubi9", + "sourceImage": "ubi", + "destStage": "edge", + "destNamespace": "build-images", + "destImage": "ubi9", + "tag": "9.3-1552", + "updatePackages": [] + }, + { + "imageType": "external", + "sourceRepo": "registry.access.redhat.com", + "sourceNamespace": "ubi9", + "sourceImage": "ubi-minimal", + "destStage": "edge", + "destNamespace": "build-images", + "destImage": "ubi9-minimal", + "tag": "9.3-1552", + "updatePackages": [] + }, { "imageType": "external", "sourceRepo": "quay.io", @@ -46,22 +68,43 @@ { "imageType": "node", "sourceImage": "ubi8-minimal", - "sourceTag": "8.9-1108.1706795067", + "sourceTag": "8.9-1137", "destImage": "node-v18-ubi8-minimal", - "nodeVersion": "18.19.0" + "nodeVersion": "18.19.1" }, { "imageType": "node", "sourceImage": "ubi8-minimal", - "sourceTag": "8.9-1108.1706795067", + "sourceTag": "8.9-1137", "destImage": "node-v20-ubi8-minimal", - "nodeVersion": "20.11.0" + "nodeVersion": "20.11.1" + }, + { + "imageType": "node", + "sourceImage": "ubi9-minimal", + "sourceTag": "9.3-1552", + "destImage": "node-v18-ubi9-minimal", + "nodeVersion": "18.19.1" + }, + { + "imageType": "node", + "sourceImage": "ubi9-minimal", + "sourceTag": "9.3-1552", + "destImage": "node-v20-ubi9-minimal", + "nodeVersion": "20.11.1" }, { "imageType": "liberty", "sourceImage": "node-v18-ubi8-minimal", - "sourceTag": "18.19.0_8.9-1108.1706795067", + "sourceTag": "18.19.1_8.9-1137", "destImage": "liberty11-ubi8-minimal", "libertyVersion": "24.0.0.1" + }, + { + "imageType": "liberty", + "sourceImage": "node-v18-ubi9-minimal", + "sourceTag": "18.19.1_9.3-1552", + "destImage": "liberty11-ubi9-minimal", + "libertyVersion": "24.0.0.1" } ] From 8d3224d59bc889563178685b49007953d74ccf73 Mon Sep 17 00:00:00 2001 From: Daniel Fan Date: Thu, 22 Feb 2024 14:02:48 -0500 Subject: [PATCH 079/179] Read Object from k8s API directly instead of cache to avoid getting outdated object (#1017) Signed-off-by: Daniel Fan --- controllers/operator/manager.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/controllers/operator/manager.go b/controllers/operator/manager.go index bffc1021..b6bd3500 100644 --- a/controllers/operator/manager.go +++ b/controllers/operator/manager.go @@ -689,7 +689,7 @@ func (m *ODLMOperator) GetValueRefFromObject(ctx context.Context, instanceType, var obj unstructured.Unstructured obj.SetAPIVersion(objAPIVersion) obj.SetKind(objKind) - if err := m.Client.Get(ctx, types.NamespacedName{Name: objName, Namespace: objNs}, &obj); err != nil { + if err := m.Reader.Get(ctx, types.NamespacedName{Name: objName, Namespace: objNs}, &obj); err != nil { if apierrors.IsNotFound(err) { klog.V(3).Infof("%s %s/%s is not found", objKind, objNs, objName) return "", nil From 5a98d8754cdf3b4f61857f47346cb23245e6778f Mon Sep 17 00:00:00 2001 From: Daniel Fan Date: Thu, 22 Feb 2024 14:40:47 -0500 Subject: [PATCH 080/179] Skip OperandRequest for OperandBindinfo if the OperandRequest is in the deletion status (#1018) Signed-off-by: Daniel Fan --- controllers/operandbindinfo/operandbindinfo_controller.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/controllers/operandbindinfo/operandbindinfo_controller.go b/controllers/operandbindinfo/operandbindinfo_controller.go index 11bd921d..63d238e7 100644 --- a/controllers/operandbindinfo/operandbindinfo_controller.go +++ b/controllers/operandbindinfo/operandbindinfo_controller.go @@ -179,6 +179,9 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctrl.Re } merr.Add(err) continue + } else if !requestInstance.ObjectMeta.DeletionTimestamp.IsZero() { + klog.Warningf("OperandRequest %s/%s is being deleted, skip the OperandBindInfo %s/%s", requestInstance.Namespace, requestInstance.Name, bindInfoInstance.Namespace, bindInfoInstance.Name) + continue } // Get binding information from OperandRequest secretReq, cmReq := getBindingInfofromRequest(bindInfoInstance, requestInstance) From 8219fb78c087bd8608b5749eddc0fa85fb937541 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 7 Mar 2024 01:24:36 +0800 Subject: [PATCH 081/179] build(deps): bump golang from 1.22.0-bullseye to 1.22.1-bullseye (#1021) Bumps golang from 1.22.0-bullseye to 1.22.1-bullseye. --- updated-dependencies: - dependency-name: golang dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 75de036b..619e163f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # Build the manager binary -FROM golang:1.22.0-bullseye as builder +FROM golang:1.22.1-bullseye as builder ARG GOARCH WORKDIR /workspace From 3970760e2e47a291c070dda47177c42a1101b55a Mon Sep 17 00:00:00 2001 From: YuChen Shen <59578388+YCShen1010@users.noreply.github.com> Date: Wed, 13 Mar 2024 23:30:42 -0400 Subject: [PATCH 082/179] add CertManager and AuditLogging CR cluster permission to ODLM (#1023) Signed-off-by: YuChen --- ...fecycle-manager.clusterserviceversion.yaml | 24 ++++++++++++------- config/rbac/role.yaml | 8 +++++++ 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml b/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml index e08a5524..6527c65d 100644 --- a/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml +++ b/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml @@ -562,14 +562,22 @@ spec: install: spec: clusterPermissions: - - rules: - - apiGroups: - - operators.coreos.com - resources: - - catalogsources - verbs: - - get - serviceAccountName: operand-deployment-lifecycle-manager + - rules: + - apiGroups: + - operators.coreos.com + resources: + - catalogsources + verbs: + - get + - apiGroups: + - operator.ibm.com + resources: + - certmanagers + - auditloggings + verbs: + - get + - delete + serviceAccountName: operand-deployment-lifecycle-manager deployments: - label: app.kubernetes.io/instance: operand-deployment-lifecycle-manager diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml index be1d8f4a..8833a2e1 100644 --- a/config/rbac/role.yaml +++ b/config/rbac/role.yaml @@ -9,6 +9,14 @@ rules: - catalogsources verbs: - get +- apiGroups: + - operator.ibm.com + resources: + - certmanagers + - auditloggings + verbs: + - get + - delete --- apiVersion: rbac.authorization.k8s.io/v1 kind: Role From 6b51bab09271b0ee1a13b9eef8095cd8cbf1c45e Mon Sep 17 00:00:00 2001 From: Henry Li Date: Tue, 19 Mar 2024 17:26:47 -0400 Subject: [PATCH 083/179] updated base image to explicitly use docker.io instead of implied (#1026) Signed-off-by: Henry H Li --- Dockerfile | 2 +- bundle.Dockerfile | 4 ++-- ...nd-deployment-lifecycle-manager.clusterserviceversion.yaml | 2 +- bundle/metadata/annotations.yaml | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Dockerfile b/Dockerfile index 619e163f..2d70dc35 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # Build the manager binary -FROM golang:1.22.1-bullseye as builder +FROM docker.io/golang:1.22.1-bullseye as builder ARG GOARCH WORKDIR /workspace diff --git a/bundle.Dockerfile b/bundle.Dockerfile index c12c2221..6f953fb9 100644 --- a/bundle.Dockerfile +++ b/bundle.Dockerfile @@ -5,8 +5,8 @@ LABEL operators.operatorframework.io.bundle.mediatype.v1=registry+v1 LABEL operators.operatorframework.io.bundle.manifests.v1=manifests/ LABEL operators.operatorframework.io.bundle.metadata.v1=metadata/ LABEL operators.operatorframework.io.bundle.package.v1=ibm-odlm -LABEL operators.operatorframework.io.bundle.channels.v1=v4.2 -LABEL operators.operatorframework.io.bundle.channel.default.v1=v4.2 +LABEL operators.operatorframework.io.bundle.channels.v1=v4.3 +LABEL operators.operatorframework.io.bundle.channel.default.v1=v4.3 LABEL operators.operatorframework.io.metrics.builder=operator-sdk-v1.29.0 LABEL operators.operatorframework.io.metrics.mediatype.v1=metrics+v1 LABEL operators.operatorframework.io.metrics.project_layout=go.kubebuilder.io/v3 diff --git a/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml b/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml index 6527c65d..3d88fcfd 100644 --- a/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml +++ b/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml @@ -129,7 +129,7 @@ metadata: categories: Developer Tools, Monitoring, Logging & Tracing, Security certified: "false" containerImage: icr.io/cpopen/odlm:latest - createdAt: "2023-11-03T17:30:05Z" + createdAt: "2024-03-13T21:38:26Z" description: The Operand Deployment Lifecycle Manager provides a Kubernetes CRD-based API to manage the lifecycle of operands. nss.operator.ibm.com/managed-operators: ibm-odlm olm.skipRange: '>=1.2.0 <4.3.0' diff --git a/bundle/metadata/annotations.yaml b/bundle/metadata/annotations.yaml index 55d60ed0..f3bfce43 100644 --- a/bundle/metadata/annotations.yaml +++ b/bundle/metadata/annotations.yaml @@ -4,8 +4,8 @@ annotations: operators.operatorframework.io.bundle.manifests.v1: manifests/ operators.operatorframework.io.bundle.metadata.v1: metadata/ operators.operatorframework.io.bundle.package.v1: ibm-odlm - operators.operatorframework.io.bundle.channels.v1: v4.2 - operators.operatorframework.io.bundle.channel.default.v1: v4.2 + operators.operatorframework.io.bundle.channels.v1: v4.3 + operators.operatorframework.io.bundle.channel.default.v1: v4.3 operators.operatorframework.io.metrics.builder: operator-sdk-v1.29.0 operators.operatorframework.io.metrics.mediatype.v1: metrics+v1 operators.operatorframework.io.metrics.project_layout: go.kubebuilder.io/v3 From 5c0f9c864ebd9499921910e694fbb556bed19b01 Mon Sep 17 00:00:00 2001 From: Daniel Fan Date: Wed, 20 Mar 2024 00:09:47 -0400 Subject: [PATCH 084/179] Introduce OwnReference API (#1025) * Introduce OwnReference API Signed-off-by: Daniel Fan * Enable OwnerReference API for resources created by OperandConfig Signed-off-by: Daniel Fan --------- Signed-off-by: Daniel Fan --- Makefile | 8 +- api/v1alpha1/operandconfig_types.go | 23 ++++ bundle.Dockerfile | 2 +- ...fecycle-manager.clusterserviceversion.yaml | 10 +- .../operator.ibm.com_operandconfigs.yaml | 30 +++++ bundle/metadata/annotations.yaml | 2 +- .../operator.ibm.com_operandconfigs.yaml | 30 +++++ ...fecycle-manager.clusterserviceversion.yaml | 8 +- .../operandrequest/reconcile_operand.go | 45 ++++++- .../operandrequest/reconcile_operand_test.go | 118 ++++++++++++++++++ go.mod | 5 +- go.sum | 5 +- 12 files changed, 264 insertions(+), 22 deletions(-) create mode 100644 controllers/operandrequest/reconcile_operand_test.go diff --git a/Makefile b/Makefile index 49b1bd30..c42fb8d3 100644 --- a/Makefile +++ b/Makefile @@ -35,7 +35,7 @@ VERSION ?= $(shell git describe --exact-match 2> /dev/null || \ RELEASE_VERSION ?= $(shell cat ./version/version.go | grep "Version =" | awk '{ print $$3}' | tr -d '"') LATEST_VERSION ?= latest OPERATOR_SDK_VERSION=v1.32.0 -YQ_VERSION=v4.17.2 +YQ_VERSION=v4.42.1 DEFAULT_CHANNEL ?= v$(shell cat ./version/version.go | grep "Version =" | awk '{ print $$3}' | tr -d '"' | cut -d '.' -f1,2) CHANNELS ?= $(DEFAULT_CHANNEL) @@ -208,14 +208,14 @@ bundle-manifests: $(KUSTOMIZE) build config/manifests | $(OPERATOR_SDK) generate bundle \ -q --overwrite --version $(OPERATOR_VERSION) $(BUNDLE_METADATA_OPTS) $(OPERATOR_SDK) bundle validate ./bundle - $(YQ) eval-all -i '.spec.relatedImages = load("config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml").spec.relatedImages' bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml + $(YQ) eval-all -i '.spec.relatedImages |= load("config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml").spec.relatedImages' bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml @# Need to replace fields this way to avoid changing PROJECT name and CSV file name, which may or may not impact CICD automation $(YQ) e -i '.annotations["operators.operatorframework.io.bundle.package.v1"] = "ibm-odlm"' bundle/metadata/annotations.yaml sed -i'' s/operand-deployment-lifecycle-manager/ibm-odlm/ bundle.Dockerfile -generate-all: manifests kustomize operator-sdk ## Generate bundle manifests, metadata and package manifests +generate-all: yq manifests kustomize operator-sdk ## Generate bundle manifests, metadata and package manifests $(OPERATOR_SDK) generate kustomize manifests -q - - make bundle-manifests CHANNELS=v4.2 DEFAULT_CHANNEL=v4.2 + - make bundle-manifests CHANNELS=v4.3 DEFAULT_CHANNEL=v4.3 ##@ Test diff --git a/api/v1alpha1/operandconfig_types.go b/api/v1alpha1/operandconfig_types.go index 3c124ed5..8f8370a0 100644 --- a/api/v1alpha1/operandconfig_types.go +++ b/api/v1alpha1/operandconfig_types.go @@ -49,6 +49,7 @@ type ConfigService struct { Resources []ConfigResource `json:"resources,omitempty"` } +// +kubebuilder:pruning:PreserveUnknownFields // ConfigResource defines the resource needed for the service type ConfigResource struct { // Name is the resource name. @@ -75,6 +76,28 @@ type ConfigResource struct { // +nullable // +optional Data *runtime.RawExtension `json:"data,omitempty"` + // OwnerReferences is the list of owner references. + // +optional + OwnerReferences []OwnerReference `json:"ownerReferences,omitempty"` +} + +type OwnerReference struct { + // API version of the referent. + APIVersion string `json:"apiVersion"` + // Kind of the referent. + Kind string `json:"kind"` + // Name of the referent. + Name string `json:"name"` + // If true, this reference points to the managing controller. + // Default is false. + // +optional + Controller *bool `json:"controller,omitempty"` + // If true, AND if the owner has the "foregroundDeletion" finalizer, then + // the owner cannot be deleted from the key-value store until this + // reference is removed. + // Defaults to false. + // +optional + BlockOwnerDeletion *bool `json:"blockOwnerDeletion,omitempty"` } // OperandConfigStatus defines the observed state of OperandConfig. diff --git a/bundle.Dockerfile b/bundle.Dockerfile index 6f953fb9..162e5db1 100644 --- a/bundle.Dockerfile +++ b/bundle.Dockerfile @@ -7,7 +7,7 @@ LABEL operators.operatorframework.io.bundle.metadata.v1=metadata/ LABEL operators.operatorframework.io.bundle.package.v1=ibm-odlm LABEL operators.operatorframework.io.bundle.channels.v1=v4.3 LABEL operators.operatorframework.io.bundle.channel.default.v1=v4.3 -LABEL operators.operatorframework.io.metrics.builder=operator-sdk-v1.29.0 +LABEL operators.operatorframework.io.metrics.builder=operator-sdk-v1.32.0 LABEL operators.operatorframework.io.metrics.mediatype.v1=metrics+v1 LABEL operators.operatorframework.io.metrics.project_layout=go.kubebuilder.io/v3 diff --git a/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml b/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml index 3d88fcfd..b85d3e1d 100644 --- a/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml +++ b/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml @@ -134,7 +134,7 @@ metadata: nss.operator.ibm.com/managed-operators: ibm-odlm olm.skipRange: '>=1.2.0 <4.3.0' operators.openshift.io/infrastructure-features: '["disconnected"]' - operators.operatorframework.io/builder: operator-sdk-v1.29.0 + operators.operatorframework.io/builder: operator-sdk-v1.32.0 operators.operatorframework.io/project_layout: go.kubebuilder.io/v3 repository: https://github.com/IBM/operand-deployment-lifecycle-manager support: IBM @@ -149,7 +149,7 @@ spec: apiservicedefinitions: {} customresourcedefinitions: owned: - - description: OperandBindInfo is the Schema for the operandbindinfoes API. Documentation For additional details regarding install parameters check https://ibm.biz/icpfs39install. License By installing this product you accept the license terms https://ibm.biz/icpfs39license + - description: OperandBindInfo is the Schema for the operandbindinfoes API. displayName: OperandBindInfo kind: OperandBindInfo name: operandbindinfos.operator.ibm.com @@ -160,7 +160,7 @@ spec: x-descriptors: - urn:alm:descriptor:io.kubernetes.phase version: v1alpha1 - - description: OperandConfig is the Schema for the operandconfigs API. Documentation For additional details regarding install parameters check https://ibm.biz/icpfs39install. License By installing this product you accept the license terms https://ibm.biz/icpfs39license + - description: OperandConfig is the Schema for the operandconfigs API. displayName: OperandConfig kind: OperandConfig name: operandconfigs.operator.ibm.com @@ -175,7 +175,7 @@ spec: x-descriptors: - urn:alm:descriptor:io.kubernetes.phase version: v1alpha1 - - description: OperandRegistry is the Schema for the operandregistries API. Documentation For additional details regarding install parameters check https://ibm.biz/icpfs39install. License By installing this product you accept the license terms https://ibm.biz/icpfs39license + - description: OperandRegistry is the Schema for the operandregistries API. displayName: OperandRegistry kind: OperandRegistry name: operandregistries.operator.ibm.com @@ -195,7 +195,7 @@ spec: x-descriptors: - urn:alm:descriptor:io.kubernetes.phase version: v1alpha1 - - description: OperandRequest is the Schema for the operandrequests API. Documentation For additional details regarding install parameters check https://ibm.biz/icpfs39install. License By installing this product you accept the license terms https://ibm.biz/icpfs39license + - description: OperandRequest is the Schema for the operandrequests API. displayName: OperandRequest kind: OperandRequest name: operandrequests.operator.ibm.com diff --git a/bundle/manifests/operator.ibm.com_operandconfigs.yaml b/bundle/manifests/operator.ibm.com_operandconfigs.yaml index e3bf82e4..e30855ab 100644 --- a/bundle/manifests/operator.ibm.com_operandconfigs.yaml +++ b/bundle/manifests/operator.ibm.com_operandconfigs.yaml @@ -102,11 +102,41 @@ spec: namespace: description: Namespace is the namespace of the resource. type: string + ownerReferences: + description: OwnerReferences is the list of owner references. + items: + properties: + apiVersion: + description: API version of the referent. + type: string + blockOwnerDeletion: + description: If true, AND if the owner has the "foregroundDeletion" + finalizer, then the owner cannot be deleted from + the key-value store until this reference is removed. + Defaults to false. + type: boolean + controller: + description: If true, this reference points to the + managing controller. Default is false. + type: boolean + kind: + description: Kind of the referent. + type: string + name: + description: Name of the referent. + type: string + required: + - apiVersion + - kind + - name + type: object + type: array required: - apiVersion - kind - name type: object + x-kubernetes-preserve-unknown-fields: true type: array spec: additionalProperties: diff --git a/bundle/metadata/annotations.yaml b/bundle/metadata/annotations.yaml index f3bfce43..e4758c86 100644 --- a/bundle/metadata/annotations.yaml +++ b/bundle/metadata/annotations.yaml @@ -6,7 +6,7 @@ annotations: operators.operatorframework.io.bundle.package.v1: ibm-odlm operators.operatorframework.io.bundle.channels.v1: v4.3 operators.operatorframework.io.bundle.channel.default.v1: v4.3 - operators.operatorframework.io.metrics.builder: operator-sdk-v1.29.0 + operators.operatorframework.io.metrics.builder: operator-sdk-v1.32.0 operators.operatorframework.io.metrics.mediatype.v1: metrics+v1 operators.operatorframework.io.metrics.project_layout: go.kubebuilder.io/v3 # Annotations for testing. diff --git a/config/crd/bases/operator.ibm.com_operandconfigs.yaml b/config/crd/bases/operator.ibm.com_operandconfigs.yaml index 08a903e7..74d6d140 100644 --- a/config/crd/bases/operator.ibm.com_operandconfigs.yaml +++ b/config/crd/bases/operator.ibm.com_operandconfigs.yaml @@ -100,11 +100,41 @@ spec: namespace: description: Namespace is the namespace of the resource. type: string + ownerReferences: + description: OwnerReferences is the list of owner references. + items: + properties: + apiVersion: + description: API version of the referent. + type: string + blockOwnerDeletion: + description: If true, AND if the owner has the "foregroundDeletion" + finalizer, then the owner cannot be deleted from + the key-value store until this reference is removed. + Defaults to false. + type: boolean + controller: + description: If true, this reference points to the + managing controller. Default is false. + type: boolean + kind: + description: Kind of the referent. + type: string + name: + description: Name of the referent. + type: string + required: + - apiVersion + - kind + - name + type: object + type: array required: - apiVersion - kind - name type: object + x-kubernetes-preserve-unknown-fields: true type: array spec: additionalProperties: diff --git a/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml b/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml index bca8ebc5..744719d0 100644 --- a/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml +++ b/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml @@ -28,7 +28,7 @@ spec: apiservicedefinitions: {} customresourcedefinitions: owned: - - description: OperandBindInfo is the Schema for the operandbindinfoes API. Documentation For additional details regarding install parameters check https://ibm.biz/icpfs39install. License By installing this product you accept the license terms https://ibm.biz/icpfs39license + - description: OperandBindInfo is the Schema for the operandbindinfoes API. displayName: OperandBindInfo kind: OperandBindInfo name: operandbindinfos.operator.ibm.com @@ -39,7 +39,7 @@ spec: x-descriptors: - urn:alm:descriptor:io.kubernetes.phase version: v1alpha1 - - description: OperandConfig is the Schema for the operandconfigs API. Documentation For additional details regarding install parameters check https://ibm.biz/icpfs39install. License By installing this product you accept the license terms https://ibm.biz/icpfs39license + - description: OperandConfig is the Schema for the operandconfigs API. displayName: OperandConfig kind: OperandConfig name: operandconfigs.operator.ibm.com @@ -54,7 +54,7 @@ spec: x-descriptors: - urn:alm:descriptor:io.kubernetes.phase version: v1alpha1 - - description: OperandRegistry is the Schema for the operandregistries API. Documentation For additional details regarding install parameters check https://ibm.biz/icpfs39install. License By installing this product you accept the license terms https://ibm.biz/icpfs39license + - description: OperandRegistry is the Schema for the operandregistries API. displayName: OperandRegistry kind: OperandRegistry name: operandregistries.operator.ibm.com @@ -74,7 +74,7 @@ spec: x-descriptors: - urn:alm:descriptor:io.kubernetes.phase version: v1alpha1 - - description: OperandRequest is the Schema for the operandrequests API. Documentation For additional details regarding install parameters check https://ibm.biz/icpfs39install. License By installing this product you accept the license terms https://ibm.biz/icpfs39license + - description: OperandRequest is the Schema for the operandrequests API. displayName: OperandRequest kind: OperandRequest name: operandrequests.operator.ibm.com diff --git a/controllers/operandrequest/reconcile_operand.go b/controllers/operandrequest/reconcile_operand.go index 32fadb0c..1b938a17 100644 --- a/controllers/operandrequest/reconcile_operand.go +++ b/controllers/operandrequest/reconcile_operand.go @@ -265,14 +265,14 @@ func (r *Reconciler) reconcileCRwithConfig(ctx context.Context, service *operato if err != nil && !apierrors.IsNotFound(err) { merr.Add(errors.Wrapf(err, "failed to get k8s resource %s/%s", k8sResNs, res.Name)) } else if apierrors.IsNotFound(err) { - if err := r.createK8sResource(ctx, k8sRes, res.Data, res.Labels, res.Annotations); err != nil { + if err := r.createK8sResource(ctx, k8sRes, res.Data, res.Labels, res.Annotations, &res.OwnerReferences); err != nil { merr.Add(err) } } else { if res.Force { // Update k8s resource klog.V(3).Info("Found existing k8s resource: " + res.Name) - if err := r.updateK8sResource(ctx, k8sRes, res.Data, res.Labels, res.Annotations); err != nil { + if err := r.updateK8sResource(ctx, k8sRes, res.Data, res.Labels, res.Annotations, &res.OwnerReferences); err != nil { merr.Add(err) } } else { @@ -939,7 +939,7 @@ func (r *Reconciler) checkCustomResource(ctx context.Context, requestInstance *o return nil } -func (r *Reconciler) createK8sResource(ctx context.Context, k8sResTemplate unstructured.Unstructured, k8sResConfig *runtime.RawExtension, newLabels, newAnnotations map[string]string) error { +func (r *Reconciler) createK8sResource(ctx context.Context, k8sResTemplate unstructured.Unstructured, k8sResConfig *runtime.RawExtension, newLabels, newAnnotations map[string]string, ownerReferences *[]operatorv1alpha1.OwnerReference) error { kind := k8sResTemplate.GetKind() name := k8sResTemplate.GetName() namespace := k8sResTemplate.GetNamespace() @@ -959,6 +959,9 @@ func (r *Reconciler) createK8sResource(ctx context.Context, k8sResTemplate unstr r.EnsureLabel(k8sResTemplate, map[string]string{constant.OpreqLabel: "true"}) r.EnsureLabel(k8sResTemplate, newLabels) r.EnsureAnnotation(k8sResTemplate, newAnnotations) + if err := r.setOwnerReferences(ctx, &k8sResTemplate, ownerReferences); err != nil { + return errors.Wrap(err, "failed to set ownerReferences for k8s resource") + } // Create the k8s resource err := r.Create(ctx, &k8sResTemplate) @@ -971,7 +974,7 @@ func (r *Reconciler) createK8sResource(ctx context.Context, k8sResTemplate unstr return nil } -func (r *Reconciler) updateK8sResource(ctx context.Context, existingK8sRes unstructured.Unstructured, k8sResConfig *runtime.RawExtension, newLabels, newAnnotations map[string]string) error { +func (r *Reconciler) updateK8sResource(ctx context.Context, existingK8sRes unstructured.Unstructured, k8sResConfig *runtime.RawExtension, newLabels, newAnnotations map[string]string, ownerReferences *[]operatorv1alpha1.OwnerReference) error { kind := existingK8sRes.GetKind() apiversion := existingK8sRes.GetAPIVersion() name := existingK8sRes.GetName() @@ -1023,7 +1026,7 @@ func (r *Reconciler) updateK8sResource(ctx context.Context, existingK8sRes unstr if err := r.deleteK8sResource(ctx, existingK8sRes, namespace); err != nil { return errors.Wrap(err, "failed to update k8s resource") } - if err := r.createK8sResource(ctx, templatek8sRes, k8sResConfig, newLabels, newAnnotations); err != nil { + if err := r.createK8sResource(ctx, templatek8sRes, k8sResConfig, newLabels, newAnnotations, ownerReferences); err != nil { return errors.Wrap(err, "failed to update k8s resource") } } @@ -1076,6 +1079,9 @@ func (r *Reconciler) updateK8sResource(ctx context.Context, existingK8sRes unstr r.EnsureAnnotation(existingK8sRes, newAnnotations) r.EnsureLabel(existingK8sRes, newLabels) + if err := r.setOwnerReferences(ctx, &existingK8sRes, ownerReferences); err != nil { + return false, errors.Wrapf(err, "failed to set ownerReferences for k8s resource -- Kind: %s, NamespacedName: %s/%s", kind, namespace, name) + } klog.V(2).Infof("updating k8s resource with apiversion: %s, kind: %s, %s/%s", apiversion, kind, namespace, name) @@ -1279,3 +1285,32 @@ func (r *Reconciler) ResourceForKind(gvk schema.GroupVersionKind, namespace stri } return &mapping.Resource, nil } + +func (r *Reconciler) setOwnerReferences(ctx context.Context, controlledRes *unstructured.Unstructured, ownerReferences *[]operatorv1alpha1.OwnerReference) error { + if ownerReferences != nil { + for _, owner := range *ownerReferences { + ownerObj := unstructured.Unstructured{} + ownerObj.SetAPIVersion(owner.APIVersion) + ownerObj.SetKind(owner.Kind) + ownerObj.SetName(owner.Name) + + if err := r.Reader.Get(ctx, types.NamespacedName{ + Name: owner.Name, + Namespace: controlledRes.GetNamespace(), + }, &ownerObj); err != nil { + return errors.Wrapf(err, "failed to get owner object -- Kind: %s, NamespacedName: %s/%s", owner.Kind, controlledRes.GetNamespace(), owner.Name) + } + if owner.Controller != nil && *owner.Controller { + if err := controllerutil.SetControllerReference(&ownerObj, controlledRes, r.Scheme); err != nil { + return errors.Wrapf(err, "failed to set controller ownerReference for k8s resource -- Kind: %s, NamespacedName: %s/%s", controlledRes.GetKind(), controlledRes.GetNamespace(), controlledRes.GetName()) + } + } else { + if err := controllerutil.SetOwnerReference(&ownerObj, controlledRes, r.Scheme); err != nil { + return errors.Wrapf(err, "failed to set ownerReference for k8s resource -- Kind: %s, NamespacedName: %s/%s", controlledRes.GetKind(), controlledRes.GetNamespace(), controlledRes.GetName()) + } + } + klog.Infof("Set %s with name %s as Owner for k8s resource -- Kind: %s, NamespacedName: %s/%s", owner.Kind, owner.Name, controlledRes.GetKind(), controlledRes.GetNamespace(), controlledRes.GetName()) + } + } + return nil +} diff --git a/controllers/operandrequest/reconcile_operand_test.go b/controllers/operandrequest/reconcile_operand_test.go new file mode 100644 index 00000000..408408c6 --- /dev/null +++ b/controllers/operandrequest/reconcile_operand_test.go @@ -0,0 +1,118 @@ +// +// Copyright 2022 IBM Corporation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package operandrequest + +import ( + "context" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/types" + "k8s.io/utils/pointer" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/client/fake" + + operatorv1alpha1 "github.com/IBM/operand-deployment-lifecycle-manager/api/v1alpha1" + deploy "github.com/IBM/operand-deployment-lifecycle-manager/controllers/operator" +) + +type MockReader struct { + mock.Mock +} + +func (m *MockReader) Get(ctx context.Context, key client.ObjectKey, obj client.Object) error { + args := m.Called(ctx, key, obj) + return args.Error(0) +} +func (m *MockReader) List(ctx context.Context, list client.ObjectList, opts ...client.ListOption) error { + args := m.Called(ctx, list, opts) + return args.Error(0) +} + +func TestSetOwnerReferences(t *testing.T) { + // Create a fake client + client := fake.NewClientBuilder().Build() + + // Create a mock reader + reader := &MockReader{} + + // Create a reconciler instance + r := &Reconciler{ + ODLMOperator: &deploy.ODLMOperator{ + Client: client, + Reader: reader, + }, + } + + // Create the controlled resource + controlledRes := &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "v1", + "kind": "Pod", + "metadata": map[string]interface{}{ + "name": "test-pod", + "namespace": "test-namespace", + }, + }, + } + + // Create the owner references + ownerReferences := []operatorv1alpha1.OwnerReference{ + { + APIVersion: "v1", + Kind: "Deployment", + Name: "test-deployment", + Controller: pointer.BoolPtr(true), + }, + { + APIVersion: "v1", + Kind: "Service", + Name: "test-service", + Controller: pointer.BoolPtr(false), + }, + } + + // Mock the Get method of the reader + reader.On("Get", mock.Anything, types.NamespacedName{Name: "test-deployment", Namespace: "test-namespace"}, mock.AnythingOfType("*unstructured.Unstructured")).Return(nil) + reader.On("Get", mock.Anything, types.NamespacedName{Name: "test-service", Namespace: "test-namespace"}, mock.AnythingOfType("*unstructured.Unstructured")).Return(nil) + + // Call the setOwnerReferences function + err := r.setOwnerReferences(context.Background(), controlledRes, &ownerReferences) + + // Assert that there are no errors + assert.NoError(t, err) + + // Assert that the owner references are set correctly + expectedOwnerReferences := []metav1.OwnerReference{ + { + APIVersion: "v1", + Kind: "Deployment", + Name: "test-deployment", + Controller: pointer.BoolPtr(true), + BlockOwnerDeletion: pointer.BoolPtr(true), + }, + { + APIVersion: "v1", + Kind: "Service", + Name: "test-service", + }, + } + assert.Equal(t, expectedOwnerReferences, controlledRes.GetOwnerReferences()) +} diff --git a/go.mod b/go.mod index 1ca8530c..14ca6fa0 100644 --- a/go.mod +++ b/go.mod @@ -15,12 +15,14 @@ require ( github.com/operator-framework/api v0.6.2 github.com/operator-framework/operator-lifecycle-manager v0.17.0 github.com/pkg/errors v0.9.1 + github.com/stretchr/testify v1.9.0 golang.org/x/mod v0.8.0 k8s.io/api v0.24.3 k8s.io/apiextensions-apiserver v0.24.2 k8s.io/apimachinery v0.24.3 k8s.io/client-go v0.24.3 k8s.io/klog v1.0.0 + k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9 sigs.k8s.io/controller-runtime v0.12.3 sigs.k8s.io/kubebuilder v1.0.9-0.20200805184228-f7a3b65dd250 ) @@ -66,6 +68,7 @@ require ( github.com/operator-framework/operator-registry v1.13.6 // indirect github.com/pelletier/go-toml v1.9.5 // indirect github.com/pelletier/go-toml/v2 v2.0.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_golang v1.12.2 // indirect github.com/prometheus/client_model v0.2.0 // indirect github.com/prometheus/common v0.32.1 // indirect @@ -76,6 +79,7 @@ require ( github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/spf13/viper v1.12.0 // indirect + github.com/stretchr/objx v0.5.2 // indirect github.com/subosito/gotenv v1.3.0 // indirect go.uber.org/atomic v1.7.0 // indirect go.uber.org/multierr v1.6.0 // indirect @@ -99,7 +103,6 @@ require ( k8s.io/component-base v0.24.2 // indirect k8s.io/klog/v2 v2.60.1 // indirect k8s.io/kube-openapi v0.0.0-20220627174259-011e075b9cb8 // indirect - k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9 // indirect sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2 // indirect sigs.k8s.io/structured-merge-diff/v4 v4.2.1 // indirect sigs.k8s.io/yaml v1.3.0 // indirect diff --git a/go.sum b/go.sum index 2650bb04..948430fb 100644 --- a/go.sum +++ b/go.sum @@ -917,6 +917,8 @@ github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +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 v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= @@ -926,7 +928,8 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5 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.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/subosito/gotenv v1.3.0 h1:mjC+YW8QpAdXibNi+vNWgzmgBH4+5l5dCXv8cNysBLI= github.com/subosito/gotenv v1.3.0/go.mod h1:YzJjq/33h7nrwdY+iHMhEOEEbW0ovIz0tB6t6PwAXzs= From 702e443e0850d07be2c892ba7885925827456a32 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 22 Mar 2024 12:32:48 +0800 Subject: [PATCH 085/179] build(deps): bump google.golang.org/protobuf from 1.31.0 to 1.33.0 (#1024) Bumps google.golang.org/protobuf from 1.31.0 to 1.33.0. --- updated-dependencies: - dependency-name: google.golang.org/protobuf dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 4 ++-- go.sum | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index 14ca6fa0..d4e17b49 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,6 @@ require ( github.com/stretchr/testify v1.9.0 golang.org/x/mod v0.8.0 k8s.io/api v0.24.3 - k8s.io/apiextensions-apiserver v0.24.2 k8s.io/apimachinery v0.24.3 k8s.io/client-go v0.24.3 k8s.io/klog v1.0.0 @@ -94,12 +93,13 @@ require ( google.golang.org/appengine v1.6.7 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d // indirect google.golang.org/grpc v1.59.0 // indirect - google.golang.org/protobuf v1.31.0 // indirect + google.golang.org/protobuf v1.33.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ini.v1 v1.66.4 // indirect gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect + k8s.io/apiextensions-apiserver v0.24.2 // indirect k8s.io/component-base v0.24.2 // indirect k8s.io/klog/v2 v2.60.1 // indirect k8s.io/kube-openapi v0.0.0-20220627174259-011e075b9cb8 // indirect diff --git a/go.sum b/go.sum index 948430fb..c66505bb 100644 --- a/go.sum +++ b/go.sum @@ -1534,8 +1534,8 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba 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.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= -google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= From b19d2c56f737fd6f5d62ec957785cd7fa7efa1bb Mon Sep 17 00:00:00 2001 From: YuChen Shen <59578388+YCShen1010@users.noreply.github.com> Date: Wed, 27 Mar 2024 12:26:53 -0400 Subject: [PATCH 086/179] Enable deep JSON merging for Kubernetes resources when updating them (#1019) * enable deep json merge for k8s resources Signed-off-by: YuChen * fix deep merge for resource spec Signed-off-by: YuChen * merge for all resrources type Signed-off-by: YuChen * each changed object updated once Signed-off-by: YuChen * compare whole resrouces file instead of spec section Signed-off-by: YuChen * set ownerreferences Signed-off-by: YuChen * ensure ann, label and set owner on updated resrouce Signed-off-by: YuChen --------- Signed-off-by: YuChen --- .../operandrequest/reconcile_operand.go | 89 ++++++++++--------- controllers/util/merge.go | 19 ++++ 2 files changed, 66 insertions(+), 42 deletions(-) diff --git a/controllers/operandrequest/reconcile_operand.go b/controllers/operandrequest/reconcile_operand.go index 1b938a17..35b922b0 100644 --- a/controllers/operandrequest/reconcile_operand.go +++ b/controllers/operandrequest/reconcile_operand.go @@ -28,6 +28,7 @@ import ( "strings" "sync" + "github.com/mohae/deepcopy" olmv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1" "github.com/pkg/errors" authorizationv1 "k8s.io/api/authorization/v1" @@ -771,12 +772,12 @@ func (r *Reconciler) updateCustomResource(ctx context.Context, existingCR unstru // Merge spec from update existing CR and OperandConfig spec updatedCRSpec := util.MergeCR(updatedExistingCRRaw, crConfig) - CRgeneration := existingCR.GetGeneration() - if reflect.DeepEqual(existingCR.Object["spec"], updatedCRSpec) && !forceUpdate { return true, nil } + CRgeneration := existingCR.GetGeneration() + klog.V(2).Infof("updating custom resource with apiversion: %s, kind: %s, %s/%s", apiversion, kind, namespace, name) existingCR.Object["spec"] = updatedCRSpec @@ -1057,61 +1058,65 @@ func (r *Reconciler) updateK8sResource(ctx context.Context, existingK8sRes unstr return true, nil } - // isEqual := r.CheckAnnotation(existingK8sRes, newAnnotations) && r.CheckLabel(existingK8sRes, newLabels) if k8sResConfig != nil { - k8sResConfigDecoded := make(map[string]interface{}) - k8sResConfigUnmarshalErr := json.Unmarshal(k8sResConfig.Raw, &k8sResConfigDecoded) - if k8sResConfigUnmarshalErr != nil { - klog.Errorf("failed to unmarshal k8s Resource Config: %v", k8sResConfigUnmarshalErr) - } - for k, v := range k8sResConfigDecoded { - // isEqual = isEqual && reflect.DeepEqual(existingK8sRes.Object[k], v) - existingK8sRes.Object[k] = v + // Convert existing k8s resource to string + existingK8sResRaw, err := json.Marshal(existingK8sRes.Object) + if err != nil { + klog.Error(err) + return false, err } - } - CRgeneration := existingK8sRes.GetGeneration() + // Merge the existing CR and the CR from the OperandConfig + updatedExistingK8sRes := util.MergeCR(existingK8sResRaw, k8sResConfig.Raw) - // if isEqual { - // return true, nil - // } + // Deep copy the existing k8s resource + originalK8sRes := deepcopy.Copy(existingK8sRes.Object) - r.EnsureAnnotation(existingK8sRes, newAnnotations) - r.EnsureLabel(existingK8sRes, newLabels) - if err := r.setOwnerReferences(ctx, &existingK8sRes, ownerReferences); err != nil { - return false, errors.Wrapf(err, "failed to set ownerReferences for k8s resource -- Kind: %s, NamespacedName: %s/%s", kind, namespace, name) - } + // Update the existing k8s resource with the merged CR + existingK8sRes.Object = updatedExistingK8sRes - klog.V(2).Infof("updating k8s resource with apiversion: %s, kind: %s, %s/%s", apiversion, kind, namespace, name) + r.EnsureAnnotation(existingK8sRes, newAnnotations) + r.EnsureLabel(existingK8sRes, newLabels) + if err := r.setOwnerReferences(ctx, &existingK8sRes, ownerReferences); err != nil { + return false, errors.Wrapf(err, "failed to set ownerReferences for k8s resource -- Kind: %s, NamespacedName: %s/%s", kind, namespace, name) + } - err = r.Update(ctx, &existingK8sRes) + if reflect.DeepEqual(originalK8sRes, existingK8sRes.Object) { + return true, nil + } - if err != nil { - return false, errors.Wrapf(err, "failed to update k8s resource -- Kind: %s, NamespacedName: %s/%s", kind, namespace, name) - } + klog.Infof("updating k8s resource with apiversion: %s, kind: %s, %s/%s", apiversion, kind, namespace, name) - UpdatedK8sRes := unstructured.Unstructured{ - Object: map[string]interface{}{ - "apiVersion": apiversion, - "kind": kind, - }, - } + CRgeneration := existingK8sRes.GetGeneration() - err = r.Client.Get(ctx, types.NamespacedName{ - Name: name, - Namespace: namespace, - }, &UpdatedK8sRes) + err = r.Update(ctx, &existingK8sRes) - if err != nil { - return false, errors.Wrapf(err, "failed to get k8s resource -- Kind: %s, NamespacedName: %s/%s", kind, namespace, name) + if err != nil { + return false, errors.Wrapf(err, "failed to update k8s resource -- Kind: %s, NamespacedName: %s/%s", kind, namespace, name) + } - } + UpdatedK8sRes := unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": apiversion, + "kind": kind, + }, + } - if UpdatedK8sRes.GetGeneration() != CRgeneration { - klog.V(2).Infof("Finish updating the k8s Resource: -- Kind: %s, NamespacedName: %s/%s", kind, namespace, name) - } + err = r.Client.Get(ctx, types.NamespacedName{ + Name: name, + Namespace: namespace, + }, &UpdatedK8sRes) + + if err != nil { + return false, errors.Wrapf(err, "failed to get k8s resource -- Kind: %s, NamespacedName: %s/%s", kind, namespace, name) + } + + if UpdatedK8sRes.GetGeneration() != CRgeneration { + klog.Infof("Finish updating the k8s Resource: -- Kind: %s, NamespacedName: %s/%s", kind, namespace, name) + } + } return true, nil }) diff --git a/controllers/util/merge.go b/controllers/util/merge.go index ab38645b..0a8a5635 100644 --- a/controllers/util/merge.go +++ b/controllers/util/merge.go @@ -72,6 +72,25 @@ func checkKeyBeforeMerging(key string, defaultMap interface{}, changedMap interf checkKeyBeforeMerging(newKey, defaultMapRef[newKey], changedMapRef[newKey], finalMap[key].(map[string]interface{})) } } + case []interface{}: + if changedMap == nil { + finalMap[key] = defaultMap + } else if _, ok := changedMap.([]interface{}); ok { //Check that the changed map value is also a slice []interface + defaultMapRef := defaultMap + changedMapRef := changedMap.([]interface{}) + for i := range defaultMapRef { + if _, ok := defaultMapRef[i].(map[string]interface{}); ok { + if len(changedMapRef) <= i { + finalMap[key] = append(finalMap[key].([]interface{}), defaultMapRef[i]) + } else { + + for newKey := range defaultMapRef[i].(map[string]interface{}) { + checkKeyBeforeMerging(newKey, defaultMapRef[i].(map[string]interface{})[newKey], changedMapRef[i].(map[string]interface{})[newKey], finalMap[key].([]interface{})[i].(map[string]interface{})) + } + } + } + } + } default: //Check if the value was set, otherwise set it if changedMap == nil { From 4857a8c5a1ff0795098e092c01fce7f0ca819464 Mon Sep 17 00:00:00 2001 From: YuChen Shen <59578388+YCShen1010@users.noreply.github.com> Date: Wed, 27 Mar 2024 23:16:54 -0400 Subject: [PATCH 087/179] fix deep copy (#1029) Signed-off-by: YuChen --- controllers/operandrequest/reconcile_operand.go | 8 ++++++-- go.mod | 1 + go.sum | 2 ++ 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/controllers/operandrequest/reconcile_operand.go b/controllers/operandrequest/reconcile_operand.go index 35b922b0..7346cd52 100644 --- a/controllers/operandrequest/reconcile_operand.go +++ b/controllers/operandrequest/reconcile_operand.go @@ -28,7 +28,7 @@ import ( "strings" "sync" - "github.com/mohae/deepcopy" + "github.com/barkimedes/go-deepcopy" olmv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1" "github.com/pkg/errors" authorizationv1 "k8s.io/api/authorization/v1" @@ -1071,7 +1071,11 @@ func (r *Reconciler) updateK8sResource(ctx context.Context, existingK8sRes unstr updatedExistingK8sRes := util.MergeCR(existingK8sResRaw, k8sResConfig.Raw) // Deep copy the existing k8s resource - originalK8sRes := deepcopy.Copy(existingK8sRes.Object) + originalK8sRes, err := deepcopy.Anything(existingK8sRes.Object) + if err != nil { + klog.Error(err) + return false, err + } // Update the existing k8s resource with the merged CR existingK8sRes.Object = updatedExistingK8sRes diff --git a/go.mod b/go.mod index d4e17b49..7961c193 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.20 require ( github.com/IBM/controller-filtered-cache v0.3.5 github.com/IBM/ibm-namespace-scope-operator v1.17.3 + github.com/barkimedes/go-deepcopy v0.0.0-20220514131651-17c30cfc62df github.com/deckarep/golang-set v1.7.1 github.com/google/go-cmp v0.5.9 github.com/jaegertracing/jaeger-operator v1.36.0 diff --git a/go.sum b/go.sum index c66505bb..eca671c1 100644 --- a/go.sum +++ b/go.sum @@ -124,6 +124,8 @@ github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:l github.com/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg= github.com/aws/aws-sdk-go v1.15.11/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0= github.com/aws/aws-sdk-go v1.17.7/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/barkimedes/go-deepcopy v0.0.0-20220514131651-17c30cfc62df h1:GSoSVRLoBaFpOOds6QyY1L8AX7uoY+Ln3BHc22W40X0= +github.com/barkimedes/go-deepcopy v0.0.0-20220514131651-17c30cfc62df/go.mod h1:hiVxq5OP2bUGBRNS3Z/bt/reCLFNbdcST6gISi1fiOM= github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM= github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= From f53293d34278dc459bfc1548aec5f93d451c1a7a Mon Sep 17 00:00:00 2001 From: Henry Li Date: Thu, 28 Mar 2024 00:35:54 -0400 Subject: [PATCH 088/179] scaffolded OperatorConfig API (#1027) * scaffolded OperatorConfig API Signed-off-by: Henry H Li * changed operatorconfig controller to use NewODLMOperator type Signed-off-by: Henry H Li * renamed operatorconfig reconciler to just Reconciler Signed-off-by: Henry H Li --------- Signed-off-by: Henry H Li --- PROJECT | 22 +++- api/v1alpha1/operatorconfig_types.go | 64 +++++++++ api/v1alpha1/zz_generated.deepcopy.go | 121 ++++++++++++++++++ bundle.Dockerfile | 2 +- ...fecycle-manager.clusterserviceversion.yaml | 39 +++--- .../operator.ibm.com_operatorconfigs.yaml | 59 +++++++++ bundle/metadata/annotations.yaml | 2 +- .../operator.ibm.com_operatorconfigs.yaml | 57 +++++++++ config/crd/kustomization.yaml | 5 + .../crd/patches/label_in_operatorconfigs.yaml | 9 ++ config/rbac/operatorconfig_editor_role.yaml | 31 +++++ config/rbac/operatorconfig_viewer_role.yaml | 27 ++++ .../operator_v1alpha1_operatorconfig.yaml | 12 ++ .../operatorconfig_controller.go | 60 +++++++++ .../operatorconfig_suite_test.go | 80 ++++++++++++ go.mod | 1 + go.sum | 1 + main.go | 7 + 18 files changed, 575 insertions(+), 24 deletions(-) create mode 100644 api/v1alpha1/operatorconfig_types.go create mode 100644 bundle/manifests/operator.ibm.com_operatorconfigs.yaml create mode 100644 config/crd/bases/operator.ibm.com_operatorconfigs.yaml create mode 100644 config/crd/patches/label_in_operatorconfigs.yaml create mode 100644 config/rbac/operatorconfig_editor_role.yaml create mode 100644 config/rbac/operatorconfig_viewer_role.yaml create mode 100644 config/samples/operator_v1alpha1_operatorconfig.yaml create mode 100644 controllers/operatorconfig/operatorconfig_controller.go create mode 100644 controllers/operatorconfig/operatorconfig_suite_test.go diff --git a/PROJECT b/PROJECT index 83657404..faf71aed 100644 --- a/PROJECT +++ b/PROJECT @@ -1,5 +1,13 @@ +# Code generated by tool. DO NOT EDIT. +# This file is used to track the info used to scaffold your project +# and allow the plugins properly work. +# More info: https://book.kubebuilder.io/reference/project-config.html domain: ibm.com -layout: go.kubebuilder.io/v3 +layout: +- go.kubebuilder.io/v3 +plugins: + manifests.sdk.operatorframework.io/v2: {} + scorecard.sdk.operatorframework.io/v2: {} projectName: operand-deployment-lifecycle-manager repo: github.com/IBM/operand-deployment-lifecycle-manager resources: @@ -27,7 +35,13 @@ resources: kind: OperandBindInfo path: github.com/IBM/operand-deployment-lifecycle-manager/api/v1alpha1 version: v1alpha1 +- api: + crdVersion: v1 + namespaced: true + controller: true + domain: ibm.com + group: operator + kind: OperatorConfig + path: github.com/IBM/operand-deployment-lifecycle-manager/api/v1alpha1 + version: v1alpha1 version: "3" -plugins: - manifests.sdk.operatorframework.io/v2: {} - scorecard.sdk.operatorframework.io/v2: {} diff --git a/api/v1alpha1/operatorconfig_types.go b/api/v1alpha1/operatorconfig_types.go new file mode 100644 index 00000000..c2c5a924 --- /dev/null +++ b/api/v1alpha1/operatorconfig_types.go @@ -0,0 +1,64 @@ +// +// Copyright 2022 IBM Corporation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! +// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. + +// OperatorConfigSpec defines the desired state of OperatorConfig +type OperatorConfigSpec struct { + // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster + // Important: Run "make" to regenerate code after modifying this file + + // Foo is an example field of OperatorConfig. Edit operatorconfig_types.go to remove/update + Foo string `json:"foo,omitempty"` +} + +// OperatorConfigStatus defines the observed state of OperatorConfig +type OperatorConfigStatus struct { + // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster + // Important: Run "make" to regenerate code after modifying this file +} + +//+kubebuilder:object:root=true +//+kubebuilder:subresource:status + +// OperatorConfig is the Schema for the operatorconfigs API +type OperatorConfig struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec OperatorConfigSpec `json:"spec,omitempty"` + Status OperatorConfigStatus `json:"status,omitempty"` +} + +//+kubebuilder:object:root=true + +// OperatorConfigList contains a list of OperatorConfig +type OperatorConfigList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []OperatorConfig `json:"items"` +} + +func init() { + SchemeBuilder.Register(&OperatorConfig{}, &OperatorConfigList{}) +} diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 531bb62f..c3013da1 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -88,6 +88,13 @@ func (in *ConfigResource) DeepCopyInto(out *ConfigResource) { *out = new(runtime.RawExtension) (*in).DeepCopyInto(*out) } + if in.OwnerReferences != nil { + in, out := &in.OwnerReferences, &out.OwnerReferences + *out = make([]OwnerReference, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConfigResource. @@ -717,6 +724,95 @@ func (in *Operator) DeepCopy() *Operator { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *OperatorConfig) DeepCopyInto(out *OperatorConfig) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Spec = in.Spec + out.Status = in.Status +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OperatorConfig. +func (in *OperatorConfig) DeepCopy() *OperatorConfig { + if in == nil { + return nil + } + out := new(OperatorConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *OperatorConfig) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *OperatorConfigList) DeepCopyInto(out *OperatorConfigList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]OperatorConfig, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OperatorConfigList. +func (in *OperatorConfigList) DeepCopy() *OperatorConfigList { + if in == nil { + return nil + } + out := new(OperatorConfigList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *OperatorConfigList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *OperatorConfigSpec) DeepCopyInto(out *OperatorConfigSpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OperatorConfigSpec. +func (in *OperatorConfigSpec) DeepCopy() *OperatorConfigSpec { + if in == nil { + return nil + } + out := new(OperatorConfigSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *OperatorConfigStatus) DeepCopyInto(out *OperatorConfigStatus) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OperatorConfigStatus. +func (in *OperatorConfigStatus) DeepCopy() *OperatorConfigStatus { + if in == nil { + return nil + } + out := new(OperatorConfigStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *OperatorStatus) DeepCopyInto(out *OperatorStatus) { *out = *in @@ -737,6 +833,31 @@ func (in *OperatorStatus) DeepCopy() *OperatorStatus { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *OwnerReference) DeepCopyInto(out *OwnerReference) { + *out = *in + if in.Controller != nil { + in, out := &in.Controller, &out.Controller + *out = new(bool) + **out = **in + } + if in.BlockOwnerDeletion != nil { + in, out := &in.BlockOwnerDeletion, &out.BlockOwnerDeletion + *out = new(bool) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OwnerReference. +func (in *OwnerReference) DeepCopy() *OwnerReference { + if in == nil { + return nil + } + out := new(OwnerReference) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ReconcileRequest) DeepCopyInto(out *ReconcileRequest) { *out = *in diff --git a/bundle.Dockerfile b/bundle.Dockerfile index 162e5db1..6f953fb9 100644 --- a/bundle.Dockerfile +++ b/bundle.Dockerfile @@ -7,7 +7,7 @@ LABEL operators.operatorframework.io.bundle.metadata.v1=metadata/ LABEL operators.operatorframework.io.bundle.package.v1=ibm-odlm LABEL operators.operatorframework.io.bundle.channels.v1=v4.3 LABEL operators.operatorframework.io.bundle.channel.default.v1=v4.3 -LABEL operators.operatorframework.io.metrics.builder=operator-sdk-v1.32.0 +LABEL operators.operatorframework.io.metrics.builder=operator-sdk-v1.29.0 LABEL operators.operatorframework.io.metrics.mediatype.v1=metrics+v1 LABEL operators.operatorframework.io.metrics.project_layout=go.kubebuilder.io/v3 diff --git a/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml b/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml index b85d3e1d..f815c155 100644 --- a/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml +++ b/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml @@ -129,12 +129,12 @@ metadata: categories: Developer Tools, Monitoring, Logging & Tracing, Security certified: "false" containerImage: icr.io/cpopen/odlm:latest - createdAt: "2024-03-13T21:38:26Z" + createdAt: "2024-03-20T18:18:08Z" description: The Operand Deployment Lifecycle Manager provides a Kubernetes CRD-based API to manage the lifecycle of operands. nss.operator.ibm.com/managed-operators: ibm-odlm olm.skipRange: '>=1.2.0 <4.3.0' operators.openshift.io/infrastructure-features: '["disconnected"]' - operators.operatorframework.io/builder: operator-sdk-v1.32.0 + operators.operatorframework.io/builder: operator-sdk-v1.29.0 operators.operatorframework.io/project_layout: go.kubebuilder.io/v3 repository: https://github.com/IBM/operand-deployment-lifecycle-manager support: IBM @@ -215,6 +215,9 @@ spec: x-descriptors: - urn:alm:descriptor:io.kubernetes.phase version: v1alpha1 + - kind: OperatorConfig + name: operatorconfigs.operator.ibm.com + version: v1alpha1 description: |- # Introduction @@ -562,22 +565,22 @@ spec: install: spec: clusterPermissions: - - rules: - - apiGroups: - - operators.coreos.com - resources: - - catalogsources - verbs: - - get - - apiGroups: - - operator.ibm.com - resources: - - certmanagers - - auditloggings - verbs: - - get - - delete - serviceAccountName: operand-deployment-lifecycle-manager + - rules: + - apiGroups: + - operators.coreos.com + resources: + - catalogsources + verbs: + - get + - apiGroups: + - operator.ibm.com + resources: + - certmanagers + - auditloggings + verbs: + - get + - delete + serviceAccountName: operand-deployment-lifecycle-manager deployments: - label: app.kubernetes.io/instance: operand-deployment-lifecycle-manager diff --git a/bundle/manifests/operator.ibm.com_operatorconfigs.yaml b/bundle/manifests/operator.ibm.com_operatorconfigs.yaml new file mode 100644 index 00000000..20d9f31d --- /dev/null +++ b/bundle/manifests/operator.ibm.com_operatorconfigs.yaml @@ -0,0 +1,59 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.6.1 + creationTimestamp: null + labels: + app.kubernetes.io/instance: operand-deployment-lifecycle-manager + app.kubernetes.io/managed-by: operand-deployment-lifecycle-manager + app.kubernetes.io/name: operand-deployment-lifecycle-manager + name: operatorconfigs.operator.ibm.com +spec: + group: operator.ibm.com + names: + kind: OperatorConfig + listKind: OperatorConfigList + plural: operatorconfigs + singular: operatorconfig + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: OperatorConfig is the Schema for the operatorconfigs API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: OperatorConfigSpec defines the desired state of OperatorConfig + properties: + foo: + description: Foo is an example field of OperatorConfig. Edit operatorconfig_types.go + to remove/update + type: string + type: object + status: + description: OperatorConfigStatus defines the observed state of OperatorConfig + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] diff --git a/bundle/metadata/annotations.yaml b/bundle/metadata/annotations.yaml index e4758c86..f3bfce43 100644 --- a/bundle/metadata/annotations.yaml +++ b/bundle/metadata/annotations.yaml @@ -6,7 +6,7 @@ annotations: operators.operatorframework.io.bundle.package.v1: ibm-odlm operators.operatorframework.io.bundle.channels.v1: v4.3 operators.operatorframework.io.bundle.channel.default.v1: v4.3 - operators.operatorframework.io.metrics.builder: operator-sdk-v1.32.0 + operators.operatorframework.io.metrics.builder: operator-sdk-v1.29.0 operators.operatorframework.io.metrics.mediatype.v1: metrics+v1 operators.operatorframework.io.metrics.project_layout: go.kubebuilder.io/v3 # Annotations for testing. diff --git a/config/crd/bases/operator.ibm.com_operatorconfigs.yaml b/config/crd/bases/operator.ibm.com_operatorconfigs.yaml new file mode 100644 index 00000000..b9062664 --- /dev/null +++ b/config/crd/bases/operator.ibm.com_operatorconfigs.yaml @@ -0,0 +1,57 @@ + +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.6.1 + creationTimestamp: null + name: operatorconfigs.operator.ibm.com +spec: + group: operator.ibm.com + names: + kind: OperatorConfig + listKind: OperatorConfigList + plural: operatorconfigs + singular: operatorconfig + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: OperatorConfig is the Schema for the operatorconfigs API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: OperatorConfigSpec defines the desired state of OperatorConfig + properties: + foo: + description: Foo is an example field of OperatorConfig. Edit operatorconfig_types.go + to remove/update + type: string + type: object + status: + description: OperatorConfigStatus defines the observed state of OperatorConfig + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] diff --git a/config/crd/kustomization.yaml b/config/crd/kustomization.yaml index be422ac7..b50b14f2 100644 --- a/config/crd/kustomization.yaml +++ b/config/crd/kustomization.yaml @@ -6,6 +6,7 @@ resources: - bases/operator.ibm.com_operandconfigs.yaml - bases/operator.ibm.com_operandbindinfos.yaml - bases/operator.ibm.com_operandregistries.yaml +- bases/operator.ibm.com_operatorconfigs.yaml # +kubebuilder:scaffold:crdkustomizeresource patchesStrategicMerge: @@ -15,6 +16,7 @@ patchesStrategicMerge: #- patches/webhook_in_operandconfigs.yaml #- patches/webhook_in_operandbindinfoes.yaml #- patches/webhook_in_operandregistries.yaml +#- patches/webhook_in_operatorconfigs.yaml # +kubebuilder:scaffold:crdkustomizewebhookpatch # [CERTMANAGER] To enable webhook, uncomment all the sections with [CERTMANAGER] prefix. @@ -23,6 +25,7 @@ patchesStrategicMerge: #- patches/cainjection_in_operandconfigs.yaml #- patches/cainjection_in_operandbindinfoes.yaml #- patches/cainjection_in_operandregistries.yaml +#- patches/cainjection_in_operatorconfigs.yaml # +kubebuilder:scaffold:crdkustomizecainjectionpatch # patches here are for adding labels for each CRD @@ -30,6 +33,8 @@ patchesStrategicMerge: - patches/label_in_operandconfigs.yaml - patches/label_in_operandbindinfos.yaml - patches/label_in_operandregistries.yaml +- patches/label_in_operatorconfigs.yaml +#- patches/cainjection_in_operatorconfigs.yaml # +kubebuilder:scaffold:crdkustomizecainjectionpatch # the following config is for teaching kustomize how to do kustomization for CRDs. diff --git a/config/crd/patches/label_in_operatorconfigs.yaml b/config/crd/patches/label_in_operatorconfigs.yaml new file mode 100644 index 00000000..49773cb2 --- /dev/null +++ b/config/crd/patches/label_in_operatorconfigs.yaml @@ -0,0 +1,9 @@ +# The following patch adds a directive for certmanager to inject CA into the CRD +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + labels: + app.kubernetes.io/instance: "operand-deployment-lifecycle-manager" + app.kubernetes.io/managed-by: "operand-deployment-lifecycle-manager" + app.kubernetes.io/name: "operand-deployment-lifecycle-manager" + name: operatorconfigs.operator.ibm.com diff --git a/config/rbac/operatorconfig_editor_role.yaml b/config/rbac/operatorconfig_editor_role.yaml new file mode 100644 index 00000000..17a6e034 --- /dev/null +++ b/config/rbac/operatorconfig_editor_role.yaml @@ -0,0 +1,31 @@ +# permissions for end users to edit operatorconfigs. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: clusterrole + app.kubernetes.io/instance: operatorconfig-editor-role + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: operand-deployment-lifecycle-manager + app.kubernetes.io/part-of: operand-deployment-lifecycle-manager + app.kubernetes.io/managed-by: kustomize + name: operatorconfig-editor-role +rules: +- apiGroups: + - operator.ibm.com + resources: + - operatorconfigs + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - operator.ibm.com + resources: + - operatorconfigs/status + verbs: + - get diff --git a/config/rbac/operatorconfig_viewer_role.yaml b/config/rbac/operatorconfig_viewer_role.yaml new file mode 100644 index 00000000..a785595c --- /dev/null +++ b/config/rbac/operatorconfig_viewer_role.yaml @@ -0,0 +1,27 @@ +# permissions for end users to view operatorconfigs. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: clusterrole + app.kubernetes.io/instance: operatorconfig-viewer-role + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: operand-deployment-lifecycle-manager + app.kubernetes.io/part-of: operand-deployment-lifecycle-manager + app.kubernetes.io/managed-by: kustomize + name: operatorconfig-viewer-role +rules: +- apiGroups: + - operator.ibm.com + resources: + - operatorconfigs + verbs: + - get + - list + - watch +- apiGroups: + - operator.ibm.com + resources: + - operatorconfigs/status + verbs: + - get diff --git a/config/samples/operator_v1alpha1_operatorconfig.yaml b/config/samples/operator_v1alpha1_operatorconfig.yaml new file mode 100644 index 00000000..f57b5d62 --- /dev/null +++ b/config/samples/operator_v1alpha1_operatorconfig.yaml @@ -0,0 +1,12 @@ +apiVersion: operator.ibm.com/v1alpha1 +kind: OperatorConfig +metadata: + labels: + app.kubernetes.io/name: operatorconfig + app.kubernetes.io/instance: operatorconfig-sample + app.kubernetes.io/part-of: operand-deployment-lifecycle-manager + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/created-by: operand-deployment-lifecycle-manager + name: operatorconfig-sample +spec: + # TODO(user): Add fields here diff --git a/controllers/operatorconfig/operatorconfig_controller.go b/controllers/operatorconfig/operatorconfig_controller.go new file mode 100644 index 00000000..9abeab89 --- /dev/null +++ b/controllers/operatorconfig/operatorconfig_controller.go @@ -0,0 +1,60 @@ +// +// Copyright 2022 IBM Corporation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package operatorconfig + +import ( + "context" + + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/log" + + operatorv1alpha1 "github.com/IBM/operand-deployment-lifecycle-manager/api/v1alpha1" + deploy "github.com/IBM/operand-deployment-lifecycle-manager/controllers/operator" +) + +// OperatorConfigReconciler reconciles a OperatorConfig object +type Reconciler struct { + *deploy.ODLMOperator +} + +//+kubebuilder:rbac:groups=operator.ibm.com,resources=operatorconfigs,verbs=get;list;watch;create;update;patch;delete +//+kubebuilder:rbac:groups=operator.ibm.com,resources=operatorconfigs/status,verbs=get;update;patch +//+kubebuilder:rbac:groups=operator.ibm.com,resources=operatorconfigs/finalizers,verbs=update + +// Reconcile is part of the main kubernetes reconciliation loop which aims to +// move the current state of the cluster closer to the desired state. +// TODO(user): Modify the Reconcile function to compare the state specified by +// the OperatorConfig object against the actual cluster state, and then +// perform operations to make the cluster state reflect the state specified by +// the user. +// +// For more details, check Reconcile and its Result here: +// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.14.1/pkg/reconcile +func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + _ = log.FromContext(ctx) + + // TODO(user): your logic here + + return ctrl.Result{}, nil +} + +// SetupWithManager sets up the controller with the Manager. +func (r *Reconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&operatorv1alpha1.OperatorConfig{}). + Complete(r) +} diff --git a/controllers/operatorconfig/operatorconfig_suite_test.go b/controllers/operatorconfig/operatorconfig_suite_test.go new file mode 100644 index 00000000..aef3a37a --- /dev/null +++ b/controllers/operatorconfig/operatorconfig_suite_test.go @@ -0,0 +1,80 @@ +// +// Copyright 2022 IBM Corporation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package operatorconfig + +import ( + "path/filepath" + "testing" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + + "k8s.io/client-go/kubernetes/scheme" + "k8s.io/client-go/rest" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/envtest" + logf "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/log/zap" + + operatorv1alpha1 "github.com/IBM/operand-deployment-lifecycle-manager/api/v1alpha1" + //+kubebuilder:scaffold:imports +) + +// These tests use Ginkgo (BDD-style Go testing framework). Refer to +// http://onsi.github.io/ginkgo/ to learn more about Ginkgo. + +var cfg *rest.Config +var k8sClient client.Client +var testEnv *envtest.Environment + +func TestAPIs(t *testing.T) { + RegisterFailHandler(Fail) + + RunSpecs(t, "Controller Suite") +} + +var _ = BeforeSuite(func() { + logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true))) + + By("bootstrapping test environment") + testEnv = &envtest.Environment{ + CRDDirectoryPaths: []string{filepath.Join("..", "config", "crd", "bases")}, + ErrorIfCRDPathMissing: true, + } + + var err error + // cfg is defined in this file globally. + cfg, err = testEnv.Start() + Expect(err).NotTo(HaveOccurred()) + Expect(cfg).NotTo(BeNil()) + + err = operatorv1alpha1.AddToScheme(scheme.Scheme) + Expect(err).NotTo(HaveOccurred()) + + //+kubebuilder:scaffold:scheme + + k8sClient, err = client.New(cfg, client.Options{Scheme: scheme.Scheme}) + Expect(err).NotTo(HaveOccurred()) + Expect(k8sClient).NotTo(BeNil()) + +}) + +var _ = AfterSuite(func() { + By("tearing down the test environment") + err := testEnv.Stop() + Expect(err).NotTo(HaveOccurred()) +}) diff --git a/go.mod b/go.mod index 7961c193..86f98feb 100644 --- a/go.mod +++ b/go.mod @@ -11,6 +11,7 @@ require ( github.com/jaegertracing/jaeger-operator v1.36.0 github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 github.com/onsi/ginkgo v1.16.5 + github.com/onsi/ginkgo/v2 v2.1.4 github.com/onsi/gomega v1.19.0 github.com/openshift/api v0.0.0-20220124143425-d74727069f6f github.com/operator-framework/api v0.6.2 diff --git a/go.sum b/go.sum index eca671c1..a02dea1d 100644 --- a/go.sum +++ b/go.sum @@ -734,6 +734,7 @@ github.com/onsi/ginkgo v1.14.1/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9k 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.1.4 h1:GNapqRSid3zijZ9H77KrgVG4/8KqiyRsxcSxe+7ApXY= +github.com/onsi/ginkgo/v2 v2.1.4/go.mod h1:um6tUpWM/cxCK3/FK8BXqEiUMUwRgSM4JXG47RKZmLU= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= diff --git a/main.go b/main.go index 0b53313b..7281861f 100644 --- a/main.go +++ b/main.go @@ -49,6 +49,7 @@ import ( "github.com/IBM/operand-deployment-lifecycle-manager/controllers/operandrequest" deploy "github.com/IBM/operand-deployment-lifecycle-manager/controllers/operator" "github.com/IBM/operand-deployment-lifecycle-manager/controllers/operatorchecker" + "github.com/IBM/operand-deployment-lifecycle-manager/controllers/operatorconfig" "github.com/IBM/operand-deployment-lifecycle-manager/controllers/util" // +kubebuilder:scaffold:imports ) @@ -166,6 +167,12 @@ func main() { } } } + if err = (&operatorconfig.Reconciler{ + ODLMOperator: deploy.NewODLMOperator(mgr, "OperatorConfig"), + }).SetupWithManager(mgr); err != nil { + klog.Error(err, "unable to create controller", "controller", "OperatorConfig") + os.Exit(1) + } // +kubebuilder:scaffold:builder if err := mgr.AddHealthzCheck("health", healthz.Ping); err != nil { From 5570fa683abeaa953050b4a2b44328e22bfbab0f Mon Sep 17 00:00:00 2001 From: Henry Li Date: Sun, 31 Mar 2024 23:18:57 -0400 Subject: [PATCH 089/179] Operatorconfig controller (#1030) * added new fields to OperatorConfigSpec type - for configuring replicas, affinity, and topologySpreadConstraints Signed-off-by: Henry H Li * added OperatorConfig controller - to apply configuration from OperatorConfig onto CSVs updated Operator type in OperandRegistry to include OperatorConfig name - this assumes OperatorConfigs are in the same namespace as registry, just like OperandConfig updated RBAC to include OperatorConfig Signed-off-by: Henry H Li * added preserve unknown fields to ServiceOperatorConfig type Signed-off-by: Henry H Li * go mod tidy Signed-off-by: Henry H Li * fixed go imports formatting Signed-off-by: Henry H Li * fixed incorrect comment description for GetConfigForOperator Signed-off-by: Henry H Li --------- Signed-off-by: Henry H Li --- api/v1alpha1/operandregistry_types.go | 3 + api/v1alpha1/operatorconfig_types.go | 43 +- api/v1alpha1/zz_generated.deepcopy.go | 42 +- ...fecycle-manager.clusterserviceversion.yaml | 5 +- .../operator.ibm.com_operandregistries.yaml | 3 + .../operator.ibm.com_operatorconfigs.yaml | 1039 +++++++++++++++++ .../operator.ibm.com_operandregistries.yaml | 3 + .../operator.ibm.com_operatorconfigs.yaml | 1039 +++++++++++++++++ config/rbac/role.yaml | 3 + .../operatorconfig_controller.go | 112 +- go.mod | 2 +- 11 files changed, 2286 insertions(+), 8 deletions(-) diff --git a/api/v1alpha1/operandregistry_types.go b/api/v1alpha1/operandregistry_types.go index 6daf2ec0..edea7ae0 100644 --- a/api/v1alpha1/operandregistry_types.go +++ b/api/v1alpha1/operandregistry_types.go @@ -73,6 +73,9 @@ type Operator struct { // SubscriptionConfig is used to override operator configuration. // +optional SubscriptionConfig *olmv1alpha1.SubscriptionConfig `json:"subscriptionConfig,omitempty"` + // OperatorConfig is the name of the OperatorConfig + // +optional + OperatorConfig string `json:"operatorConfig,omitempty"` } // +kubebuilder:validation:Enum=public;private diff --git a/api/v1alpha1/operatorconfig_types.go b/api/v1alpha1/operatorconfig_types.go index c2c5a924..643dbedd 100644 --- a/api/v1alpha1/operatorconfig_types.go +++ b/api/v1alpha1/operatorconfig_types.go @@ -17,22 +17,49 @@ package v1alpha1 import ( + corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) -// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! -// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. - // OperatorConfigSpec defines the desired state of OperatorConfig +// +kubebuilder:pruning:PreserveUnknownFields type OperatorConfigSpec struct { // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster // Important: Run "make" to regenerate code after modifying this file // Foo is an example field of OperatorConfig. Edit operatorconfig_types.go to remove/update Foo string `json:"foo,omitempty"` + + // Services is a list of services to be configured, specifically their operators + // +kubebuilder:pruning:PreserveUnknownFields + Services []ServiceOperatorConfig `json:"services,omitempty"` +} + +// ServiceOperatorConfig defines the configuration of the service. +type ServiceOperatorConfig struct { + // Name is the operator name as requested in the OperandRequest. + Name string `json:"name"` + // If specified, the pod's scheduling constraints + // +optional + Affinity *corev1.Affinity `json:"affinity,omitempty" protobuf:"bytes,18,opt,name=affinity"` + // Number of desired pods. This is a pointer to distinguish between explicit + // zero and not specified. Defaults to 1. + // +optional + Replicas *int32 `json:"replicas,omitempty" protobuf:"varint,1,opt,name=replicas"` + // TopologySpreadConstraints describes how a group of pods ought to spread across topology + // domains. Scheduler will schedule pods in a way which abides by the constraints. + // All topologySpreadConstraints are ANDed. + // +optional + // +patchMergeKey=topologyKey + // +patchStrategy=merge + // +listType=map + // +listMapKey=topologyKey + // +listMapKey=whenUnsatisfiable + TopologySpreadConstraints []corev1.TopologySpreadConstraint `json:"topologySpreadConstraints,omitempty" patchStrategy:"merge" patchMergeKey:"topologyKey" protobuf:"bytes,33,opt,name=topologySpreadConstraints"` } // OperatorConfigStatus defines the observed state of OperatorConfig +// +kubebuilder:pruning:PreserveUnknownFields type OperatorConfigStatus struct { // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster // Important: Run "make" to regenerate code after modifying this file @@ -59,6 +86,16 @@ type OperatorConfigList struct { Items []OperatorConfig `json:"items"` } +// GetConfigForOperator obtains a particular ServiceOperatorConfig by using operator name for searching. +func (r *OperatorConfig) GetConfigForOperator(name string) *ServiceOperatorConfig { + for _, o := range r.Spec.Services { + if o.Name == name { + return &o + } + } + return nil +} + func init() { SchemeBuilder.Register(&OperatorConfig{}, &OperatorConfigList{}) } diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index c3013da1..26f36494 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -23,6 +23,7 @@ package v1alpha1 import ( operatorsv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1" + "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/runtime" ) @@ -729,7 +730,7 @@ func (in *OperatorConfig) DeepCopyInto(out *OperatorConfig) { *out = *in out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - out.Spec = in.Spec + in.Spec.DeepCopyInto(&out.Spec) out.Status = in.Status } @@ -786,6 +787,13 @@ func (in *OperatorConfigList) DeepCopyObject() runtime.Object { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *OperatorConfigSpec) DeepCopyInto(out *OperatorConfigSpec) { *out = *in + if in.Services != nil { + in, out := &in.Services, &out.Services + *out = make([]ServiceOperatorConfig, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OperatorConfigSpec. @@ -954,6 +962,38 @@ func (in *ServiceData) DeepCopy() *ServiceData { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ServiceOperatorConfig) DeepCopyInto(out *ServiceOperatorConfig) { + *out = *in + if in.Affinity != nil { + in, out := &in.Affinity, &out.Affinity + *out = new(v1.Affinity) + (*in).DeepCopyInto(*out) + } + if in.Replicas != nil { + in, out := &in.Replicas, &out.Replicas + *out = new(int32) + **out = **in + } + if in.TopologySpreadConstraints != nil { + in, out := &in.TopologySpreadConstraints, &out.TopologySpreadConstraints + *out = make([]v1.TopologySpreadConstraint, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServiceOperatorConfig. +func (in *ServiceOperatorConfig) DeepCopy() *ServiceOperatorConfig { + if in == nil { + return nil + } + out := new(ServiceOperatorConfig) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ServiceStatus) DeepCopyInto(out *ServiceStatus) { *out = *in diff --git a/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml b/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml index f815c155..df1d3384 100644 --- a/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml +++ b/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml @@ -129,7 +129,7 @@ metadata: categories: Developer Tools, Monitoring, Logging & Tracing, Security certified: "false" containerImage: icr.io/cpopen/odlm:latest - createdAt: "2024-03-20T18:18:08Z" + createdAt: "2024-03-29T03:10:47Z" description: The Operand Deployment Lifecycle Manager provides a Kubernetes CRD-based API to manage the lifecycle of operands. nss.operator.ibm.com/managed-operators: ibm-odlm olm.skipRange: '>=1.2.0 <4.3.0' @@ -701,6 +701,9 @@ spec: - operandbindinfos - operandbindinfos/status - operandbindinfos/finalizers + - operatorconfigs + - operatorconfigs/status + - operatorconfigs/finalizers verbs: - create - delete diff --git a/bundle/manifests/operator.ibm.com_operandregistries.yaml b/bundle/manifests/operator.ibm.com_operandregistries.yaml index 2fad66fb..95efd0ae 100644 --- a/bundle/manifests/operator.ibm.com_operandregistries.yaml +++ b/bundle/manifests/operator.ibm.com_operandregistries.yaml @@ -85,6 +85,9 @@ spec: is not set, the operator namespace is the same as OperandRegistry Namespace type: string + operatorConfig: + description: OperatorConfig is the name of the OperatorConfig + type: string packageName: description: Name of the package that defines the applications. type: string diff --git a/bundle/manifests/operator.ibm.com_operatorconfigs.yaml b/bundle/manifests/operator.ibm.com_operatorconfigs.yaml index 20d9f31d..d21f73e4 100644 --- a/bundle/manifests/operator.ibm.com_operatorconfigs.yaml +++ b/bundle/manifests/operator.ibm.com_operatorconfigs.yaml @@ -42,10 +42,1049 @@ spec: description: Foo is an example field of OperatorConfig. Edit operatorconfig_types.go to remove/update type: string + services: + description: Services is a list of services to be configured, specifically + their operators + items: + description: ServiceOperatorConfig defines the configuration of + the service. + properties: + affinity: + description: If specified, the pod's scheduling constraints + properties: + nodeAffinity: + description: Describes node affinity scheduling rules for + the pod. + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: The scheduler will prefer to schedule pods + to nodes that satisfy the affinity expressions specified + by this field, but it may choose a node that violates + one or more of the expressions. The node that is most + preferred is the one with the greatest sum of weights, + i.e. for each node that meets all of the scheduling + requirements (resource request, requiredDuringScheduling + affinity expressions, etc.), compute a sum by iterating + through the elements of this field and adding "weight" + to the sum if the node matches the corresponding matchExpressions; + the node(s) with the highest sum are the most preferred. + items: + description: An empty preferred scheduling term matches + all objects with implicit weight 0 (i.e. it's a + no-op). A null preferred scheduling term matches + no objects (i.e. is also a no-op). + properties: + preference: + description: A node selector term, associated + with the corresponding weight. + properties: + matchExpressions: + description: A list of node selector requirements + by node's labels. + items: + description: A node selector requirement + is a selector that contains values, a + key, and an operator that relates the + key and values. + properties: + key: + description: The label key that the + selector applies to. + type: string + operator: + description: Represents a key's relationship + to a set of values. Valid operators + are In, NotIn, Exists, DoesNotExist. + Gt, and Lt. + type: string + values: + description: An array of string values. + If the operator is In or NotIn, the + values array must be non-empty. If + the operator is Exists or DoesNotExist, + the values array must be empty. If + the operator is Gt or Lt, the values + array must have a single element, + which will be interpreted as an integer. + This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchFields: + description: A list of node selector requirements + by node's fields. + items: + description: A node selector requirement + is a selector that contains values, a + key, and an operator that relates the + key and values. + properties: + key: + description: The label key that the + selector applies to. + type: string + operator: + description: Represents a key's relationship + to a set of values. Valid operators + are In, NotIn, Exists, DoesNotExist. + Gt, and Lt. + type: string + values: + description: An array of string values. + If the operator is In or NotIn, the + values array must be non-empty. If + the operator is Exists or DoesNotExist, + the values array must be empty. If + the operator is Gt or Lt, the values + array must have a single element, + which will be interpreted as an integer. + This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + type: object + weight: + description: Weight associated with matching the + corresponding nodeSelectorTerm, in the range + 1-100. + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + requiredDuringSchedulingIgnoredDuringExecution: + description: If the affinity requirements specified + by this field are not met at scheduling time, the + pod will not be scheduled onto the node. If the affinity + requirements specified by this field cease to be met + at some point during pod execution (e.g. due to an + update), the system may or may not try to eventually + evict the pod from its node. + properties: + nodeSelectorTerms: + description: Required. A list of node selector terms. + The terms are ORed. + items: + description: A null or empty node selector term + matches no objects. The requirements of them + are ANDed. The TopologySelectorTerm type implements + a subset of the NodeSelectorTerm. + properties: + matchExpressions: + description: A list of node selector requirements + by node's labels. + items: + description: A node selector requirement + is a selector that contains values, a + key, and an operator that relates the + key and values. + properties: + key: + description: The label key that the + selector applies to. + type: string + operator: + description: Represents a key's relationship + to a set of values. Valid operators + are In, NotIn, Exists, DoesNotExist. + Gt, and Lt. + type: string + values: + description: An array of string values. + If the operator is In or NotIn, the + values array must be non-empty. If + the operator is Exists or DoesNotExist, + the values array must be empty. If + the operator is Gt or Lt, the values + array must have a single element, + which will be interpreted as an integer. + This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchFields: + description: A list of node selector requirements + by node's fields. + items: + description: A node selector requirement + is a selector that contains values, a + key, and an operator that relates the + key and values. + properties: + key: + description: The label key that the + selector applies to. + type: string + operator: + description: Represents a key's relationship + to a set of values. Valid operators + are In, NotIn, Exists, DoesNotExist. + Gt, and Lt. + type: string + values: + description: An array of string values. + If the operator is In or NotIn, the + values array must be non-empty. If + the operator is Exists or DoesNotExist, + the values array must be empty. If + the operator is Gt or Lt, the values + array must have a single element, + which will be interpreted as an integer. + This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + type: object + type: array + required: + - nodeSelectorTerms + type: object + type: object + podAffinity: + description: Describes pod affinity scheduling rules (e.g. + co-locate this pod in the same node, zone, etc. as some + other pod(s)). + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: The scheduler will prefer to schedule pods + to nodes that satisfy the affinity expressions specified + by this field, but it may choose a node that violates + one or more of the expressions. The node that is most + preferred is the one with the greatest sum of weights, + i.e. for each node that meets all of the scheduling + requirements (resource request, requiredDuringScheduling + affinity expressions, etc.), compute a sum by iterating + through the elements of this field and adding "weight" + to the sum if the node has pods which matches the + corresponding podAffinityTerm; the node(s) with the + highest sum are the most preferred. + items: + description: The weights of all of the matched WeightedPodAffinityTerm + fields are added per-node to find the most preferred + node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity term, associated + with the corresponding weight. + properties: + labelSelector: + description: A label query over a set of resources, + in this case pods. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The + requirements are ANDed. + items: + description: A label selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: operator represents + a key's relationship to a set + of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array + of string values. If the operator + is In or NotIn, the values array + must be non-empty. If the operator + is Exists or DoesNotExist, the + values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, + whose key field is "key", the operator + is "In", and the values array contains + only "value". The requirements are ANDed. + type: object + type: object + namespaceSelector: + description: A label query over the set of + namespaces that the term applies to. The + term is applied to the union of the namespaces + selected by this field and the ones listed + in the namespaces field. null selector and + null or empty namespaces list means "this + pod's namespace". An empty selector ({}) + matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The + requirements are ANDed. + items: + description: A label selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: operator represents + a key's relationship to a set + of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array + of string values. If the operator + is In or NotIn, the values array + must be non-empty. If the operator + is Exists or DoesNotExist, the + values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, + whose key field is "key", the operator + is "In", and the values array contains + only "value". The requirements are ANDed. + type: object + type: object + namespaces: + description: namespaces specifies a static + list of namespace names that the term applies + to. The term is applied to the union of + the namespaces listed in this field and + the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector + means "this pod's namespace". + items: + type: string + type: array + topologyKey: + description: This pod should be co-located + (affinity) or not co-located (anti-affinity) + with the pods matching the labelSelector + in the specified namespaces, where co-located + is defined as running on a node whose value + of the label with key topologyKey matches + that of any node on which any of the selected + pods is running. Empty topologyKey is not + allowed. + type: string + required: + - topologyKey + type: object + weight: + description: weight associated with matching the + corresponding podAffinityTerm, in the range + 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + requiredDuringSchedulingIgnoredDuringExecution: + description: If the affinity requirements specified + by this field are not met at scheduling time, the + pod will not be scheduled onto the node. If the affinity + requirements specified by this field cease to be met + at some point during pod execution (e.g. due to a + pod label update), the system may or may not try to + eventually evict the pod from its node. When there + are multiple elements, the lists of nodes corresponding + to each podAffinityTerm are intersected, i.e. all + terms must be satisfied. + items: + description: Defines a set of pods (namely those matching + the labelSelector relative to the given namespace(s)) + that this pod should be co-located (affinity) or + not co-located (anti-affinity) with, where co-located + is defined as running on a node whose value of the + label with key matches that of any + node on which a pod of the set of pods is running + properties: + labelSelector: + description: A label query over a set of resources, + in this case pods. + properties: + matchExpressions: + description: matchExpressions is a list of + label selector requirements. The requirements + are ANDed. + items: + description: A label selector requirement + is a selector that contains values, a + key, and an operator that relates the + key and values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, + whose key field is "key", the operator is + "In", and the values array contains only + "value". The requirements are ANDed. + type: object + type: object + namespaceSelector: + description: A label query over the set of namespaces + that the term applies to. The term is applied + to the union of the namespaces selected by this + field and the ones listed in the namespaces + field. null selector and null or empty namespaces + list means "this pod's namespace". An empty + selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list of + label selector requirements. The requirements + are ANDed. + items: + description: A label selector requirement + is a selector that contains values, a + key, and an operator that relates the + key and values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, + whose key field is "key", the operator is + "In", and the values array contains only + "value". The requirements are ANDed. + type: object + type: object + namespaces: + description: namespaces specifies a static list + of namespace names that the term applies to. + The term is applied to the union of the namespaces + listed in this field and the ones selected by + namespaceSelector. null or empty namespaces + list and null namespaceSelector means "this + pod's namespace". + items: + type: string + type: array + topologyKey: + description: This pod should be co-located (affinity) + or not co-located (anti-affinity) with the pods + matching the labelSelector in the specified + namespaces, where co-located is defined as running + on a node whose value of the label with key + topologyKey matches that of any node on which + any of the selected pods is running. Empty topologyKey + is not allowed. + type: string + required: + - topologyKey + type: object + type: array + type: object + podAntiAffinity: + description: Describes pod anti-affinity scheduling rules + (e.g. avoid putting this pod in the same node, zone, etc. + as some other pod(s)). + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: The scheduler will prefer to schedule pods + to nodes that satisfy the anti-affinity expressions + specified by this field, but it may choose a node + that violates one or more of the expressions. The + node that is most preferred is the one with the greatest + sum of weights, i.e. for each node that meets all + of the scheduling requirements (resource request, + requiredDuringScheduling anti-affinity expressions, + etc.), compute a sum by iterating through the elements + of this field and adding "weight" to the sum if the + node has pods which matches the corresponding podAffinityTerm; + the node(s) with the highest sum are the most preferred. + items: + description: The weights of all of the matched WeightedPodAffinityTerm + fields are added per-node to find the most preferred + node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity term, associated + with the corresponding weight. + properties: + labelSelector: + description: A label query over a set of resources, + in this case pods. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The + requirements are ANDed. + items: + description: A label selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: operator represents + a key's relationship to a set + of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array + of string values. If the operator + is In or NotIn, the values array + must be non-empty. If the operator + is Exists or DoesNotExist, the + values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, + whose key field is "key", the operator + is "In", and the values array contains + only "value". The requirements are ANDed. + type: object + type: object + namespaceSelector: + description: A label query over the set of + namespaces that the term applies to. The + term is applied to the union of the namespaces + selected by this field and the ones listed + in the namespaces field. null selector and + null or empty namespaces list means "this + pod's namespace". An empty selector ({}) + matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The + requirements are ANDed. + items: + description: A label selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: operator represents + a key's relationship to a set + of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array + of string values. If the operator + is In or NotIn, the values array + must be non-empty. If the operator + is Exists or DoesNotExist, the + values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, + whose key field is "key", the operator + is "In", and the values array contains + only "value". The requirements are ANDed. + type: object + type: object + namespaces: + description: namespaces specifies a static + list of namespace names that the term applies + to. The term is applied to the union of + the namespaces listed in this field and + the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector + means "this pod's namespace". + items: + type: string + type: array + topologyKey: + description: This pod should be co-located + (affinity) or not co-located (anti-affinity) + with the pods matching the labelSelector + in the specified namespaces, where co-located + is defined as running on a node whose value + of the label with key topologyKey matches + that of any node on which any of the selected + pods is running. Empty topologyKey is not + allowed. + type: string + required: + - topologyKey + type: object + weight: + description: weight associated with matching the + corresponding podAffinityTerm, in the range + 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + requiredDuringSchedulingIgnoredDuringExecution: + description: If the anti-affinity requirements specified + by this field are not met at scheduling time, the + pod will not be scheduled onto the node. If the anti-affinity + requirements specified by this field cease to be met + at some point during pod execution (e.g. due to a + pod label update), the system may or may not try to + eventually evict the pod from its node. When there + are multiple elements, the lists of nodes corresponding + to each podAffinityTerm are intersected, i.e. all + terms must be satisfied. + items: + description: Defines a set of pods (namely those matching + the labelSelector relative to the given namespace(s)) + that this pod should be co-located (affinity) or + not co-located (anti-affinity) with, where co-located + is defined as running on a node whose value of the + label with key matches that of any + node on which a pod of the set of pods is running + properties: + labelSelector: + description: A label query over a set of resources, + in this case pods. + properties: + matchExpressions: + description: matchExpressions is a list of + label selector requirements. The requirements + are ANDed. + items: + description: A label selector requirement + is a selector that contains values, a + key, and an operator that relates the + key and values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, + whose key field is "key", the operator is + "In", and the values array contains only + "value". The requirements are ANDed. + type: object + type: object + namespaceSelector: + description: A label query over the set of namespaces + that the term applies to. The term is applied + to the union of the namespaces selected by this + field and the ones listed in the namespaces + field. null selector and null or empty namespaces + list means "this pod's namespace". An empty + selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list of + label selector requirements. The requirements + are ANDed. + items: + description: A label selector requirement + is a selector that contains values, a + key, and an operator that relates the + key and values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, + whose key field is "key", the operator is + "In", and the values array contains only + "value". The requirements are ANDed. + type: object + type: object + namespaces: + description: namespaces specifies a static list + of namespace names that the term applies to. + The term is applied to the union of the namespaces + listed in this field and the ones selected by + namespaceSelector. null or empty namespaces + list and null namespaceSelector means "this + pod's namespace". + items: + type: string + type: array + topologyKey: + description: This pod should be co-located (affinity) + or not co-located (anti-affinity) with the pods + matching the labelSelector in the specified + namespaces, where co-located is defined as running + on a node whose value of the label with key + topologyKey matches that of any node on which + any of the selected pods is running. Empty topologyKey + is not allowed. + type: string + required: + - topologyKey + type: object + type: array + type: object + type: object + name: + description: Name is the operator name as requested in the OperandRequest. + type: string + replicas: + description: Number of desired pods. This is a pointer to distinguish + between explicit zero and not specified. Defaults to 1. + format: int32 + type: integer + topologySpreadConstraints: + description: TopologySpreadConstraints describes how a group + of pods ought to spread across topology domains. Scheduler + will schedule pods in a way which abides by the constraints. + All topologySpreadConstraints are ANDed. + items: + description: TopologySpreadConstraint specifies how to spread + matching pods among the given topology. + properties: + labelSelector: + description: LabelSelector is used to find matching pods. + Pods that match this label selector are counted to determine + the number of pods in their corresponding topology domain. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, + NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values + array must be non-empty. If the operator is + Exists or DoesNotExist, the values array must + be empty. This array is replaced during a + strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} pairs. + A single {key,value} in the matchLabels map is equivalent + to an element of matchExpressions, whose key field + is "key", the operator is "In", and the values array + contains only "value". The requirements are ANDed. + type: object + type: object + maxSkew: + description: 'MaxSkew describes the degree to which pods + may be unevenly distributed. When `whenUnsatisfiable=DoNotSchedule`, + it is the maximum permitted difference between the number + of matching pods in the target topology and the global + minimum. The global minimum is the minimum number of + matching pods in an eligible domain or zero if the number + of eligible domains is less than MinDomains. For example, + in a 3-zone cluster, MaxSkew is set to 1, and pods with + the same labelSelector spread as 2/2/1: In this case, + the global minimum is 1. | zone1 | zone2 | zone3 | | P + P | P P | P | - if MaxSkew is 1, incoming pod + can only be scheduled to zone3 to become 2/2/2; scheduling + it onto zone1(zone2) would make the ActualSkew(3-1) + on zone1(zone2) violate MaxSkew(1). - if MaxSkew is + 2, incoming pod can be scheduled onto any zone. When + `whenUnsatisfiable=ScheduleAnyway`, it is used to give + higher precedence to topologies that satisfy it. It''s + a required field. Default value is 1 and 0 is not allowed.' + format: int32 + type: integer + minDomains: + description: "MinDomains indicates a minimum number of + eligible domains. When the number of eligible domains + with matching topology keys is less than minDomains, + Pod Topology Spread treats \"global minimum\" as 0, + and then the calculation of Skew is performed. And when + the number of eligible domains with matching topology + keys equals or greater than minDomains, this value has + no effect on scheduling. As a result, when the number + of eligible domains is less than minDomains, scheduler + won't schedule more than maxSkew Pods to those domains. + If value is nil, the constraint behaves as if MinDomains + is equal to 1. Valid values are integers greater than + 0. When value is not nil, WhenUnsatisfiable must be + DoNotSchedule. \n For example, in a 3-zone cluster, + MaxSkew is set to 2, MinDomains is set to 5 and pods + with the same labelSelector spread as 2/2/2: | zone1 + | zone2 | zone3 | | P P | P P | P P | The number + of domains is less than 5(MinDomains), so \"global minimum\" + is treated as 0. In this situation, new pod with the + same labelSelector cannot be scheduled, because computed + skew will be 3(3 - 0) if new Pod is scheduled to any + of the three zones, it will violate MaxSkew. \n This + is an alpha field and requires enabling MinDomainsInPodTopologySpread + feature gate." + format: int32 + type: integer + topologyKey: + description: TopologyKey is the key of node labels. Nodes + that have a label with this key and identical values + are considered to be in the same topology. We consider + each as a "bucket", and try to put balanced + number of pods into each bucket. We define a domain + as a particular instance of a topology. Also, we define + an eligible domain as a domain whose nodes match the + node selector. e.g. If TopologyKey is "kubernetes.io/hostname", + each Node is a domain of that topology. And, if TopologyKey + is "topology.kubernetes.io/zone", each zone is a domain + of that topology. It's a required field. + type: string + whenUnsatisfiable: + description: 'WhenUnsatisfiable indicates how to deal + with a pod if it doesn''t satisfy the spread constraint. + - DoNotSchedule (default) tells the scheduler not to + schedule it. - ScheduleAnyway tells the scheduler to + schedule the pod in any location, but giving higher + precedence to topologies that would help reduce the skew. + A constraint is considered "Unsatisfiable" for an incoming + pod if and only if every possible node assignment for + that pod would violate "MaxSkew" on some topology. For + example, in a 3-zone cluster, MaxSkew is set to 1, and + pods with the same labelSelector spread as 3/1/1: | + zone1 | zone2 | zone3 | | P P P | P | P | If + WhenUnsatisfiable is set to DoNotSchedule, incoming + pod can only be scheduled to zone2(zone3) to become + 3/2/1(3/1/2) as ActualSkew(2-1) on zone2(zone3) satisfies + MaxSkew(1). In other words, the cluster can still be + imbalanced, but scheduler won''t make it *more* imbalanced. + It''s a required field.' + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array + x-kubernetes-list-map-keys: + - topologyKey + - whenUnsatisfiable + x-kubernetes-list-type: map + required: + - name + type: object + type: array + x-kubernetes-preserve-unknown-fields: true type: object + x-kubernetes-preserve-unknown-fields: true status: description: OperatorConfigStatus defines the observed state of OperatorConfig type: object + x-kubernetes-preserve-unknown-fields: true type: object served: true storage: true diff --git a/config/crd/bases/operator.ibm.com_operandregistries.yaml b/config/crd/bases/operator.ibm.com_operandregistries.yaml index cbef8a2b..2b74874a 100644 --- a/config/crd/bases/operator.ibm.com_operandregistries.yaml +++ b/config/crd/bases/operator.ibm.com_operandregistries.yaml @@ -83,6 +83,9 @@ spec: is not set, the operator namespace is the same as OperandRegistry Namespace type: string + operatorConfig: + description: OperatorConfig is the name of the OperatorConfig + type: string packageName: description: Name of the package that defines the applications. type: string diff --git a/config/crd/bases/operator.ibm.com_operatorconfigs.yaml b/config/crd/bases/operator.ibm.com_operatorconfigs.yaml index b9062664..768e5240 100644 --- a/config/crd/bases/operator.ibm.com_operatorconfigs.yaml +++ b/config/crd/bases/operator.ibm.com_operatorconfigs.yaml @@ -40,10 +40,1049 @@ spec: description: Foo is an example field of OperatorConfig. Edit operatorconfig_types.go to remove/update type: string + services: + description: Services is a list of services to be configured, specifically + their operators + items: + description: ServiceOperatorConfig defines the configuration of + the service. + properties: + affinity: + description: If specified, the pod's scheduling constraints + properties: + nodeAffinity: + description: Describes node affinity scheduling rules for + the pod. + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: The scheduler will prefer to schedule pods + to nodes that satisfy the affinity expressions specified + by this field, but it may choose a node that violates + one or more of the expressions. The node that is most + preferred is the one with the greatest sum of weights, + i.e. for each node that meets all of the scheduling + requirements (resource request, requiredDuringScheduling + affinity expressions, etc.), compute a sum by iterating + through the elements of this field and adding "weight" + to the sum if the node matches the corresponding matchExpressions; + the node(s) with the highest sum are the most preferred. + items: + description: An empty preferred scheduling term matches + all objects with implicit weight 0 (i.e. it's a + no-op). A null preferred scheduling term matches + no objects (i.e. is also a no-op). + properties: + preference: + description: A node selector term, associated + with the corresponding weight. + properties: + matchExpressions: + description: A list of node selector requirements + by node's labels. + items: + description: A node selector requirement + is a selector that contains values, a + key, and an operator that relates the + key and values. + properties: + key: + description: The label key that the + selector applies to. + type: string + operator: + description: Represents a key's relationship + to a set of values. Valid operators + are In, NotIn, Exists, DoesNotExist. + Gt, and Lt. + type: string + values: + description: An array of string values. + If the operator is In or NotIn, the + values array must be non-empty. If + the operator is Exists or DoesNotExist, + the values array must be empty. If + the operator is Gt or Lt, the values + array must have a single element, + which will be interpreted as an integer. + This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchFields: + description: A list of node selector requirements + by node's fields. + items: + description: A node selector requirement + is a selector that contains values, a + key, and an operator that relates the + key and values. + properties: + key: + description: The label key that the + selector applies to. + type: string + operator: + description: Represents a key's relationship + to a set of values. Valid operators + are In, NotIn, Exists, DoesNotExist. + Gt, and Lt. + type: string + values: + description: An array of string values. + If the operator is In or NotIn, the + values array must be non-empty. If + the operator is Exists or DoesNotExist, + the values array must be empty. If + the operator is Gt or Lt, the values + array must have a single element, + which will be interpreted as an integer. + This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + type: object + weight: + description: Weight associated with matching the + corresponding nodeSelectorTerm, in the range + 1-100. + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + requiredDuringSchedulingIgnoredDuringExecution: + description: If the affinity requirements specified + by this field are not met at scheduling time, the + pod will not be scheduled onto the node. If the affinity + requirements specified by this field cease to be met + at some point during pod execution (e.g. due to an + update), the system may or may not try to eventually + evict the pod from its node. + properties: + nodeSelectorTerms: + description: Required. A list of node selector terms. + The terms are ORed. + items: + description: A null or empty node selector term + matches no objects. The requirements of them + are ANDed. The TopologySelectorTerm type implements + a subset of the NodeSelectorTerm. + properties: + matchExpressions: + description: A list of node selector requirements + by node's labels. + items: + description: A node selector requirement + is a selector that contains values, a + key, and an operator that relates the + key and values. + properties: + key: + description: The label key that the + selector applies to. + type: string + operator: + description: Represents a key's relationship + to a set of values. Valid operators + are In, NotIn, Exists, DoesNotExist. + Gt, and Lt. + type: string + values: + description: An array of string values. + If the operator is In or NotIn, the + values array must be non-empty. If + the operator is Exists or DoesNotExist, + the values array must be empty. If + the operator is Gt or Lt, the values + array must have a single element, + which will be interpreted as an integer. + This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchFields: + description: A list of node selector requirements + by node's fields. + items: + description: A node selector requirement + is a selector that contains values, a + key, and an operator that relates the + key and values. + properties: + key: + description: The label key that the + selector applies to. + type: string + operator: + description: Represents a key's relationship + to a set of values. Valid operators + are In, NotIn, Exists, DoesNotExist. + Gt, and Lt. + type: string + values: + description: An array of string values. + If the operator is In or NotIn, the + values array must be non-empty. If + the operator is Exists or DoesNotExist, + the values array must be empty. If + the operator is Gt or Lt, the values + array must have a single element, + which will be interpreted as an integer. + This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + type: object + type: array + required: + - nodeSelectorTerms + type: object + type: object + podAffinity: + description: Describes pod affinity scheduling rules (e.g. + co-locate this pod in the same node, zone, etc. as some + other pod(s)). + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: The scheduler will prefer to schedule pods + to nodes that satisfy the affinity expressions specified + by this field, but it may choose a node that violates + one or more of the expressions. The node that is most + preferred is the one with the greatest sum of weights, + i.e. for each node that meets all of the scheduling + requirements (resource request, requiredDuringScheduling + affinity expressions, etc.), compute a sum by iterating + through the elements of this field and adding "weight" + to the sum if the node has pods which matches the + corresponding podAffinityTerm; the node(s) with the + highest sum are the most preferred. + items: + description: The weights of all of the matched WeightedPodAffinityTerm + fields are added per-node to find the most preferred + node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity term, associated + with the corresponding weight. + properties: + labelSelector: + description: A label query over a set of resources, + in this case pods. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The + requirements are ANDed. + items: + description: A label selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: operator represents + a key's relationship to a set + of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array + of string values. If the operator + is In or NotIn, the values array + must be non-empty. If the operator + is Exists or DoesNotExist, the + values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, + whose key field is "key", the operator + is "In", and the values array contains + only "value". The requirements are ANDed. + type: object + type: object + namespaceSelector: + description: A label query over the set of + namespaces that the term applies to. The + term is applied to the union of the namespaces + selected by this field and the ones listed + in the namespaces field. null selector and + null or empty namespaces list means "this + pod's namespace". An empty selector ({}) + matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The + requirements are ANDed. + items: + description: A label selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: operator represents + a key's relationship to a set + of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array + of string values. If the operator + is In or NotIn, the values array + must be non-empty. If the operator + is Exists or DoesNotExist, the + values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, + whose key field is "key", the operator + is "In", and the values array contains + only "value". The requirements are ANDed. + type: object + type: object + namespaces: + description: namespaces specifies a static + list of namespace names that the term applies + to. The term is applied to the union of + the namespaces listed in this field and + the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector + means "this pod's namespace". + items: + type: string + type: array + topologyKey: + description: This pod should be co-located + (affinity) or not co-located (anti-affinity) + with the pods matching the labelSelector + in the specified namespaces, where co-located + is defined as running on a node whose value + of the label with key topologyKey matches + that of any node on which any of the selected + pods is running. Empty topologyKey is not + allowed. + type: string + required: + - topologyKey + type: object + weight: + description: weight associated with matching the + corresponding podAffinityTerm, in the range + 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + requiredDuringSchedulingIgnoredDuringExecution: + description: If the affinity requirements specified + by this field are not met at scheduling time, the + pod will not be scheduled onto the node. If the affinity + requirements specified by this field cease to be met + at some point during pod execution (e.g. due to a + pod label update), the system may or may not try to + eventually evict the pod from its node. When there + are multiple elements, the lists of nodes corresponding + to each podAffinityTerm are intersected, i.e. all + terms must be satisfied. + items: + description: Defines a set of pods (namely those matching + the labelSelector relative to the given namespace(s)) + that this pod should be co-located (affinity) or + not co-located (anti-affinity) with, where co-located + is defined as running on a node whose value of the + label with key matches that of any + node on which a pod of the set of pods is running + properties: + labelSelector: + description: A label query over a set of resources, + in this case pods. + properties: + matchExpressions: + description: matchExpressions is a list of + label selector requirements. The requirements + are ANDed. + items: + description: A label selector requirement + is a selector that contains values, a + key, and an operator that relates the + key and values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, + whose key field is "key", the operator is + "In", and the values array contains only + "value". The requirements are ANDed. + type: object + type: object + namespaceSelector: + description: A label query over the set of namespaces + that the term applies to. The term is applied + to the union of the namespaces selected by this + field and the ones listed in the namespaces + field. null selector and null or empty namespaces + list means "this pod's namespace". An empty + selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list of + label selector requirements. The requirements + are ANDed. + items: + description: A label selector requirement + is a selector that contains values, a + key, and an operator that relates the + key and values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, + whose key field is "key", the operator is + "In", and the values array contains only + "value". The requirements are ANDed. + type: object + type: object + namespaces: + description: namespaces specifies a static list + of namespace names that the term applies to. + The term is applied to the union of the namespaces + listed in this field and the ones selected by + namespaceSelector. null or empty namespaces + list and null namespaceSelector means "this + pod's namespace". + items: + type: string + type: array + topologyKey: + description: This pod should be co-located (affinity) + or not co-located (anti-affinity) with the pods + matching the labelSelector in the specified + namespaces, where co-located is defined as running + on a node whose value of the label with key + topologyKey matches that of any node on which + any of the selected pods is running. Empty topologyKey + is not allowed. + type: string + required: + - topologyKey + type: object + type: array + type: object + podAntiAffinity: + description: Describes pod anti-affinity scheduling rules + (e.g. avoid putting this pod in the same node, zone, etc. + as some other pod(s)). + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: The scheduler will prefer to schedule pods + to nodes that satisfy the anti-affinity expressions + specified by this field, but it may choose a node + that violates one or more of the expressions. The + node that is most preferred is the one with the greatest + sum of weights, i.e. for each node that meets all + of the scheduling requirements (resource request, + requiredDuringScheduling anti-affinity expressions, + etc.), compute a sum by iterating through the elements + of this field and adding "weight" to the sum if the + node has pods which matches the corresponding podAffinityTerm; + the node(s) with the highest sum are the most preferred. + items: + description: The weights of all of the matched WeightedPodAffinityTerm + fields are added per-node to find the most preferred + node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity term, associated + with the corresponding weight. + properties: + labelSelector: + description: A label query over a set of resources, + in this case pods. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The + requirements are ANDed. + items: + description: A label selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: operator represents + a key's relationship to a set + of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array + of string values. If the operator + is In or NotIn, the values array + must be non-empty. If the operator + is Exists or DoesNotExist, the + values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, + whose key field is "key", the operator + is "In", and the values array contains + only "value". The requirements are ANDed. + type: object + type: object + namespaceSelector: + description: A label query over the set of + namespaces that the term applies to. The + term is applied to the union of the namespaces + selected by this field and the ones listed + in the namespaces field. null selector and + null or empty namespaces list means "this + pod's namespace". An empty selector ({}) + matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The + requirements are ANDed. + items: + description: A label selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: operator represents + a key's relationship to a set + of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array + of string values. If the operator + is In or NotIn, the values array + must be non-empty. If the operator + is Exists or DoesNotExist, the + values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, + whose key field is "key", the operator + is "In", and the values array contains + only "value". The requirements are ANDed. + type: object + type: object + namespaces: + description: namespaces specifies a static + list of namespace names that the term applies + to. The term is applied to the union of + the namespaces listed in this field and + the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector + means "this pod's namespace". + items: + type: string + type: array + topologyKey: + description: This pod should be co-located + (affinity) or not co-located (anti-affinity) + with the pods matching the labelSelector + in the specified namespaces, where co-located + is defined as running on a node whose value + of the label with key topologyKey matches + that of any node on which any of the selected + pods is running. Empty topologyKey is not + allowed. + type: string + required: + - topologyKey + type: object + weight: + description: weight associated with matching the + corresponding podAffinityTerm, in the range + 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + requiredDuringSchedulingIgnoredDuringExecution: + description: If the anti-affinity requirements specified + by this field are not met at scheduling time, the + pod will not be scheduled onto the node. If the anti-affinity + requirements specified by this field cease to be met + at some point during pod execution (e.g. due to a + pod label update), the system may or may not try to + eventually evict the pod from its node. When there + are multiple elements, the lists of nodes corresponding + to each podAffinityTerm are intersected, i.e. all + terms must be satisfied. + items: + description: Defines a set of pods (namely those matching + the labelSelector relative to the given namespace(s)) + that this pod should be co-located (affinity) or + not co-located (anti-affinity) with, where co-located + is defined as running on a node whose value of the + label with key matches that of any + node on which a pod of the set of pods is running + properties: + labelSelector: + description: A label query over a set of resources, + in this case pods. + properties: + matchExpressions: + description: matchExpressions is a list of + label selector requirements. The requirements + are ANDed. + items: + description: A label selector requirement + is a selector that contains values, a + key, and an operator that relates the + key and values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, + whose key field is "key", the operator is + "In", and the values array contains only + "value". The requirements are ANDed. + type: object + type: object + namespaceSelector: + description: A label query over the set of namespaces + that the term applies to. The term is applied + to the union of the namespaces selected by this + field and the ones listed in the namespaces + field. null selector and null or empty namespaces + list means "this pod's namespace". An empty + selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list of + label selector requirements. The requirements + are ANDed. + items: + description: A label selector requirement + is a selector that contains values, a + key, and an operator that relates the + key and values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, + whose key field is "key", the operator is + "In", and the values array contains only + "value". The requirements are ANDed. + type: object + type: object + namespaces: + description: namespaces specifies a static list + of namespace names that the term applies to. + The term is applied to the union of the namespaces + listed in this field and the ones selected by + namespaceSelector. null or empty namespaces + list and null namespaceSelector means "this + pod's namespace". + items: + type: string + type: array + topologyKey: + description: This pod should be co-located (affinity) + or not co-located (anti-affinity) with the pods + matching the labelSelector in the specified + namespaces, where co-located is defined as running + on a node whose value of the label with key + topologyKey matches that of any node on which + any of the selected pods is running. Empty topologyKey + is not allowed. + type: string + required: + - topologyKey + type: object + type: array + type: object + type: object + name: + description: Name is the operator name as requested in the OperandRequest. + type: string + replicas: + description: Number of desired pods. This is a pointer to distinguish + between explicit zero and not specified. Defaults to 1. + format: int32 + type: integer + topologySpreadConstraints: + description: TopologySpreadConstraints describes how a group + of pods ought to spread across topology domains. Scheduler + will schedule pods in a way which abides by the constraints. + All topologySpreadConstraints are ANDed. + items: + description: TopologySpreadConstraint specifies how to spread + matching pods among the given topology. + properties: + labelSelector: + description: LabelSelector is used to find matching pods. + Pods that match this label selector are counted to determine + the number of pods in their corresponding topology domain. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, + NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values + array must be non-empty. If the operator is + Exists or DoesNotExist, the values array must + be empty. This array is replaced during a + strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} pairs. + A single {key,value} in the matchLabels map is equivalent + to an element of matchExpressions, whose key field + is "key", the operator is "In", and the values array + contains only "value". The requirements are ANDed. + type: object + type: object + maxSkew: + description: 'MaxSkew describes the degree to which pods + may be unevenly distributed. When `whenUnsatisfiable=DoNotSchedule`, + it is the maximum permitted difference between the number + of matching pods in the target topology and the global + minimum. The global minimum is the minimum number of + matching pods in an eligible domain or zero if the number + of eligible domains is less than MinDomains. For example, + in a 3-zone cluster, MaxSkew is set to 1, and pods with + the same labelSelector spread as 2/2/1: In this case, + the global minimum is 1. | zone1 | zone2 | zone3 | | P + P | P P | P | - if MaxSkew is 1, incoming pod + can only be scheduled to zone3 to become 2/2/2; scheduling + it onto zone1(zone2) would make the ActualSkew(3-1) + on zone1(zone2) violate MaxSkew(1). - if MaxSkew is + 2, incoming pod can be scheduled onto any zone. When + `whenUnsatisfiable=ScheduleAnyway`, it is used to give + higher precedence to topologies that satisfy it. It''s + a required field. Default value is 1 and 0 is not allowed.' + format: int32 + type: integer + minDomains: + description: "MinDomains indicates a minimum number of + eligible domains. When the number of eligible domains + with matching topology keys is less than minDomains, + Pod Topology Spread treats \"global minimum\" as 0, + and then the calculation of Skew is performed. And when + the number of eligible domains with matching topology + keys equals or greater than minDomains, this value has + no effect on scheduling. As a result, when the number + of eligible domains is less than minDomains, scheduler + won't schedule more than maxSkew Pods to those domains. + If value is nil, the constraint behaves as if MinDomains + is equal to 1. Valid values are integers greater than + 0. When value is not nil, WhenUnsatisfiable must be + DoNotSchedule. \n For example, in a 3-zone cluster, + MaxSkew is set to 2, MinDomains is set to 5 and pods + with the same labelSelector spread as 2/2/2: | zone1 + | zone2 | zone3 | | P P | P P | P P | The number + of domains is less than 5(MinDomains), so \"global minimum\" + is treated as 0. In this situation, new pod with the + same labelSelector cannot be scheduled, because computed + skew will be 3(3 - 0) if new Pod is scheduled to any + of the three zones, it will violate MaxSkew. \n This + is an alpha field and requires enabling MinDomainsInPodTopologySpread + feature gate." + format: int32 + type: integer + topologyKey: + description: TopologyKey is the key of node labels. Nodes + that have a label with this key and identical values + are considered to be in the same topology. We consider + each as a "bucket", and try to put balanced + number of pods into each bucket. We define a domain + as a particular instance of a topology. Also, we define + an eligible domain as a domain whose nodes match the + node selector. e.g. If TopologyKey is "kubernetes.io/hostname", + each Node is a domain of that topology. And, if TopologyKey + is "topology.kubernetes.io/zone", each zone is a domain + of that topology. It's a required field. + type: string + whenUnsatisfiable: + description: 'WhenUnsatisfiable indicates how to deal + with a pod if it doesn''t satisfy the spread constraint. + - DoNotSchedule (default) tells the scheduler not to + schedule it. - ScheduleAnyway tells the scheduler to + schedule the pod in any location, but giving higher + precedence to topologies that would help reduce the skew. + A constraint is considered "Unsatisfiable" for an incoming + pod if and only if every possible node assignment for + that pod would violate "MaxSkew" on some topology. For + example, in a 3-zone cluster, MaxSkew is set to 1, and + pods with the same labelSelector spread as 3/1/1: | + zone1 | zone2 | zone3 | | P P P | P | P | If + WhenUnsatisfiable is set to DoNotSchedule, incoming + pod can only be scheduled to zone2(zone3) to become + 3/2/1(3/1/2) as ActualSkew(2-1) on zone2(zone3) satisfies + MaxSkew(1). In other words, the cluster can still be + imbalanced, but scheduler won''t make it *more* imbalanced. + It''s a required field.' + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array + x-kubernetes-list-map-keys: + - topologyKey + - whenUnsatisfiable + x-kubernetes-list-type: map + required: + - name + type: object + type: array + x-kubernetes-preserve-unknown-fields: true type: object + x-kubernetes-preserve-unknown-fields: true status: description: OperatorConfigStatus defines the observed state of OperatorConfig type: object + x-kubernetes-preserve-unknown-fields: true type: object served: true storage: true diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml index 8833a2e1..fdd077c2 100644 --- a/config/rbac/role.yaml +++ b/config/rbac/role.yaml @@ -59,6 +59,9 @@ rules: - operandbindinfos - operandbindinfos/status - operandbindinfos/finalizers + - operatorconfigs + - operatorconfigs/status + - operatorconfigs/finalizers - verbs: - create - delete diff --git a/controllers/operatorconfig/operatorconfig_controller.go b/controllers/operatorconfig/operatorconfig_controller.go index 9abeab89..a00f90ae 100644 --- a/controllers/operatorconfig/operatorconfig_controller.go +++ b/controllers/operatorconfig/operatorconfig_controller.go @@ -19,8 +19,19 @@ package operatorconfig import ( "context" + "github.com/barkimedes/go-deepcopy" + olmv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1" + "k8s.io/apimachinery/pkg/types" + "k8s.io/klog" ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/builder" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/event" + "sigs.k8s.io/controller-runtime/pkg/handler" "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/predicate" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + "sigs.k8s.io/controller-runtime/pkg/source" operatorv1alpha1 "github.com/IBM/operand-deployment-lifecycle-manager/api/v1alpha1" deploy "github.com/IBM/operand-deployment-lifecycle-manager/controllers/operator" @@ -47,14 +58,111 @@ type Reconciler struct { func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { _ = log.FromContext(ctx) - // TODO(user): your logic here + instance := &operatorv1alpha1.OperandRequest{} + if err := r.Client.Get(ctx, req.NamespacedName, instance); err != nil { + return ctrl.Result{}, client.IgnoreNotFound(err) + } + klog.Infof("Reconciling OperatorConfig for request: %s, %s", instance.Namespace, instance.Name) + + for _, v := range instance.Spec.Requests { + reqBlock := v + registry, err := r.GetOperandRegistry(ctx, instance.GetRegistryKey(reqBlock)) + if err != nil { + return ctrl.Result{}, err + } + for _, u := range reqBlock.Operands { + operand := u + operator := registry.GetOperator(operand.Name) + if operator.OperatorConfig == "" { + break + } + + var sub *olmv1alpha1.Subscription + sub, err = r.GetSubscription(ctx, operator.Name, operator.Namespace, registry.Namespace, operator.PackageName) + if err != nil { + return ctrl.Result{}, err + } + + var csv *olmv1alpha1.ClusterServiceVersion + csv, err = r.GetClusterServiceVersion(ctx, sub) + if err != nil { + return ctrl.Result{}, err + } + + klog.Infof("Fetching OperatorConfig: %s", operator.OperatorConfig) + config := &operatorv1alpha1.OperatorConfig{} + if err := r.Client.Get(ctx, types.NamespacedName{ + Name: operator.OperatorConfig, + Namespace: registry.Namespace, + }, config); err != nil { + return ctrl.Result{}, client.IgnoreNotFound(err) + } + serviceConfig := config.GetConfigForOperator(operator.Name) + if serviceConfig == nil { + klog.Infof("OperatorConfig: %s, does not have configuration for operator: %s", operator.OperatorConfig, operator.Name) + return ctrl.Result{}, nil + } + + copyToCast, err := deepcopy.Anything(csv) + if err != nil { + return ctrl.Result{}, err + } + csvToUpdate := copyToCast.(*olmv1alpha1.ClusterServiceVersion) + klog.Infof("Applying OperatorConfig: %s to Operator: %s via CSV: %s, %s", operator.OperatorConfig, operator.Name, csv.Name, csv.Namespace) + return r.configCsv(ctx, csvToUpdate, serviceConfig) + } + } return ctrl.Result{}, nil } +func (r *Reconciler) configCsv(ctx context.Context, csv *olmv1alpha1.ClusterServiceVersion, config *operatorv1alpha1.ServiceOperatorConfig) (ctrl.Result, error) { + if config.Replicas != nil { + csv.Spec.InstallStrategy.StrategySpec.DeploymentSpecs[0].Spec.Replicas = config.Replicas + } + if config.Affinity != nil { + csv.Spec.InstallStrategy.StrategySpec.DeploymentSpecs[0].Spec.Template.Spec.Affinity = config.Affinity + } + if config.TopologySpreadConstraints != nil { + csv.Spec.InstallStrategy.StrategySpec.DeploymentSpecs[0].Spec.Template.Spec.TopologySpreadConstraints = config.TopologySpreadConstraints + } + if err := r.Client.Update(ctx, csv); err != nil { + return ctrl.Result{}, err + } + return ctrl.Result{}, nil +} + +func (r *Reconciler) requestsFromMapFunc(ctx context.Context) handler.MapFunc { + return func(object client.Object) []reconcile.Request { + requests := []reconcile.Request{} + + operandRequests, _ := r.ListOperandRequests(ctx, nil) + for _, req := range operandRequests.Items { + r := reconcile.Request{ + NamespacedName: types.NamespacedName{ + Namespace: req.Namespace, + Name: req.Name, + }, + } + requests = append(requests, r) + } + return requests + } +} + // SetupWithManager sets up the controller with the Manager. func (r *Reconciler) SetupWithManager(mgr ctrl.Manager) error { + ctx := context.Background() return ctrl.NewControllerManagedBy(mgr). - For(&operatorv1alpha1.OperatorConfig{}). + For(&operatorv1alpha1.OperandRequest{}). + Watches(&source.Kind{Type: &operatorv1alpha1.OperatorConfig{}}, handler.EnqueueRequestsFromMapFunc(r.requestsFromMapFunc(ctx)), builder.WithPredicates(predicate.Funcs{ + CreateFunc: func(e event.CreateEvent) bool { + return true + }, + DeleteFunc: func(e event.DeleteEvent) bool { + // Evaluates to false if the object has been confirmed deleted. + return !e.DeleteStateUnknown + }, + })). Complete(r) } diff --git a/go.mod b/go.mod index 86f98feb..fdda194f 100644 --- a/go.mod +++ b/go.mod @@ -20,6 +20,7 @@ require ( github.com/stretchr/testify v1.9.0 golang.org/x/mod v0.8.0 k8s.io/api v0.24.3 + k8s.io/apiextensions-apiserver v0.24.2 k8s.io/apimachinery v0.24.3 k8s.io/client-go v0.24.3 k8s.io/klog v1.0.0 @@ -101,7 +102,6 @@ require ( gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/apiextensions-apiserver v0.24.2 // indirect k8s.io/component-base v0.24.2 // indirect k8s.io/klog/v2 v2.60.1 // indirect k8s.io/kube-openapi v0.0.0-20220627174259-011e075b9cb8 // indirect From b707a0b700ef0d85681b2cbacad34829cd4ba037 Mon Sep 17 00:00:00 2001 From: Daniel Fan Date: Mon, 1 Apr 2024 23:18:58 -0400 Subject: [PATCH 090/179] Support uninstallation on intra-dependency (#1028) * Support uninstallation on intra-dependency Signed-off-by: Daniel Fan * update manifest Signed-off-by: Daniel Fan --------- Signed-off-by: Daniel Fan --- Makefile | 5 +- api/v1alpha1/operandbindinfo_types.go | 2 +- api/v1alpha1/operandconfig_types.go | 2 +- api/v1alpha1/operandregistry_types.go | 2 +- api/v1alpha1/operandrequest_types.go | 2 +- api/v1alpha1/operatorconfig_types.go | 2 +- bundle.Dockerfile | 2 +- ...fecycle-manager.clusterserviceversion.yaml | 116 +- .../operator.ibm.com_operandbindinfos.yaml | 70 +- .../operator.ibm.com_operandconfigs.yaml | 39 +- .../operator.ibm.com_operandregistries.yaml | 1771 ++++++++-------- .../operator.ibm.com_operandrequests.yaml | 89 +- .../operator.ibm.com_operatorconfigs.yaml | 950 ++++----- bundle/metadata/annotations.yaml | 2 +- .../operator.ibm.com_operandbindinfos.yaml | 74 +- .../operator.ibm.com_operandconfigs.yaml | 43 +- .../operator.ibm.com_operandregistries.yaml | 1775 ++++++++--------- .../operator.ibm.com_operandrequests.yaml | 93 +- .../operator.ibm.com_operatorconfigs.yaml | 954 ++++----- ...fecycle-manager.clusterserviceversion.yaml | 21 +- config/rbac/role.yaml | 119 +- controllers/constant/constant.go | 3 + .../operandbindinfo_controller.go | 2 + .../operandconfig/operandconfig_controller.go | 2 + .../operandregistry_controller.go | 2 + .../operandrequest_controller.go | 12 + .../operandrequest/reconcile_operand.go | 3 +- .../operandrequest/reconcile_operator.go | 151 +- .../operandrequest/reconcile_operator_test.go | 240 +++ .../operatorconfig_controller.go | 4 +- controllers/util/util.go | 9 + controllers/util/util_test.go | 40 + 32 files changed, 3376 insertions(+), 3225 deletions(-) create mode 100644 controllers/operandrequest/reconcile_operator_test.go diff --git a/Makefile b/Makefile index c42fb8d3..fe7e856e 100644 --- a/Makefile +++ b/Makefile @@ -100,9 +100,6 @@ BUNDLE_DEFAULT_CHANNEL := --default-channel=$(DEFAULT_CHANNEL) endif BUNDLE_METADATA_OPTS ?= $(BUNDLE_CHANNELS) $(BUNDLE_DEFAULT_CHANNEL) -# Produce CRDs that work back to Kubernetes 1.11 (no version conversion) -CRD_OPTIONS ?= "crd:trivialVersions=true" - # Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set) ifeq (,$(shell go env GOBIN)) GOBIN=$(shell go env GOPATH)/bin @@ -199,7 +196,7 @@ deploy-e2e: kustomize ## Deploy controller in the configured Kubernetes cluster ##@ Generate code and manifests manifests: controller-gen ## Generate manifests e.g. CRD, RBAC etc. - $(CONTROLLER_GEN) $(CRD_OPTIONS) rbac:roleName=operand-deployment-lifecycle-manager webhook paths="./..." output:crd:artifacts:config=config/crd/bases + $(CONTROLLER_GEN) crd rbac:roleName=operand-deployment-lifecycle-manager webhook paths="./..." output:crd:artifacts:config=config/crd/bases generate: controller-gen ## Generate code e.g. API etc. $(CONTROLLER_GEN) object:headerFile="hack/boilerplate.go.txt" paths="./..." diff --git a/api/v1alpha1/operandbindinfo_types.go b/api/v1alpha1/operandbindinfo_types.go index 35cb293b..f65fff28 100644 --- a/api/v1alpha1/operandbindinfo_types.go +++ b/api/v1alpha1/operandbindinfo_types.go @@ -118,7 +118,7 @@ type OperandBindInfoStatus struct { // +kubebuilder:object:root=true // +kubebuilder:subresource:status -// OperandBindInfo is the Schema for the operandbindinfoes API. +// OperandBindInfo is the Schema for the operandbindinfoes API. Documentation For additional details regarding install parameters check https://ibm.biz/icpfs39install. License By installing this product you accept the license terms https://ibm.biz/icpfs39license // +kubebuilder:subresource:status // +kubebuilder:resource:path=operandbindinfos,shortName=opbi,scope=Namespaced // +kubebuilder:printcolumn:name="Age",type=date,JSONPath=.metadata.creationTimestamp diff --git a/api/v1alpha1/operandconfig_types.go b/api/v1alpha1/operandconfig_types.go index 8f8370a0..4b4e643f 100644 --- a/api/v1alpha1/operandconfig_types.go +++ b/api/v1alpha1/operandconfig_types.go @@ -117,7 +117,7 @@ type CrStatus struct { CrStatus map[string]ServicePhase `json:"customResourceStatus,omitempty"` } -// OperandConfig is the Schema for the operandconfigs API. +// OperandConfig is the Schema for the operandconfigs API. Documentation For additional details regarding install parameters check https://ibm.biz/icpfs39install. License By installing this product you accept the license terms https://ibm.biz/icpfs39license // +kubebuilder:object:root=true // +kubebuilder:subresource:status // +kubebuilder:resource:path=operandconfigs,shortName=opcon,scope=Namespaced diff --git a/api/v1alpha1/operandregistry_types.go b/api/v1alpha1/operandregistry_types.go index edea7ae0..94955f3b 100644 --- a/api/v1alpha1/operandregistry_types.go +++ b/api/v1alpha1/operandregistry_types.go @@ -148,7 +148,7 @@ type ReconcileRequest struct { // +kubebuilder:printcolumn:name="Created At",type=string,JSONPath=.metadata.creationTimestamp // +operator-sdk:csv:customresourcedefinitions:displayName="OperandRegistry" -// OperandRegistry is the Schema for the operandregistries API. +// OperandRegistry is the Schema for the operandregistries API. Documentation For additional details regarding install parameters check https://ibm.biz/icpfs39install. License By installing this product you accept the license terms https://ibm.biz/icpfs39license type OperandRegistry struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` diff --git a/api/v1alpha1/operandrequest_types.go b/api/v1alpha1/operandrequest_types.go index 349a57df..d99d416d 100644 --- a/api/v1alpha1/operandrequest_types.go +++ b/api/v1alpha1/operandrequest_types.go @@ -245,7 +245,7 @@ type MemberStatus struct { // +kubebuilder:printcolumn:name="Created At",type=string,JSONPath=.metadata.creationTimestamp // +operator-sdk:csv:customresourcedefinitions:displayName="OperandRequest" -// OperandRequest is the Schema for the operandrequests API. +// OperandRequest is the Schema for the operandrequests API. Documentation For additional details regarding install parameters check https://ibm.biz/icpfs39install. License By installing this product you accept the license terms https://ibm.biz/icpfs39license type OperandRequest struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` diff --git a/api/v1alpha1/operatorconfig_types.go b/api/v1alpha1/operatorconfig_types.go index 643dbedd..a35494de 100644 --- a/api/v1alpha1/operatorconfig_types.go +++ b/api/v1alpha1/operatorconfig_types.go @@ -68,7 +68,7 @@ type OperatorConfigStatus struct { //+kubebuilder:object:root=true //+kubebuilder:subresource:status -// OperatorConfig is the Schema for the operatorconfigs API +// OperatorConfig is the Schema for the operatorconfigs API. Documentation For additional details regarding install parameters check https://ibm.biz/icpfs39install. License By installing this product you accept the license terms https://ibm.biz/icpfs39license type OperatorConfig struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` diff --git a/bundle.Dockerfile b/bundle.Dockerfile index 6f953fb9..162e5db1 100644 --- a/bundle.Dockerfile +++ b/bundle.Dockerfile @@ -7,7 +7,7 @@ LABEL operators.operatorframework.io.bundle.metadata.v1=metadata/ LABEL operators.operatorframework.io.bundle.package.v1=ibm-odlm LABEL operators.operatorframework.io.bundle.channels.v1=v4.3 LABEL operators.operatorframework.io.bundle.channel.default.v1=v4.3 -LABEL operators.operatorframework.io.metrics.builder=operator-sdk-v1.29.0 +LABEL operators.operatorframework.io.metrics.builder=operator-sdk-v1.32.0 LABEL operators.operatorframework.io.metrics.mediatype.v1=metrics+v1 LABEL operators.operatorframework.io.metrics.project_layout=go.kubebuilder.io/v3 diff --git a/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml b/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml index df1d3384..745b750c 100644 --- a/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml +++ b/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml @@ -129,12 +129,12 @@ metadata: categories: Developer Tools, Monitoring, Logging & Tracing, Security certified: "false" containerImage: icr.io/cpopen/odlm:latest - createdAt: "2024-03-29T03:10:47Z" + createdAt: "2024-04-02T02:16:34Z" description: The Operand Deployment Lifecycle Manager provides a Kubernetes CRD-based API to manage the lifecycle of operands. nss.operator.ibm.com/managed-operators: ibm-odlm olm.skipRange: '>=1.2.0 <4.3.0' operators.openshift.io/infrastructure-features: '["disconnected"]' - operators.operatorframework.io/builder: operator-sdk-v1.29.0 + operators.operatorframework.io/builder: operator-sdk-v1.32.0 operators.operatorframework.io/project_layout: go.kubebuilder.io/v3 repository: https://github.com/IBM/operand-deployment-lifecycle-manager support: IBM @@ -149,7 +149,7 @@ spec: apiservicedefinitions: {} customresourcedefinitions: owned: - - description: OperandBindInfo is the Schema for the operandbindinfoes API. + - description: OperandBindInfo is the Schema for the operandbindinfoes API. Documentation For additional details regarding install parameters check https://ibm.biz/icpfs39install. License By installing this product you accept the license terms https://ibm.biz/icpfs39license displayName: OperandBindInfo kind: OperandBindInfo name: operandbindinfos.operator.ibm.com @@ -160,7 +160,7 @@ spec: x-descriptors: - urn:alm:descriptor:io.kubernetes.phase version: v1alpha1 - - description: OperandConfig is the Schema for the operandconfigs API. + - description: OperandConfig is the Schema for the operandconfigs API. Documentation For additional details regarding install parameters check https://ibm.biz/icpfs39install. License By installing this product you accept the license terms https://ibm.biz/icpfs39license displayName: OperandConfig kind: OperandConfig name: operandconfigs.operator.ibm.com @@ -175,7 +175,7 @@ spec: x-descriptors: - urn:alm:descriptor:io.kubernetes.phase version: v1alpha1 - - description: OperandRegistry is the Schema for the operandregistries API. + - description: OperandRegistry is the Schema for the operandregistries API. Documentation For additional details regarding install parameters check https://ibm.biz/icpfs39install. License By installing this product you accept the license terms https://ibm.biz/icpfs39license displayName: OperandRegistry kind: OperandRegistry name: operandregistries.operator.ibm.com @@ -195,7 +195,7 @@ spec: x-descriptors: - urn:alm:descriptor:io.kubernetes.phase version: v1alpha1 - - description: OperandRequest is the Schema for the operandrequests API. + - description: OperandRequest is the Schema for the operandrequests API. Documentation For additional details regarding install parameters check https://ibm.biz/icpfs39install. License By installing this product you accept the license terms https://ibm.biz/icpfs39license displayName: OperandRequest kind: OperandRequest name: operandrequests.operator.ibm.com @@ -215,7 +215,9 @@ spec: x-descriptors: - urn:alm:descriptor:io.kubernetes.phase version: v1alpha1 - - kind: OperatorConfig + - description: OperatorConfig is the Schema for the operatorconfigs API + displayName: Operator Config + kind: OperatorConfig name: operatorconfigs.operator.ibm.com version: v1alpha1 description: |- @@ -567,19 +569,19 @@ spec: clusterPermissions: - rules: - apiGroups: - - operators.coreos.com + - operator.ibm.com resources: - - catalogsources + - auditloggings + - certmanagers verbs: + - delete - get - apiGroups: - - operator.ibm.com + - operators.coreos.com resources: - - certmanagers - - auditloggings + - catalogsources verbs: - get - - delete serviceAccountName: operand-deployment-lifecycle-manager deployments: - label: @@ -674,6 +676,21 @@ spec: terminationGracePeriodSeconds: 10 permissions: - rules: + - apiGroups: + - "" + resources: + - configmaps + - namespaces + - secrets + - services + verbs: + - create + - delete + - get + - list + - patch + - update + - watch - apiGroups: - '*' resources: @@ -686,24 +703,39 @@ spec: - patch - update - watch + - apiGroups: + - k8s.keycloak.org + resources: + - keycloakrealmimports + - keycloaks + verbs: + - create + - delete + - get + - list + - patch + - update + - watch - apiGroups: - operator.ibm.com resources: - operandconfigs - - operandconfigs/status - operandconfigs/finalizers + - operandconfigs/status + verbs: + - create + - delete + - get + - list + - patch + - update + - watch + - apiGroups: + - operator.ibm.com + resources: - operandregistries - - operandregistries/status - operandregistries/finalizers - - operandrequests - - operandrequests/status - - operandrequests/finalizers - - operandbindinfos - - operandbindinfos/status - - operandbindinfos/finalizers - - operatorconfigs - - operatorconfigs/status - - operatorconfigs/finalizers + - operandregistries/status verbs: - create - delete @@ -713,12 +745,11 @@ spec: - update - watch - apiGroups: - - "" + - operator.ibm.com resources: - - configmaps - - secrets - - services - - namespaces + - operandrequests + - operandrequests/finalizers + - operandrequests/status verbs: - create - delete @@ -728,9 +759,11 @@ spec: - update - watch - apiGroups: - - route.openshift.io + - operator.ibm.com resources: - - routes + - operatorconfigs + - operatorconfigs/finalizers + - operatorconfigs/status verbs: - create - delete @@ -742,8 +775,8 @@ spec: - apiGroups: - operators.coreos.com resources: - - operatorgroups - - installplans + - clusterserviceversions + - subscriptions verbs: - create - delete @@ -753,9 +786,10 @@ spec: - update - watch - apiGroups: - - k8s.keycloak.org + - operators.coreos.com resources: - - keycloaks + - installplans + - operatorgroups verbs: - create - delete @@ -774,6 +808,18 @@ spec: - patch - update - watch + - apiGroups: + - route.openshift.io + resources: + - routes + verbs: + - create + - delete + - get + - list + - patch + - update + - watch serviceAccountName: operand-deployment-lifecycle-manager strategy: deployment installModes: diff --git a/bundle/manifests/operator.ibm.com_operandbindinfos.yaml b/bundle/manifests/operator.ibm.com_operandbindinfos.yaml index ede2685f..bea8cfed 100644 --- a/bundle/manifests/operator.ibm.com_operandbindinfos.yaml +++ b/bundle/manifests/operator.ibm.com_operandbindinfos.yaml @@ -2,7 +2,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.6.1 + controller-gen.kubebuilder.io/version: v0.14.0 creationTimestamp: null labels: app.kubernetes.io/instance: operand-deployment-lifecycle-manager @@ -35,16 +35,24 @@ spec: schema: openAPIV3Schema: description: OperandBindInfo is the Schema for the operandbindinfoes API. + Documentation For additional details regarding install parameters check + https://ibm.biz/icpfs39install. License By installing this product you accept + the license terms https://ibm.biz/icpfs39license properties: apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources type: string kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds type: string metadata: type: object @@ -53,12 +61,13 @@ spec: properties: bindings: additionalProperties: - description: Bindable is a Kubernetes resources to be shared from - one namespace to another. List of supported resources are Secrets, - Configmaps, Services, and Routes. Secrets and Configmaps will - be copied such that a new Secret/Configmap with exactly the same - data will be created in the target namespace. Services and Routes - data will be copied into a configmap in the target namespace. + description: |- + Bindable is a Kubernetes resources to be shared from one namespace to another. + List of supported resources are Secrets, Configmaps, Services, and Routes. + Secrets and Configmaps will be copied such that a new Secret/Configmap with + exactly the same data will be created in the target namespace. + Services and Routes data will be copied into a configmap in the target + namespace. properties: configmap: description: The configmap identifies an existing configmap @@ -66,15 +75,16 @@ spec: of the OperandRequest. type: string route: - description: Route data will be shared by copying it into a - configmap which is then created in the target namespace + description: |- + Route data will be shared by copying it into a configmap which is then + created in the target namespace properties: data: additionalProperties: type: string - description: Data is a key-value pair where the value is - a YAML path to a value in the OpenShift Route, e.g. .spec.host - or .spec.tls.termination + description: |- + Data is a key-value pair where the value is a YAML path to a value in the + OpenShift Route, e.g. .spec.host or .spec.tls.termination type: object name: description: Name is the name of the OpenShift Route resource @@ -85,15 +95,16 @@ spec: exists, the ODLM will share to the namespace of the OperandRequest. type: string service: - description: Service data will be shared by copying it into - a configmap which is then created in the target namespace + description: |- + Service data will be shared by copying it into a configmap which is then + created in the target namespace properties: data: additionalProperties: type: string - description: Data is a key-value pair where the value is - a YAML path to a value in the Kubernetes Service, e.g. - .spec.ports[0]port + description: |- + Data is a key-value pair where the value is a YAML path to a value in the + Kubernetes Service, e.g. .spec.ports[0]port type: object name: description: Name is the name of the Kubernetes Service @@ -107,7 +118,8 @@ spec: description: type: string operand: - description: The deployed service identifies itself with its operand. + description: |- + The deployed service identifies itself with its operand. This must match the name in the OperandRegistry in the current namespace. type: string registry: @@ -115,9 +127,9 @@ spec: CR from which this operand deployment is being requested. type: string registryNamespace: - description: Specifies the namespace in which the OperandRegistry - reside. The default is the current namespace in which the request - is defined. + description: |- + Specifies the namespace in which the OperandRegistry reside. + The default is the current namespace in which the request is defined. type: string required: - operand @@ -146,5 +158,5 @@ status: acceptedNames: kind: "" plural: "" - conditions: [] - storedVersions: [] + conditions: null + storedVersions: null diff --git a/bundle/manifests/operator.ibm.com_operandconfigs.yaml b/bundle/manifests/operator.ibm.com_operandconfigs.yaml index e30855ab..d0950bb8 100644 --- a/bundle/manifests/operator.ibm.com_operandconfigs.yaml +++ b/bundle/manifests/operator.ibm.com_operandconfigs.yaml @@ -2,7 +2,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.6.1 + controller-gen.kubebuilder.io/version: v0.14.0 creationTimestamp: null labels: app.kubernetes.io/instance: operand-deployment-lifecycle-manager @@ -34,17 +34,24 @@ spec: name: v1alpha1 schema: openAPIV3Schema: - description: OperandConfig is the Schema for the operandconfigs API. + description: OperandConfig is the Schema for the operandconfigs API. Documentation + For additional details regarding install parameters check https://ibm.biz/icpfs39install. + License By installing this product you accept the license terms https://ibm.biz/icpfs39license properties: apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources type: string kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds type: string metadata: type: object @@ -110,14 +117,16 @@ spec: description: API version of the referent. type: string blockOwnerDeletion: - description: If true, AND if the owner has the "foregroundDeletion" - finalizer, then the owner cannot be deleted from - the key-value store until this reference is removed. + description: |- + If true, AND if the owner has the "foregroundDeletion" finalizer, then + the owner cannot be deleted from the key-value store until this + reference is removed. Defaults to false. type: boolean controller: - description: If true, this reference points to the - managing controller. Default is false. + description: |- + If true, this reference points to the managing controller. + Default is false. type: boolean kind: description: Kind of the referent. @@ -183,5 +192,5 @@ status: acceptedNames: kind: "" plural: "" - conditions: [] - storedVersions: [] + conditions: null + storedVersions: null diff --git a/bundle/manifests/operator.ibm.com_operandregistries.yaml b/bundle/manifests/operator.ibm.com_operandregistries.yaml index 95efd0ae..a8f57f4e 100644 --- a/bundle/manifests/operator.ibm.com_operandregistries.yaml +++ b/bundle/manifests/operator.ibm.com_operandregistries.yaml @@ -2,7 +2,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.6.1 + controller-gen.kubebuilder.io/version: v0.14.0 creationTimestamp: null labels: app.kubernetes.io/instance: operand-deployment-lifecycle-manager @@ -35,16 +35,24 @@ spec: schema: openAPIV3Schema: description: OperandRegistry is the Schema for the operandregistries API. + Documentation For additional details regarding install parameters check + https://ibm.biz/icpfs39install. License By installing this product you accept + the license terms https://ibm.biz/icpfs39license properties: apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources type: string kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds type: string metadata: type: object @@ -63,27 +71,28 @@ spec: description: Description of a common service. type: string installMode: - description: 'The install mode of an operator, either namespace - or cluster. Valid values are: - "namespace" (default): operator - is deployed in namespace of OperandRegistry; - "cluster": - operator is deployed in "openshift-operators" namespace; - - "no-op": operator is not supported to be fresh deployed;' + description: |- + The install mode of an operator, either namespace or cluster. + Valid values are: + - "namespace" (default): operator is deployed in namespace of OperandRegistry; + - "cluster": operator is deployed in "openshift-operators" namespace; + - "no-op": operator is not supported to be fresh deployed; type: string installPlanApproval: - description: 'Approval mode for emitted InstallPlans. Valid - values are: - "Automatic" (default): operator will be installed - automatically; - "Manual": operator installation will be pending - until users approve it;' + description: |- + Approval mode for emitted InstallPlans. + Valid values are: + - "Automatic" (default): operator will be installed automatically; + - "Manual": operator installation will be pending until users approve it; type: string name: description: A unique name for the operator whose operand may be deployed. type: string namespace: - description: The namespace in which operator should be deployed - when InstallMode is empty or set to "namespace". If the namespace - is not set, the operator namespace is the same as OperandRegistry - Namespace + description: |- + The namespace in which operator should be deployed when InstallMode is empty or set to "namespace". + If the namespace is not set, the operator namespace is the same as OperandRegistry Namespace type: string operatorConfig: description: OperatorConfig is the name of the OperatorConfig @@ -92,10 +101,11 @@ spec: description: Name of the package that defines the applications. type: string scope: - description: 'A scope indicator, either public or private. Valid - values are: - "private" (default): deployment only request - from the containing names; - "public": deployment can be requested - from other namespaces;' + description: |- + A scope indicator, either public or private. + Valid values are: + - "private" (default): deployment only request from the containing names; + - "public": deployment can be requested from other namespaces; enum: - public - private @@ -116,8 +126,9 @@ spec: configuration. properties: env: - description: Env is a list of environment variables to set - in the container. Cannot be updated. + description: |- + Env is a list of environment variables to set in the container. + Cannot be updated. items: description: EnvVar represents an environment variable present in a Container. @@ -127,17 +138,16 @@ spec: be a C_IDENTIFIER. type: string value: - description: 'Variable references $(VAR_NAME) are - expanded using the previously defined environment - variables in the container and any service environment - variables. If a variable cannot be resolved, the - reference in the input string will be unchanged. - Double $$ are reduced to a single $, which allows - for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" - will produce the string literal "$(VAR_NAME)". Escaped - references will never be expanded, regardless of - whether the variable exists or not. Defaults to - "".' + description: |- + Variable references $(VAR_NAME) are expanded + using the previously defined environment variables in the container and + any service environment variables. If a variable cannot be resolved, + the reference in the input string will be unchanged. Double $$ are reduced + to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. + "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". + Escaped references will never be expanded, regardless of whether the variable + exists or not. + Defaults to "". type: string valueFrom: description: Source for the environment variable's @@ -150,10 +160,10 @@ spec: description: The key to select. type: string name: - description: 'Name of the referent. More info: - https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, - kind, uid?' + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? type: string optional: description: Specify whether the ConfigMap @@ -162,12 +172,11 @@ spec: required: - key type: object + x-kubernetes-map-type: atomic fieldRef: - description: 'Selects a field of the pod: supports - metadata.name, metadata.namespace, `metadata.labels['''']`, - `metadata.annotations['''']`, spec.nodeName, - spec.serviceAccountName, status.hostIP, status.podIP, - status.podIPs.' + description: |- + Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['']`, `metadata.annotations['']`, + spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs. properties: apiVersion: description: Version of the schema the FieldPath @@ -180,12 +189,11 @@ spec: required: - fieldPath type: object + x-kubernetes-map-type: atomic resourceFieldRef: - description: 'Selects a resource of the container: - only resources limits and requests (limits.cpu, - limits.memory, limits.ephemeral-storage, requests.cpu, - requests.memory and requests.ephemeral-storage) - are currently supported.' + description: |- + Selects a resource of the container: only resources limits and requests + (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported. properties: containerName: description: 'Container name: required for @@ -205,6 +213,7 @@ spec: required: - resource type: object + x-kubernetes-map-type: atomic secretKeyRef: description: Selects a key of a secret in the pod's namespace @@ -214,10 +223,10 @@ spec: from. Must be a valid secret key. type: string name: - description: 'Name of the referent. More info: - https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, - kind, uid?' + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? type: string optional: description: Specify whether the Secret or @@ -226,19 +235,20 @@ spec: required: - key type: object + x-kubernetes-map-type: atomic type: object required: - name type: object type: array envFrom: - description: EnvFrom is a list of sources to populate environment - variables in the container. The keys defined within a - source must be a C_IDENTIFIER. All invalid keys will be - reported as an event when the container is starting. When - a key exists in multiple sources, the value associated - with the last source will take precedence. Values defined - by an Env with a duplicate key will take precedence. Immutable. + description: |- + EnvFrom is a list of sources to populate environment variables in the container. + The keys defined within a source must be a C_IDENTIFIER. All invalid keys + will be reported as an event when the container is starting. When a key exists in multiple + sources, the value associated with the last source will take precedence. + Values defined by an Env with a duplicate key will take precedence. + Immutable. items: description: EnvFromSource represents the source of a set of ConfigMaps @@ -247,16 +257,17 @@ spec: description: The ConfigMap to select from properties: name: - description: 'Name of the referent. More info: - https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, kind, - uid?' + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? type: string optional: description: Specify whether the ConfigMap must be defined type: boolean type: object + x-kubernetes-map-type: atomic prefix: description: An optional identifier to prepend to each key in the ConfigMap. Must be a C_IDENTIFIER. @@ -265,29 +276,32 @@ spec: description: The Secret to select from properties: name: - description: 'Name of the referent. More info: - https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, kind, - uid?' + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? type: string optional: description: Specify whether the Secret must be defined type: boolean type: object + x-kubernetes-map-type: atomic type: object type: array nodeSelector: additionalProperties: type: string - description: 'NodeSelector is a selector which must be true - for the pod to fit on a node. Selector which must match - a node''s labels for the pod to be scheduled on that node. - More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/' + description: |- + NodeSelector is a selector which must be true for the pod to fit on a node. + Selector which must match a node's labels for the pod to be scheduled on that node. + More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ type: object resources: - description: 'Resources represents compute resources required - by this container. Immutable. More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/' + description: |- + Resources represents compute resources required by this container. + Immutable. + More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/ properties: limits: additionalProperties: @@ -296,8 +310,9 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: 'Limits describes the maximum amount of - compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object requests: additionalProperties: @@ -306,25 +321,26 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: 'Requests describes the minimum amount - of compute resources required. If Requests is omitted - for a container, it defaults to Limits if that is - explicitly specified, otherwise to an implementation-defined - value. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object type: object selector: - description: Selector is the label selector for pods to - be configured. Existing ReplicaSets whose pods are selected - by this will be the ones affected by this deployment. + description: |- + Selector is the label selector for pods to be configured. + Existing ReplicaSets whose pods are + selected by this will be the ones affected by this deployment. It must match the pod template's labels. properties: matchExpressions: description: matchExpressions is a list of label selector requirements. The requirements are ANDed. items: - description: A label selector requirement is a selector - that contains values, a key, and an operator that + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. properties: key: @@ -332,17 +348,16 @@ spec: applies to. type: string operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, - NotIn, Exists and DoesNotExist. + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. type: string values: - description: values is an array of string values. - If the operator is In or NotIn, the values array - must be non-empty. If the operator is Exists - or DoesNotExist, the values array must be empty. - This array is replaced during a strategic merge - patch. + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. items: type: string type: array @@ -354,53 +369,49 @@ spec: matchLabels: additionalProperties: type: string - description: matchLabels is a map of {key,value} pairs. - A single {key,value} in the matchLabels map is equivalent - to an element of matchExpressions, whose key field - is "key", the operator is "In", and the values array - contains only "value". The requirements are ANDed. + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. type: object type: object + x-kubernetes-map-type: atomic tolerations: description: Tolerations are the pod's tolerations. items: - description: The pod this Toleration is attached to tolerates - any taint that matches the triple - using the matching operator . + description: |- + The pod this Toleration is attached to tolerates any taint that matches + the triple using the matching operator . properties: effect: - description: Effect indicates the taint effect to - match. Empty means match all taint effects. When - specified, allowed values are NoSchedule, PreferNoSchedule - and NoExecute. + description: |- + Effect indicates the taint effect to match. Empty means match all taint effects. + When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. type: string key: - description: Key is the taint key that the toleration - applies to. Empty means match all taint keys. If - the key is empty, operator must be Exists; this - combination means to match all values and all keys. + description: |- + Key is the taint key that the toleration applies to. Empty means match all taint keys. + If the key is empty, operator must be Exists; this combination means to match all values and all keys. type: string operator: - description: Operator represents a key's relationship - to the value. Valid operators are Exists and Equal. - Defaults to Equal. Exists is equivalent to wildcard - for value, so that a pod can tolerate all taints - of a particular category. + description: |- + Operator represents a key's relationship to the value. + Valid operators are Exists and Equal. Defaults to Equal. + Exists is equivalent to wildcard for value, so that a pod can + tolerate all taints of a particular category. type: string tolerationSeconds: - description: TolerationSeconds represents the period - of time the toleration (which must be of effect - NoExecute, otherwise this field is ignored) tolerates - the taint. By default, it is not set, which means - tolerate the taint forever (do not evict). Zero - and negative values will be treated as 0 (evict - immediately) by the system. + description: |- + TolerationSeconds represents the period of time the toleration (which must be + of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, + it is not set, which means tolerate the taint forever (do not evict). Zero and + negative values will be treated as 0 (evict immediately) by the system. format: int64 type: integer value: - description: Value is the taint value the toleration - matches to. If the operator is Exists, the value - should be empty, otherwise just a regular string. + description: |- + Value is the taint value the toleration matches to. + If the operator is Exists, the value should be empty, otherwise just a regular string. type: string type: object type: array @@ -411,34 +422,36 @@ spec: within a container. properties: mountPath: - description: Path within the container at which the - volume should be mounted. Must not contain ':'. + description: |- + Path within the container at which the volume should be mounted. Must + not contain ':'. type: string mountPropagation: - description: mountPropagation determines how mounts - are propagated from the host to container and the - other way around. When not set, MountPropagationNone - is used. This field is beta in 1.10. + description: |- + mountPropagation determines how mounts are propagated from the host + to container and the other way around. + When not set, MountPropagationNone is used. + This field is beta in 1.10. type: string name: description: This must match the Name of a Volume. type: string readOnly: - description: Mounted read-only if true, read-write - otherwise (false or unspecified). Defaults to false. + description: |- + Mounted read-only if true, read-write otherwise (false or unspecified). + Defaults to false. type: boolean subPath: - description: Path within the volume from which the - container's volume should be mounted. Defaults to - "" (volume's root). + description: |- + Path within the volume from which the container's volume should be mounted. + Defaults to "" (volume's root). type: string subPathExpr: - description: Expanded path within the volume from - which the container's volume should be mounted. - Behaves similarly to SubPath but environment variable - references $(VAR_NAME) are expanded using the container's - environment. Defaults to "" (volume's root). SubPathExpr - and SubPath are mutually exclusive. + description: |- + Expanded path within the volume from which the container's volume should be mounted. + Behaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment. + Defaults to "" (volume's root). + SubPathExpr and SubPath are mutually exclusive. type: string required: - mountPath @@ -452,40 +465,36 @@ spec: that may be accessed by any container in the pod. properties: awsElasticBlockStore: - description: 'awsElasticBlockStore represents an AWS - Disk resource that is attached to a kubelet''s host - machine and then exposed to the pod. More info: - https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' + description: |- + awsElasticBlockStore represents an AWS Disk resource that is attached to a + kubelet's host machine and then exposed to the pod. + More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore properties: fsType: - description: 'fsType is the filesystem type of - the volume that you want to mount. Tip: Ensure - that the filesystem type is supported by the - host operating system. Examples: "ext4", "xfs", - "ntfs". Implicitly inferred to be "ext4" if - unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore - TODO: how do we prevent errors in the filesystem - from compromising the machine' + description: |- + fsType is the filesystem type of the volume that you want to mount. + Tip: Ensure that the filesystem type is supported by the host operating system. + Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore + TODO: how do we prevent errors in the filesystem from compromising the machine type: string partition: - description: 'partition is the partition in the - volume that you want to mount. If omitted, the - default is to mount by volume name. Examples: - For volume /dev/sda1, you specify the partition - as "1". Similarly, the volume partition for - /dev/sda is "0" (or you can leave the property - empty).' + description: |- + partition is the partition in the volume that you want to mount. + If omitted, the default is to mount by volume name. + Examples: For volume /dev/sda1, you specify the partition as "1". + Similarly, the volume partition for /dev/sda is "0" (or you can leave the property empty). format: int32 type: integer readOnly: - description: 'readOnly value true will force the - readOnly setting in VolumeMounts. More info: - https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' + description: |- + readOnly value true will force the readOnly setting in VolumeMounts. + More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore type: boolean volumeID: - description: 'volumeID is unique ID of the persistent - disk resource in AWS (Amazon EBS volume). More - info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' + description: |- + volumeID is unique ID of the persistent disk resource in AWS (Amazon EBS volume). + More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore type: string required: - volumeID @@ -507,10 +516,10 @@ spec: the blob storage type: string fsType: - description: fsType is Filesystem type to mount. - Must be a filesystem type supported by the host - operating system. Ex. "ext4", "xfs", "ntfs". - Implicitly inferred to be "ext4" if unspecified. + description: |- + fsType is Filesystem type to mount. + Must be a filesystem type supported by the host operating system. + Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. type: string kind: description: 'kind expected values are Shared: @@ -520,9 +529,9 @@ spec: set). defaults to shared' type: string readOnly: - description: readOnly Defaults to false (read/write). - ReadOnly here will force the ReadOnly setting - in VolumeMounts. + description: |- + readOnly Defaults to false (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. type: boolean required: - diskName @@ -533,9 +542,9 @@ spec: mount on the host and bind mount to the pod. properties: readOnly: - description: readOnly defaults to false (read/write). - ReadOnly here will force the ReadOnly setting - in VolumeMounts. + description: |- + readOnly defaults to false (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. type: boolean secretName: description: secretName is the name of secret @@ -554,8 +563,9 @@ spec: the host that shares a pod's lifetime properties: monitors: - description: 'monitors is Required: Monitors is - a collection of Ceph monitors More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + description: |- + monitors is Required: Monitors is a collection of Ceph monitors + More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it items: type: string type: array @@ -565,67 +575,72 @@ spec: is /' type: string readOnly: - description: 'readOnly is Optional: Defaults to - false (read/write). ReadOnly here will force - the ReadOnly setting in VolumeMounts. More info: - https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + description: |- + readOnly is Optional: Defaults to false (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. + More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it type: boolean secretFile: - description: 'secretFile is Optional: SecretFile - is the path to key ring for User, default is - /etc/ceph/user.secret More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + description: |- + secretFile is Optional: SecretFile is the path to key ring for User, default is /etc/ceph/user.secret + More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it type: string secretRef: - description: 'secretRef is Optional: SecretRef - is reference to the authentication secret for - User, default is empty. More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + description: |- + secretRef is Optional: SecretRef is reference to the authentication secret for User, default is empty. + More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it properties: name: - description: 'Name of the referent. More info: - https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, - kind, uid?' + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? type: string type: object + x-kubernetes-map-type: atomic user: - description: 'user is optional: User is the rados - user name, default is admin More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + description: |- + user is optional: User is the rados user name, default is admin + More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it type: string required: - monitors type: object cinder: - description: 'cinder represents a cinder volume attached - and mounted on kubelets host machine. More info: - https://examples.k8s.io/mysql-cinder-pd/README.md' + description: |- + cinder represents a cinder volume attached and mounted on kubelets host machine. + More info: https://examples.k8s.io/mysql-cinder-pd/README.md properties: fsType: - description: 'fsType is the filesystem type to - mount. Must be a filesystem type supported by - the host operating system. Examples: "ext4", - "xfs", "ntfs". Implicitly inferred to be "ext4" - if unspecified. More info: https://examples.k8s.io/mysql-cinder-pd/README.md' + description: |- + fsType is the filesystem type to mount. + Must be a filesystem type supported by the host operating system. + Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + More info: https://examples.k8s.io/mysql-cinder-pd/README.md type: string readOnly: - description: 'readOnly defaults to false (read/write). - ReadOnly here will force the ReadOnly setting - in VolumeMounts. More info: https://examples.k8s.io/mysql-cinder-pd/README.md' + description: |- + readOnly defaults to false (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. + More info: https://examples.k8s.io/mysql-cinder-pd/README.md type: boolean secretRef: - description: 'secretRef is optional: points to - a secret object containing parameters used to - connect to OpenStack.' + description: |- + secretRef is optional: points to a secret object containing parameters used to connect + to OpenStack. properties: name: - description: 'Name of the referent. More info: - https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, - kind, uid?' + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? type: string type: object + x-kubernetes-map-type: atomic volumeID: - description: 'volumeID used to identify the volume - in cinder. More info: https://examples.k8s.io/mysql-cinder-pd/README.md' + description: |- + volumeID used to identify the volume in cinder. + More info: https://examples.k8s.io/mysql-cinder-pd/README.md type: string required: - volumeID @@ -635,31 +650,25 @@ spec: should populate this volume properties: defaultMode: - description: 'defaultMode is optional: mode bits - used to set permissions on created files by - default. Must be an octal value between 0000 - and 0777 or a decimal value between 0 and 511. - YAML accepts both octal and decimal values, - JSON requires decimal values for mode bits. - Defaults to 0644. Directories within the path - are not affected by this setting. This might - be in conflict with other options that affect - the file mode, like fsGroup, and the result - can be other mode bits set.' + description: |- + defaultMode is optional: mode bits used to set permissions on created files by default. + Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. + Defaults to 0644. + Directories within the path are not affected by this setting. + This might be in conflict with other options that affect the file + mode, like fsGroup, and the result can be other mode bits set. format: int32 type: integer items: - description: items if unspecified, each key-value - pair in the Data field of the referenced ConfigMap - will be projected into the volume as a file - whose name is the key and content is the value. - If specified, the listed keys will be projected - into the specified paths, and unlisted keys - will not be present. If a key is specified which - is not present in the ConfigMap, the volume - setup will error unless it is marked optional. - Paths must be relative and may not contain the - '..' path or start with '..'. + description: |- + items if unspecified, each key-value pair in the Data field of the referenced + ConfigMap will be projected into the volume as a file whose name is the + key and content is the value. If specified, the listed keys will be + projected into the specified paths, and unlisted keys will not be + present. If a key is specified which is not present in the ConfigMap, + the volume setup will error unless it is marked optional. Paths must be + relative and may not contain the '..' path or start with '..'. items: description: Maps a string key to a path within a volume. @@ -668,25 +677,21 @@ spec: description: key is the key to project. type: string mode: - description: 'mode is Optional: mode bits - used to set permissions on this file. - Must be an octal value between 0000 and - 0777 or a decimal value between 0 and - 511. YAML accepts both octal and decimal - values, JSON requires decimal values for - mode bits. If not specified, the volume - defaultMode will be used. This might be - in conflict with other options that affect - the file mode, like fsGroup, and the result - can be other mode bits set.' + description: |- + mode is Optional: mode bits used to set permissions on this file. + Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. + If not specified, the volume defaultMode will be used. + This might be in conflict with other options that affect the file + mode, like fsGroup, and the result can be other mode bits set. format: int32 type: integer path: - description: path is the relative path of - the file to map the key to. May not be - an absolute path. May not contain the - path element '..'. May not start with - the string '..'. + description: |- + path is the relative path of the file to map the key to. + May not be an absolute path. + May not contain the path element '..'. + May not start with the string '..'. type: string required: - key @@ -694,61 +699,60 @@ spec: type: object type: array name: - description: 'Name of the referent. More info: - https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, kind, - uid?' + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? type: string optional: description: optional specify whether the ConfigMap or its keys must be defined type: boolean type: object + x-kubernetes-map-type: atomic csi: description: csi (Container Storage Interface) represents ephemeral storage that is handled by certain external CSI drivers (Beta feature). properties: driver: - description: driver is the name of the CSI driver - that handles this volume. Consult with your - admin for the correct name as registered in - the cluster. + description: |- + driver is the name of the CSI driver that handles this volume. + Consult with your admin for the correct name as registered in the cluster. type: string fsType: - description: fsType to mount. Ex. "ext4", "xfs", - "ntfs". If not provided, the empty value is - passed to the associated CSI driver which will - determine the default filesystem to apply. + description: |- + fsType to mount. Ex. "ext4", "xfs", "ntfs". + If not provided, the empty value is passed to the associated CSI driver + which will determine the default filesystem to apply. type: string nodePublishSecretRef: - description: nodePublishSecretRef is a reference - to the secret object containing sensitive information - to pass to the CSI driver to complete the CSI + description: |- + nodePublishSecretRef is a reference to the secret object containing + sensitive information to pass to the CSI driver to complete the CSI NodePublishVolume and NodeUnpublishVolume calls. - This field is optional, and may be empty if - no secret is required. If the secret object - contains more than one secret, all secret references - are passed. + This field is optional, and may be empty if no secret is required. If the + secret object contains more than one secret, all secret references are passed. properties: name: - description: 'Name of the referent. More info: - https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, - kind, uid?' + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? type: string type: object + x-kubernetes-map-type: atomic readOnly: - description: readOnly specifies a read-only configuration - for the volume. Defaults to false (read/write). + description: |- + readOnly specifies a read-only configuration for the volume. + Defaults to false (read/write). type: boolean volumeAttributes: additionalProperties: type: string - description: volumeAttributes stores driver-specific - properties that are passed to the CSI driver. - Consult your driver's documentation for supported - values. + description: |- + volumeAttributes stores driver-specific properties that are passed to the CSI + driver. Consult your driver's documentation for supported values. type: object required: - driver @@ -758,18 +762,15 @@ spec: the pod that should populate this volume properties: defaultMode: - description: 'Optional: mode bits to use on created - files by default. Must be a Optional: mode bits - used to set permissions on created files by - default. Must be an octal value between 0000 - and 0777 or a decimal value between 0 and 511. - YAML accepts both octal and decimal values, - JSON requires decimal values for mode bits. - Defaults to 0644. Directories within the path - are not affected by this setting. This might - be in conflict with other options that affect - the file mode, like fsGroup, and the result - can be other mode bits set.' + description: |- + Optional: mode bits to use on created files by default. Must be a + Optional: mode bits used to set permissions on created files by default. + Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. + Defaults to 0644. + Directories within the path are not affected by this setting. + This might be in conflict with other options that affect the file + mode, like fsGroup, and the result can be other mode bits set. format: int32 type: integer items: @@ -797,18 +798,15 @@ spec: required: - fieldPath type: object + x-kubernetes-map-type: atomic mode: - description: 'Optional: mode bits used to - set permissions on this file, must be - an octal value between 0000 and 0777 or - a decimal value between 0 and 511. YAML - accepts both octal and decimal values, - JSON requires decimal values for mode - bits. If not specified, the volume defaultMode - will be used. This might be in conflict - with other options that affect the file - mode, like fsGroup, and the result can - be other mode bits set.' + description: |- + Optional: mode bits used to set permissions on this file, must be an octal value + between 0000 and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. + If not specified, the volume defaultMode will be used. + This might be in conflict with other options that affect the file + mode, like fsGroup, and the result can be other mode bits set. format: int32 type: integer path: @@ -820,10 +818,9 @@ spec: with ''..''' type: string resourceFieldRef: - description: 'Selects a resource of the - container: only resources limits and requests - (limits.cpu, limits.memory, requests.cpu - and requests.memory) are currently supported.' + description: |- + Selects a resource of the container: only resources limits and requests + (limits.cpu, limits.memory, requests.cpu and requests.memory) are currently supported. properties: containerName: description: 'Container name: required @@ -845,127 +842,131 @@ spec: required: - resource type: object + x-kubernetes-map-type: atomic required: - path type: object type: array type: object emptyDir: - description: 'emptyDir represents a temporary directory - that shares a pod''s lifetime. More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir' + description: |- + emptyDir represents a temporary directory that shares a pod's lifetime. + More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir properties: medium: - description: 'medium represents what type of storage - medium should back this directory. The default - is "" which means to use the node''s default - medium. Must be an empty string (default) or - Memory. More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir' + description: |- + medium represents what type of storage medium should back this directory. + The default is "" which means to use the node's default medium. + Must be an empty string (default) or Memory. + More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir type: string sizeLimit: anyOf: - type: integer - type: string - description: 'sizeLimit is the total amount of - local storage required for this EmptyDir volume. - The size limit is also applicable for memory - medium. The maximum usage on memory medium EmptyDir - would be the minimum value between the SizeLimit - specified here and the sum of memory limits - of all containers in a pod. The default is nil - which means that the limit is undefined. More - info: http://kubernetes.io/docs/user-guide/volumes#emptydir' + description: |- + sizeLimit is the total amount of local storage required for this EmptyDir volume. + The size limit is also applicable for memory medium. + The maximum usage on memory medium EmptyDir would be the minimum value between + the SizeLimit specified here and the sum of memory limits of all containers in a pod. + The default is nil which means that the limit is undefined. + More info: http://kubernetes.io/docs/user-guide/volumes#emptydir pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true type: object ephemeral: - description: "ephemeral represents a volume that is - handled by a cluster storage driver. The volume's - lifecycle is tied to the pod that defines it - it - will be created before the pod starts, and deleted - when the pod is removed. \n Use this if: a) the - volume is only needed while the pod runs, b) features - of normal volumes like restoring from snapshot or - capacity tracking are needed, c) the storage - driver is specified through a storage class, and - d) the storage driver supports dynamic volume provisioning - through a PersistentVolumeClaim (see EphemeralVolumeSource - for more information on the connection between - this volume type and PersistentVolumeClaim). - \n Use PersistentVolumeClaim or one of the vendor-specific - APIs for volumes that persist for longer than the - lifecycle of an individual pod. \n Use CSI for light-weight - local ephemeral volumes if the CSI driver is meant - to be used that way - see the documentation of the - driver for more information. \n A pod can use both - types of ephemeral volumes and persistent volumes - at the same time." + description: |- + ephemeral represents a volume that is handled by a cluster storage driver. + The volume's lifecycle is tied to the pod that defines it - it will be created before the pod starts, + and deleted when the pod is removed. + + + Use this if: + a) the volume is only needed while the pod runs, + b) features of normal volumes like restoring from snapshot or capacity + tracking are needed, + c) the storage driver is specified through a storage class, and + d) the storage driver supports dynamic volume provisioning through + a PersistentVolumeClaim (see EphemeralVolumeSource for more + information on the connection between this volume type + and PersistentVolumeClaim). + + + Use PersistentVolumeClaim or one of the vendor-specific + APIs for volumes that persist for longer than the lifecycle + of an individual pod. + + + Use CSI for light-weight local ephemeral volumes if the CSI driver is meant to + be used that way - see the documentation of the driver for + more information. + + + A pod can use both types of ephemeral volumes and + persistent volumes at the same time. properties: volumeClaimTemplate: - description: "Will be used to create a stand-alone - PVC to provision the volume. The pod in which - this EphemeralVolumeSource is embedded will - be the owner of the PVC, i.e. the PVC will be - deleted together with the pod. The name of - the PVC will be `-` where - `` is the name from the `PodSpec.Volumes` - array entry. Pod validation will reject the - pod if the concatenated name is not valid for - a PVC (for example, too long). \n An existing - PVC with that name that is not owned by the - pod will *not* be used for the pod to avoid - using an unrelated volume by mistake. Starting - the pod is then blocked until the unrelated - PVC is removed. If such a pre-created PVC is - meant to be used by the pod, the PVC has to - updated with an owner reference to the pod once - the pod exists. Normally this should not be - necessary, but it may be useful when manually - reconstructing a broken cluster. \n This field - is read-only and no changes will be made by - Kubernetes to the PVC after it has been created. - \n Required, must not be nil." + description: |- + Will be used to create a stand-alone PVC to provision the volume. + The pod in which this EphemeralVolumeSource is embedded will be the + owner of the PVC, i.e. the PVC will be deleted together with the + pod. The name of the PVC will be `-` where + `` is the name from the `PodSpec.Volumes` array + entry. Pod validation will reject the pod if the concatenated name + is not valid for a PVC (for example, too long). + + + An existing PVC with that name that is not owned by the pod + will *not* be used for the pod to avoid using an unrelated + volume by mistake. Starting the pod is then blocked until + the unrelated PVC is removed. If such a pre-created PVC is + meant to be used by the pod, the PVC has to updated with an + owner reference to the pod once the pod exists. Normally + this should not be necessary, but it may be useful when + manually reconstructing a broken cluster. + + + This field is read-only and no changes will be made by Kubernetes + to the PVC after it has been created. + + + Required, must not be nil. properties: metadata: - description: May contain labels and annotations - that will be copied into the PVC when creating - it. No other fields are allowed and will - be rejected during validation. + description: |- + May contain labels and annotations that will be copied into the PVC + when creating it. No other fields are allowed and will be rejected during + validation. type: object spec: - description: The specification for the PersistentVolumeClaim. - The entire content is copied unchanged into - the PVC that gets created from this template. - The same fields as in a PersistentVolumeClaim + description: |- + The specification for the PersistentVolumeClaim. The entire content is + copied unchanged into the PVC that gets created from this + template. The same fields as in a PersistentVolumeClaim are also valid here. properties: accessModes: - description: 'accessModes contains the - desired access modes the volume should - have. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1' + description: |- + accessModes contains the desired access modes the volume should have. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1 items: type: string type: array dataSource: - description: 'dataSource field can be - used to specify either: * An existing - VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) + description: |- + dataSource field can be used to specify either: + * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) * An existing PVC (PersistentVolumeClaim) - If the provisioner or an external controller - can support the specified data source, - it will create a new volume based on - the contents of the specified data source. - If the AnyVolumeDataSource feature gate - is enabled, this field will always have - the same contents as the DataSourceRef - field.' + If the provisioner or an external controller can support the specified data source, + it will create a new volume based on the contents of the specified data source. + If the AnyVolumeDataSource feature gate is enabled, this field will always have + the same contents as the DataSourceRef field. properties: apiGroup: - description: APIGroup is the group - for the resource being referenced. - If APIGroup is not specified, the - specified Kind must be in the core - API group. For any other third-party - types, APIGroup is required. + description: |- + APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in the core API group. + For any other third-party types, APIGroup is required. type: string kind: description: Kind is the type of resource @@ -979,44 +980,32 @@ spec: - kind - name type: object + x-kubernetes-map-type: atomic dataSourceRef: - description: 'dataSourceRef specifies - the object from which to populate the - volume with data, if a non-empty volume - is desired. This may be any local object - from a non-empty API group (non core - object) or a PersistentVolumeClaim object. - When this field is specified, volume - binding will only succeed if the type - of the specified object matches some - installed volume populator or dynamic - provisioner. This field will replace - the functionality of the DataSource - field and as such if both fields are - non-empty, they must have the same value. - For backwards compatibility, both fields - (DataSource and DataSourceRef) will - be set to the same value automatically - if one of them is empty and the other - is non-empty. There are two important - differences between DataSource and DataSourceRef: - * While DataSource only allows two specific - types of objects, DataSourceRef allows - any non-core object, as well as PersistentVolumeClaim - objects. * While DataSource ignores - disallowed values (dropping them), DataSourceRef preserves - all values, and generates an error if - a disallowed value is specified. (Beta) - Using this field requires the AnyVolumeDataSource - feature gate to be enabled.' + description: |- + dataSourceRef specifies the object from which to populate the volume with data, if a non-empty + volume is desired. This may be any local object from a non-empty API group (non + core object) or a PersistentVolumeClaim object. + When this field is specified, volume binding will only succeed if the type of + the specified object matches some installed volume populator or dynamic + provisioner. + This field will replace the functionality of the DataSource field and as such + if both fields are non-empty, they must have the same value. For backwards + compatibility, both fields (DataSource and DataSourceRef) will be set to the same + value automatically if one of them is empty and the other is non-empty. + There are two important differences between DataSource and DataSourceRef: + * While DataSource only allows two specific types of objects, DataSourceRef + allows any non-core object, as well as PersistentVolumeClaim objects. + * While DataSource ignores disallowed values (dropping them), DataSourceRef + preserves all values, and generates an error if a disallowed value is + specified. + (Beta) Using this field requires the AnyVolumeDataSource feature gate to be enabled. properties: apiGroup: - description: APIGroup is the group - for the resource being referenced. - If APIGroup is not specified, the - specified Kind must be in the core - API group. For any other third-party - types, APIGroup is required. + description: |- + APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in the core API group. + For any other third-party types, APIGroup is required. type: string kind: description: Kind is the type of resource @@ -1030,16 +1019,14 @@ spec: - kind - name type: object + x-kubernetes-map-type: atomic resources: - description: 'resources represents the - minimum resources the volume should - have. If RecoverVolumeExpansionFailure - feature is enabled users are allowed - to specify resource requirements that - are lower than previous value but must - still be higher than capacity recorded - in the status field of the claim. More - info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources' + description: |- + resources represents the minimum resources the volume should have. + If RecoverVolumeExpansionFailure feature is enabled users are allowed to specify resource requirements + that are lower than previous value but must still be higher than capacity recorded in the + status field of the claim. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources properties: limits: additionalProperties: @@ -1048,9 +1035,9 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: 'Limits describes the - maximum amount of compute resources - allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object requests: additionalProperties: @@ -1059,13 +1046,11 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: 'Requests describes the - minimum amount of compute resources - required. If Requests is omitted - for a container, it defaults to - Limits if that is explicitly specified, - otherwise to an implementation-defined - value. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object type: object selector: @@ -1077,10 +1062,9 @@ spec: list of label selector requirements. The requirements are ANDed. items: - description: A label selector requirement - is a selector that contains values, - a key, and an operator that relates - the key and values. + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. properties: key: description: key is the label @@ -1088,21 +1072,15 @@ spec: to. type: string operator: - description: operator represents - a key's relationship to a - set of values. Valid operators - are In, NotIn, Exists and - DoesNotExist. + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. type: string values: - description: values is an array - of string values. If the operator - is In or NotIn, the values - array must be non-empty. If - the operator is Exists or - DoesNotExist, the values array - must be empty. This array - is replaced during a strategic + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic merge patch. items: type: string @@ -1115,26 +1093,22 @@ spec: matchLabels: additionalProperties: type: string - description: matchLabels is a map - of {key,value} pairs. A single {key,value} - in the matchLabels map is equivalent - to an element of matchExpressions, - whose key field is "key", the operator - is "In", and the values array contains - only "value". The requirements are - ANDed. + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. type: object type: object + x-kubernetes-map-type: atomic storageClassName: - description: 'storageClassName is the - name of the StorageClass required by - the claim. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1' + description: |- + storageClassName is the name of the StorageClass required by the claim. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1 type: string volumeMode: - description: volumeMode defines what type - of volume is required by the claim. - Value of Filesystem is implied when - not included in claim spec. + description: |- + volumeMode defines what type of volume is required by the claim. + Value of Filesystem is implied when not included in claim spec. type: string volumeName: description: volumeName is the binding @@ -1152,21 +1126,20 @@ spec: then exposed to the pod. properties: fsType: - description: 'fsType is the filesystem type to - mount. Must be a filesystem type supported by - the host operating system. Ex. "ext4", "xfs", - "ntfs". Implicitly inferred to be "ext4" if - unspecified. TODO: how do we prevent errors - in the filesystem from compromising the machine' + description: |- + fsType is the filesystem type to mount. + Must be a filesystem type supported by the host operating system. + Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + TODO: how do we prevent errors in the filesystem from compromising the machine type: string lun: description: 'lun is Optional: FC target lun number' format: int32 type: integer readOnly: - description: 'readOnly is Optional: Defaults to - false (read/write). ReadOnly here will force - the ReadOnly setting in VolumeMounts.' + description: |- + readOnly is Optional: Defaults to false (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. type: boolean targetWWNs: description: 'targetWWNs is Optional: FC target @@ -1175,29 +1148,27 @@ spec: type: string type: array wwids: - description: 'wwids Optional: FC volume world - wide identifiers (wwids) Either wwids or combination - of targetWWNs and lun must be set, but not both - simultaneously.' + description: |- + wwids Optional: FC volume world wide identifiers (wwids) + Either wwids or combination of targetWWNs and lun must be set, but not both simultaneously. items: type: string type: array type: object flexVolume: - description: flexVolume represents a generic volume - resource that is provisioned/attached using an exec - based plugin. + description: |- + flexVolume represents a generic volume resource that is + provisioned/attached using an exec based plugin. properties: driver: description: driver is the name of the driver to use for this volume. type: string fsType: - description: fsType is the filesystem type to - mount. Must be a filesystem type supported by - the host operating system. Ex. "ext4", "xfs", - "ntfs". The default filesystem depends on FlexVolume - script. + description: |- + fsType is the filesystem type to mount. + Must be a filesystem type supported by the host operating system. + Ex. "ext4", "xfs", "ntfs". The default filesystem depends on FlexVolume script. type: string options: additionalProperties: @@ -1206,26 +1177,26 @@ spec: holds extra command options if any.' type: object readOnly: - description: 'readOnly is Optional: defaults to - false (read/write). ReadOnly here will force - the ReadOnly setting in VolumeMounts.' + description: |- + readOnly is Optional: defaults to false (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. type: boolean secretRef: - description: 'secretRef is Optional: secretRef - is reference to the secret object containing - sensitive information to pass to the plugin - scripts. This may be empty if no secret object - is specified. If the secret object contains - more than one secret, all secrets are passed - to the plugin scripts.' + description: |- + secretRef is Optional: secretRef is reference to the secret object containing + sensitive information to pass to the plugin scripts. This may be + empty if no secret object is specified. If the secret object + contains more than one secret, all secrets are passed to the plugin + scripts. properties: name: - description: 'Name of the referent. More info: - https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, - kind, uid?' + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? type: string type: object + x-kubernetes-map-type: atomic required: - driver type: object @@ -1235,9 +1206,9 @@ spec: Flocker control service being running properties: datasetName: - description: datasetName is Name of the dataset - stored as metadata -> name on the dataset for - Flocker should be considered as deprecated + description: |- + datasetName is Name of the dataset stored as metadata -> name on the dataset for Flocker + should be considered as deprecated type: string datasetUUID: description: datasetUUID is the UUID of the dataset. @@ -1245,57 +1216,54 @@ spec: type: string type: object gcePersistentDisk: - description: 'gcePersistentDisk represents a GCE Disk - resource that is attached to a kubelet''s host machine - and then exposed to the pod. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + description: |- + gcePersistentDisk represents a GCE Disk resource that is attached to a + kubelet's host machine and then exposed to the pod. + More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk properties: fsType: - description: 'fsType is filesystem type of the - volume that you want to mount. Tip: Ensure that - the filesystem type is supported by the host - operating system. Examples: "ext4", "xfs", "ntfs". - Implicitly inferred to be "ext4" if unspecified. + description: |- + fsType is filesystem type of the volume that you want to mount. + Tip: Ensure that the filesystem type is supported by the host operating system. + Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk - TODO: how do we prevent errors in the filesystem - from compromising the machine' + TODO: how do we prevent errors in the filesystem from compromising the machine type: string partition: - description: 'partition is the partition in the - volume that you want to mount. If omitted, the - default is to mount by volume name. Examples: - For volume /dev/sda1, you specify the partition - as "1". Similarly, the volume partition for - /dev/sda is "0" (or you can leave the property - empty). More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + description: |- + partition is the partition in the volume that you want to mount. + If omitted, the default is to mount by volume name. + Examples: For volume /dev/sda1, you specify the partition as "1". + Similarly, the volume partition for /dev/sda is "0" (or you can leave the property empty). + More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk format: int32 type: integer pdName: - description: 'pdName is unique name of the PD - resource in GCE. Used to identify the disk in - GCE. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + description: |- + pdName is unique name of the PD resource in GCE. Used to identify the disk in GCE. + More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk type: string readOnly: - description: 'readOnly here will force the ReadOnly - setting in VolumeMounts. Defaults to false. - More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + description: |- + readOnly here will force the ReadOnly setting in VolumeMounts. + Defaults to false. + More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk type: boolean required: - pdName type: object gitRepo: - description: 'gitRepo represents a git repository - at a particular revision. DEPRECATED: GitRepo is - deprecated. To provision a container with a git - repo, mount an EmptyDir into an InitContainer that - clones the repo using git, then mount the EmptyDir - into the Pod''s container.' + description: |- + gitRepo represents a git repository at a particular revision. + DEPRECATED: GitRepo is deprecated. To provision a container with a git repo, mount an + EmptyDir into an InitContainer that clones the repo using git, then mount the EmptyDir + into the Pod's container. properties: directory: - description: directory is the target directory - name. Must not contain or start with '..'. If - '.' is supplied, the volume directory will be - the git repository. Otherwise, if specified, - the volume will contain the git repository in + description: |- + directory is the target directory name. + Must not contain or start with '..'. If '.' is supplied, the volume directory will be the + git repository. Otherwise, if specified, the volume will contain the git repository in the subdirectory with the given name. type: string repository: @@ -1309,54 +1277,61 @@ spec: - repository type: object glusterfs: - description: 'glusterfs represents a Glusterfs mount - on the host that shares a pod''s lifetime. More - info: https://examples.k8s.io/volumes/glusterfs/README.md' + description: |- + glusterfs represents a Glusterfs mount on the host that shares a pod's lifetime. + More info: https://examples.k8s.io/volumes/glusterfs/README.md properties: endpoints: - description: 'endpoints is the endpoint name that - details Glusterfs topology. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod' + description: |- + endpoints is the endpoint name that details Glusterfs topology. + More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod type: string path: - description: 'path is the Glusterfs volume path. - More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod' + description: |- + path is the Glusterfs volume path. + More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod type: string readOnly: - description: 'readOnly here will force the Glusterfs - volume to be mounted with read-only permissions. - Defaults to false. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod' + description: |- + readOnly here will force the Glusterfs volume to be mounted with read-only permissions. + Defaults to false. + More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod type: boolean required: - endpoints - path type: object hostPath: - description: 'hostPath represents a pre-existing file - or directory on the host machine that is directly - exposed to the container. This is generally used - for system agents or other privileged things that - are allowed to see the host machine. Most containers - will NOT need this. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath - --- TODO(jonesdl) We need to restrict who can use - host directory mounts and who can/can not mount - host directories as read/write.' + description: |- + hostPath represents a pre-existing file or directory on the host + machine that is directly exposed to the container. This is generally + used for system agents or other privileged things that are allowed + to see the host machine. Most containers will NOT need this. + More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath + --- + TODO(jonesdl) We need to restrict who can use host directory mounts and who can/can not + mount host directories as read/write. properties: path: - description: 'path of the directory on the host. - If the path is a symlink, it will follow the - link to the real path. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath' + description: |- + path of the directory on the host. + If the path is a symlink, it will follow the link to the real path. + More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath type: string type: - description: 'type for HostPath Volume Defaults - to "" More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath' + description: |- + type for HostPath Volume + Defaults to "" + More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath type: string required: - path type: object iscsi: - description: 'iscsi represents an ISCSI Disk resource - that is attached to a kubelet''s host machine and - then exposed to the pod. More info: https://examples.k8s.io/volumes/iscsi/README.md' + description: |- + iscsi represents an ISCSI Disk resource that is attached to a + kubelet's host machine and then exposed to the pod. + More info: https://examples.k8s.io/volumes/iscsi/README.md properties: chapAuthDiscovery: description: chapAuthDiscovery defines whether @@ -1367,63 +1342,60 @@ spec: iSCSI Session CHAP authentication type: boolean fsType: - description: 'fsType is the filesystem type of - the volume that you want to mount. Tip: Ensure - that the filesystem type is supported by the - host operating system. Examples: "ext4", "xfs", - "ntfs". Implicitly inferred to be "ext4" if - unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#iscsi - TODO: how do we prevent errors in the filesystem - from compromising the machine' + description: |- + fsType is the filesystem type of the volume that you want to mount. + Tip: Ensure that the filesystem type is supported by the host operating system. + Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + More info: https://kubernetes.io/docs/concepts/storage/volumes#iscsi + TODO: how do we prevent errors in the filesystem from compromising the machine type: string initiatorName: - description: initiatorName is the custom iSCSI - Initiator Name. If initiatorName is specified - with iscsiInterface simultaneously, new iSCSI - interface : will - be created for the connection. + description: |- + initiatorName is the custom iSCSI Initiator Name. + If initiatorName is specified with iscsiInterface simultaneously, new iSCSI interface + : will be created for the connection. type: string iqn: description: iqn is the target iSCSI Qualified Name. type: string iscsiInterface: - description: iscsiInterface is the interface Name - that uses an iSCSI transport. Defaults to 'default' - (tcp). + description: |- + iscsiInterface is the interface Name that uses an iSCSI transport. + Defaults to 'default' (tcp). type: string lun: description: lun represents iSCSI Target Lun number. format: int32 type: integer portals: - description: portals is the iSCSI Target Portal - List. The portal is either an IP or ip_addr:port - if the port is other than default (typically - TCP ports 860 and 3260). + description: |- + portals is the iSCSI Target Portal List. The portal is either an IP or ip_addr:port if the port + is other than default (typically TCP ports 860 and 3260). items: type: string type: array readOnly: - description: readOnly here will force the ReadOnly - setting in VolumeMounts. Defaults to false. + description: |- + readOnly here will force the ReadOnly setting in VolumeMounts. + Defaults to false. type: boolean secretRef: description: secretRef is the CHAP Secret for iSCSI target and initiator authentication properties: name: - description: 'Name of the referent. More info: - https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, - kind, uid?' + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? type: string type: object + x-kubernetes-map-type: atomic targetPortal: - description: targetPortal is iSCSI Target Portal. - The Portal is either an IP or ip_addr:port if - the port is other than default (typically TCP - ports 860 and 3260). + description: |- + targetPortal is iSCSI Target Portal. The Portal is either an IP or ip_addr:port if the port + is other than default (typically TCP ports 860 and 3260). type: string required: - iqn @@ -1431,43 +1403,51 @@ spec: - targetPortal type: object name: - description: 'name of the volume. Must be a DNS_LABEL - and unique within the pod. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + description: |- + name of the volume. + Must be a DNS_LABEL and unique within the pod. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string nfs: - description: 'nfs represents an NFS mount on the host - that shares a pod''s lifetime More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' + description: |- + nfs represents an NFS mount on the host that shares a pod's lifetime + More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs properties: path: - description: 'path that is exported by the NFS - server. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' + description: |- + path that is exported by the NFS server. + More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs type: string readOnly: - description: 'readOnly here will force the NFS - export to be mounted with read-only permissions. - Defaults to false. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' + description: |- + readOnly here will force the NFS export to be mounted with read-only permissions. + Defaults to false. + More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs type: boolean server: - description: 'server is the hostname or IP address - of the NFS server. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' + description: |- + server is the hostname or IP address of the NFS server. + More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs type: string required: - path - server type: object persistentVolumeClaim: - description: 'persistentVolumeClaimVolumeSource represents - a reference to a PersistentVolumeClaim in the same - namespace. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims' + description: |- + persistentVolumeClaimVolumeSource represents a reference to a + PersistentVolumeClaim in the same namespace. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims properties: claimName: - description: 'claimName is the name of a PersistentVolumeClaim - in the same namespace as the pod using this - volume. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims' + description: |- + claimName is the name of a PersistentVolumeClaim in the same namespace as the pod using this volume. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims type: string readOnly: - description: readOnly Will force the ReadOnly - setting in VolumeMounts. Default false. + description: |- + readOnly Will force the ReadOnly setting in VolumeMounts. + Default false. type: boolean required: - claimName @@ -1478,11 +1458,10 @@ spec: host machine properties: fsType: - description: fsType is the filesystem type to - mount. Must be a filesystem type supported by - the host operating system. Ex. "ext4", "xfs", - "ntfs". Implicitly inferred to be "ext4" if - unspecified. + description: |- + fsType is the filesystem type to mount. + Must be a filesystem type supported by the host operating system. + Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. type: string pdID: description: pdID is the ID that identifies Photon @@ -1496,15 +1475,15 @@ spec: volume attached and mounted on kubelets host machine properties: fsType: - description: fSType represents the filesystem - type to mount Must be a filesystem type supported - by the host operating system. Ex. "ext4", "xfs". - Implicitly inferred to be "ext4" if unspecified. + description: |- + fSType represents the filesystem type to mount + Must be a filesystem type supported by the host operating system. + Ex. "ext4", "xfs". Implicitly inferred to be "ext4" if unspecified. type: string readOnly: - description: readOnly defaults to false (read/write). - ReadOnly here will force the ReadOnly setting - in VolumeMounts. + description: |- + readOnly defaults to false (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. type: boolean volumeID: description: volumeID uniquely identifies a Portworx @@ -1518,16 +1497,13 @@ spec: secrets, configmaps, and downward API properties: defaultMode: - description: defaultMode are the mode bits used - to set permissions on created files by default. - Must be an octal value between 0000 and 0777 - or a decimal value between 0 and 511. YAML accepts - both octal and decimal values, JSON requires - decimal values for mode bits. Directories within - the path are not affected by this setting. This - might be in conflict with other options that - affect the file mode, like fsGroup, and the - result can be other mode bits set. + description: |- + defaultMode are the mode bits used to set permissions on created files by default. + Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. + Directories within the path are not affected by this setting. + This might be in conflict with other options that affect the file + mode, like fsGroup, and the result can be other mode bits set. format: int32 type: integer sources: @@ -1541,20 +1517,14 @@ spec: the configMap data to project properties: items: - description: items if unspecified, each - key-value pair in the Data field of - the referenced ConfigMap will be projected - into the volume as a file whose name - is the key and content is the value. - If specified, the listed keys will - be projected into the specified paths, - and unlisted keys will not be present. - If a key is specified which is not - present in the ConfigMap, the volume - setup will error unless it is marked - optional. Paths must be relative and - may not contain the '..' path or start - with '..'. + description: |- + items if unspecified, each key-value pair in the Data field of the referenced + ConfigMap will be projected into the volume as a file whose name is the + key and content is the value. If specified, the listed keys will be + projected into the specified paths, and unlisted keys will not be + present. If a key is specified which is not present in the ConfigMap, + the volume setup will error unless it is marked optional. Paths must be + relative and may not contain the '..' path or start with '..'. items: description: Maps a string key to a path within a volume. @@ -1564,30 +1534,21 @@ spec: project. type: string mode: - description: 'mode is Optional: - mode bits used to set permissions - on this file. Must be an octal - value between 0000 and 0777 - or a decimal value between 0 - and 511. YAML accepts both octal - and decimal values, JSON requires - decimal values for mode bits. - If not specified, the volume - defaultMode will be used. This - might be in conflict with other - options that affect the file - mode, like fsGroup, and the - result can be other mode bits - set.' + description: |- + mode is Optional: mode bits used to set permissions on this file. + Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. + If not specified, the volume defaultMode will be used. + This might be in conflict with other options that affect the file + mode, like fsGroup, and the result can be other mode bits set. format: int32 type: integer path: - description: path is the relative - path of the file to map the - key to. May not be an absolute - path. May not contain the path - element '..'. May not start - with the string '..'. + description: |- + path is the relative path of the file to map the key to. + May not be an absolute path. + May not contain the path element '..'. + May not start with the string '..'. type: string required: - key @@ -1595,10 +1556,10 @@ spec: type: object type: array name: - description: 'Name of the referent. + description: |- + Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, - kind, uid?' + TODO: Add other useful fields. apiVersion, kind, uid? type: string optional: description: optional specify whether @@ -1606,6 +1567,7 @@ spec: defined type: boolean type: object + x-kubernetes-map-type: atomic downwardAPI: description: downwardAPI information about the downwardAPI data to project @@ -1638,21 +1600,15 @@ spec: required: - fieldPath type: object + x-kubernetes-map-type: atomic mode: - description: 'Optional: mode bits - used to set permissions on this - file, must be an octal value - between 0000 and 0777 or a decimal - value between 0 and 511. YAML - accepts both octal and decimal - values, JSON requires decimal - values for mode bits. If not - specified, the volume defaultMode - will be used. This might be - in conflict with other options - that affect the file mode, like - fsGroup, and the result can - be other mode bits set.' + description: |- + Optional: mode bits used to set permissions on this file, must be an octal value + between 0000 and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. + If not specified, the volume defaultMode will be used. + This might be in conflict with other options that affect the file + mode, like fsGroup, and the result can be other mode bits set. format: int32 type: integer path: @@ -1665,12 +1621,9 @@ spec: not start with ''..''' type: string resourceFieldRef: - description: 'Selects a resource - of the container: only resources - limits and requests (limits.cpu, - limits.memory, requests.cpu - and requests.memory) are currently - supported.' + description: |- + Selects a resource of the container: only resources limits and requests + (limits.cpu, limits.memory, requests.cpu and requests.memory) are currently supported. properties: containerName: description: 'Container name: @@ -1693,6 +1646,7 @@ spec: required: - resource type: object + x-kubernetes-map-type: atomic required: - path type: object @@ -1703,20 +1657,14 @@ spec: secret data to project properties: items: - description: items if unspecified, each - key-value pair in the Data field of - the referenced Secret will be projected - into the volume as a file whose name - is the key and content is the value. - If specified, the listed keys will - be projected into the specified paths, - and unlisted keys will not be present. - If a key is specified which is not - present in the Secret, the volume - setup will error unless it is marked - optional. Paths must be relative and - may not contain the '..' path or start - with '..'. + description: |- + items if unspecified, each key-value pair in the Data field of the referenced + Secret will be projected into the volume as a file whose name is the + key and content is the value. If specified, the listed keys will be + projected into the specified paths, and unlisted keys will not be + present. If a key is specified which is not present in the Secret, + the volume setup will error unless it is marked optional. Paths must be + relative and may not contain the '..' path or start with '..'. items: description: Maps a string key to a path within a volume. @@ -1726,30 +1674,21 @@ spec: project. type: string mode: - description: 'mode is Optional: - mode bits used to set permissions - on this file. Must be an octal - value between 0000 and 0777 - or a decimal value between 0 - and 511. YAML accepts both octal - and decimal values, JSON requires - decimal values for mode bits. - If not specified, the volume - defaultMode will be used. This - might be in conflict with other - options that affect the file - mode, like fsGroup, and the - result can be other mode bits - set.' + description: |- + mode is Optional: mode bits used to set permissions on this file. + Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. + If not specified, the volume defaultMode will be used. + This might be in conflict with other options that affect the file + mode, like fsGroup, and the result can be other mode bits set. format: int32 type: integer path: - description: path is the relative - path of the file to map the - key to. May not be an absolute - path. May not contain the path - element '..'. May not start - with the string '..'. + description: |- + path is the relative path of the file to map the key to. + May not be an absolute path. + May not contain the path element '..'. + May not start with the string '..'. type: string required: - key @@ -1757,10 +1696,10 @@ spec: type: object type: array name: - description: 'Name of the referent. + description: |- + Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, - kind, uid?' + TODO: Add other useful fields. apiVersion, kind, uid? type: string optional: description: optional field specify @@ -1768,38 +1707,33 @@ spec: be defined type: boolean type: object + x-kubernetes-map-type: atomic serviceAccountToken: description: serviceAccountToken is information about the serviceAccountToken data to project properties: audience: - description: audience is the intended - audience of the token. A recipient - of a token must identify itself with - an identifier specified in the audience - of the token, and otherwise should - reject the token. The audience defaults - to the identifier of the apiserver. + description: |- + audience is the intended audience of the token. A recipient of a token + must identify itself with an identifier specified in the audience of the + token, and otherwise should reject the token. The audience defaults to the + identifier of the apiserver. type: string expirationSeconds: - description: expirationSeconds is the - requested duration of validity of - the service account token. As the - token approaches expiration, the kubelet - volume plugin will proactively rotate - the service account token. The kubelet - will start trying to rotate the token - if the token is older than 80 percent - of its time to live or if the token - is older than 24 hours.Defaults to - 1 hour and must be at least 10 minutes. + description: |- + expirationSeconds is the requested duration of validity of the service + account token. As the token approaches expiration, the kubelet volume + plugin will proactively rotate the service account token. The kubelet will + start trying to rotate the token if the token is older than 80 percent of + its time to live or if the token is older than 24 hours.Defaults to 1 hour + and must be at least 10 minutes. format: int64 type: integer path: - description: path is the path relative - to the mount point of the file to - project the token into. + description: |- + path is the path relative to the mount point of the file to project the + token into. type: string required: - path @@ -1812,29 +1746,30 @@ spec: the host that shares a pod's lifetime properties: group: - description: group to map volume access to Default - is no group + description: |- + group to map volume access to + Default is no group type: string readOnly: - description: readOnly here will force the Quobyte - volume to be mounted with read-only permissions. + description: |- + readOnly here will force the Quobyte volume to be mounted with read-only permissions. Defaults to false. type: boolean registry: - description: registry represents a single or multiple - Quobyte Registry services specified as a string - as host:port pair (multiple entries are separated - with commas) which acts as the central registry - for volumes + description: |- + registry represents a single or multiple Quobyte Registry services + specified as a string as host:port pair (multiple entries are separated with commas) + which acts as the central registry for volumes type: string tenant: - description: tenant owning the given Quobyte volume - in the Backend Used with dynamically provisioned - Quobyte volumes, value is set by the plugin + description: |- + tenant owning the given Quobyte volume in the Backend + Used with dynamically provisioned Quobyte volumes, value is set by the plugin type: string user: - description: user to map volume access to Defaults - to serivceaccount user + description: |- + user to map volume access to + Defaults to serivceaccount user type: string volume: description: volume is a string that references @@ -1845,59 +1780,68 @@ spec: - volume type: object rbd: - description: 'rbd represents a Rados Block Device - mount on the host that shares a pod''s lifetime. - More info: https://examples.k8s.io/volumes/rbd/README.md' + description: |- + rbd represents a Rados Block Device mount on the host that shares a pod's lifetime. + More info: https://examples.k8s.io/volumes/rbd/README.md properties: fsType: - description: 'fsType is the filesystem type of - the volume that you want to mount. Tip: Ensure - that the filesystem type is supported by the - host operating system. Examples: "ext4", "xfs", - "ntfs". Implicitly inferred to be "ext4" if - unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#rbd - TODO: how do we prevent errors in the filesystem - from compromising the machine' + description: |- + fsType is the filesystem type of the volume that you want to mount. + Tip: Ensure that the filesystem type is supported by the host operating system. + Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + More info: https://kubernetes.io/docs/concepts/storage/volumes#rbd + TODO: how do we prevent errors in the filesystem from compromising the machine type: string image: - description: 'image is the rados image name. More - info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + description: |- + image is the rados image name. + More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it type: string keyring: - description: 'keyring is the path to key ring - for RBDUser. Default is /etc/ceph/keyring. More - info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + description: |- + keyring is the path to key ring for RBDUser. + Default is /etc/ceph/keyring. + More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it type: string monitors: - description: 'monitors is a collection of Ceph - monitors. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + description: |- + monitors is a collection of Ceph monitors. + More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it items: type: string type: array pool: - description: 'pool is the rados pool name. Default - is rbd. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + description: |- + pool is the rados pool name. + Default is rbd. + More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it type: string readOnly: - description: 'readOnly here will force the ReadOnly - setting in VolumeMounts. Defaults to false. - More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + description: |- + readOnly here will force the ReadOnly setting in VolumeMounts. + Defaults to false. + More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it type: boolean secretRef: - description: 'secretRef is name of the authentication - secret for RBDUser. If provided overrides keyring. - Default is nil. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + description: |- + secretRef is name of the authentication secret for RBDUser. If provided + overrides keyring. + Default is nil. + More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it properties: name: - description: 'Name of the referent. More info: - https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, - kind, uid?' + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? type: string type: object + x-kubernetes-map-type: atomic user: - description: 'user is the rados user name. Default - is admin. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + description: |- + user is the rados user name. + Default is admin. + More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it type: string required: - image @@ -1908,10 +1852,11 @@ spec: volume attached and mounted on Kubernetes nodes. properties: fsType: - description: fsType is the filesystem type to - mount. Must be a filesystem type supported by - the host operating system. Ex. "ext4", "xfs", - "ntfs". Default is "xfs". + description: |- + fsType is the filesystem type to mount. + Must be a filesystem type supported by the host operating system. + Ex. "ext4", "xfs", "ntfs". + Default is "xfs". type: string gateway: description: gateway is the host address of the @@ -1923,31 +1868,31 @@ spec: storage. type: string readOnly: - description: readOnly Defaults to false (read/write). - ReadOnly here will force the ReadOnly setting - in VolumeMounts. + description: |- + readOnly Defaults to false (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. type: boolean secretRef: - description: secretRef references to the secret - for ScaleIO user and other sensitive information. - If this is not provided, Login operation will - fail. + description: |- + secretRef references to the secret for ScaleIO user and other + sensitive information. If this is not provided, Login operation will fail. properties: name: - description: 'Name of the referent. More info: - https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, - kind, uid?' + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? type: string type: object + x-kubernetes-map-type: atomic sslEnabled: description: sslEnabled Flag enable/disable SSL communication with Gateway, default false type: boolean storageMode: - description: storageMode indicates whether the - storage for a volume should be ThickProvisioned - or ThinProvisioned. Default is ThinProvisioned. + description: |- + storageMode indicates whether the storage for a volume should be ThickProvisioned or ThinProvisioned. + Default is ThinProvisioned. type: string storagePool: description: storagePool is the ScaleIO Storage @@ -1958,9 +1903,9 @@ spec: system as configured in ScaleIO. type: string volumeName: - description: volumeName is the name of a volume - already created in the ScaleIO system that is - associated with this volume source. + description: |- + volumeName is the name of a volume already created in the ScaleIO system + that is associated with this volume source. type: string required: - gateway @@ -1968,35 +1913,30 @@ spec: - system type: object secret: - description: 'secret represents a secret that should - populate this volume. More info: https://kubernetes.io/docs/concepts/storage/volumes#secret' + description: |- + secret represents a secret that should populate this volume. + More info: https://kubernetes.io/docs/concepts/storage/volumes#secret properties: defaultMode: - description: 'defaultMode is Optional: mode bits - used to set permissions on created files by - default. Must be an octal value between 0000 - and 0777 or a decimal value between 0 and 511. - YAML accepts both octal and decimal values, - JSON requires decimal values for mode bits. - Defaults to 0644. Directories within the path - are not affected by this setting. This might - be in conflict with other options that affect - the file mode, like fsGroup, and the result - can be other mode bits set.' + description: |- + defaultMode is Optional: mode bits used to set permissions on created files by default. + Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, JSON requires decimal values + for mode bits. Defaults to 0644. + Directories within the path are not affected by this setting. + This might be in conflict with other options that affect the file + mode, like fsGroup, and the result can be other mode bits set. format: int32 type: integer items: - description: items If unspecified, each key-value - pair in the Data field of the referenced Secret - will be projected into the volume as a file - whose name is the key and content is the value. - If specified, the listed keys will be projected - into the specified paths, and unlisted keys - will not be present. If a key is specified which - is not present in the Secret, the volume setup - will error unless it is marked optional. Paths - must be relative and may not contain the '..' - path or start with '..'. + description: |- + items If unspecified, each key-value pair in the Data field of the referenced + Secret will be projected into the volume as a file whose name is the + key and content is the value. If specified, the listed keys will be + projected into the specified paths, and unlisted keys will not be + present. If a key is specified which is not present in the Secret, + the volume setup will error unless it is marked optional. Paths must be + relative and may not contain the '..' path or start with '..'. items: description: Maps a string key to a path within a volume. @@ -2005,25 +1945,21 @@ spec: description: key is the key to project. type: string mode: - description: 'mode is Optional: mode bits - used to set permissions on this file. - Must be an octal value between 0000 and - 0777 or a decimal value between 0 and - 511. YAML accepts both octal and decimal - values, JSON requires decimal values for - mode bits. If not specified, the volume - defaultMode will be used. This might be - in conflict with other options that affect - the file mode, like fsGroup, and the result - can be other mode bits set.' + description: |- + mode is Optional: mode bits used to set permissions on this file. + Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. + If not specified, the volume defaultMode will be used. + This might be in conflict with other options that affect the file + mode, like fsGroup, and the result can be other mode bits set. format: int32 type: integer path: - description: path is the relative path of - the file to map the key to. May not be - an absolute path. May not contain the - path element '..'. May not start with - the string '..'. + description: |- + path is the relative path of the file to map the key to. + May not be an absolute path. + May not contain the path element '..'. + May not start with the string '..'. type: string required: - key @@ -2035,8 +1971,9 @@ spec: Secret or its keys must be defined type: boolean secretName: - description: 'secretName is the name of the secret - in the pod''s namespace to use. More info: https://kubernetes.io/docs/concepts/storage/volumes#secret' + description: |- + secretName is the name of the secret in the pod's namespace to use. + More info: https://kubernetes.io/docs/concepts/storage/volumes#secret type: string type: object storageos: @@ -2044,45 +1981,42 @@ spec: attached and mounted on Kubernetes nodes. properties: fsType: - description: fsType is the filesystem type to - mount. Must be a filesystem type supported by - the host operating system. Ex. "ext4", "xfs", - "ntfs". Implicitly inferred to be "ext4" if - unspecified. + description: |- + fsType is the filesystem type to mount. + Must be a filesystem type supported by the host operating system. + Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. type: string readOnly: - description: readOnly defaults to false (read/write). - ReadOnly here will force the ReadOnly setting - in VolumeMounts. + description: |- + readOnly defaults to false (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. type: boolean secretRef: - description: secretRef specifies the secret to - use for obtaining the StorageOS API credentials. If - not specified, default values will be attempted. + description: |- + secretRef specifies the secret to use for obtaining the StorageOS API + credentials. If not specified, default values will be attempted. properties: name: - description: 'Name of the referent. More info: - https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, - kind, uid?' + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? type: string type: object + x-kubernetes-map-type: atomic volumeName: - description: volumeName is the human-readable - name of the StorageOS volume. Volume names - are only unique within a namespace. + description: |- + volumeName is the human-readable name of the StorageOS volume. Volume + names are only unique within a namespace. type: string volumeNamespace: - description: volumeNamespace specifies the scope - of the volume within StorageOS. If no namespace - is specified then the Pod's namespace will be - used. This allows the Kubernetes name scoping - to be mirrored within StorageOS for tighter - integration. Set VolumeName to any name to override - the default behaviour. Set to "default" if you - are not using namespaces within StorageOS. Namespaces - that do not pre-exist within StorageOS will - be created. + description: |- + volumeNamespace specifies the scope of the volume within StorageOS. If no + namespace is specified then the Pod's namespace will be used. This allows the + Kubernetes name scoping to be mirrored within StorageOS for tighter integration. + Set VolumeName to any name to override the default behaviour. + Set to "default" if you are not using namespaces within StorageOS. + Namespaces that do not pre-exist within StorageOS will be created. type: string type: object vsphereVolume: @@ -2090,10 +2024,10 @@ spec: attached and mounted on kubelets host machine properties: fsType: - description: fsType is filesystem type to mount. - Must be a filesystem type supported by the host - operating system. Ex. "ext4", "xfs", "ntfs". - Implicitly inferred to be "ext4" if unspecified. + description: |- + fsType is filesystem type to mount. + Must be a filesystem type supported by the host operating system. + Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. type: string storagePolicyID: description: storagePolicyID is the storage Policy @@ -2137,8 +2071,9 @@ spec: description: Conditions represents the current state of the Request Service. items: - description: Condition represents the current state of the Request - Service. A condition might not show up if it is not happening. + description: |- + Condition represents the current state of the Request Service. + A condition might not show up if it is not happening. properties: lastTransitionTime: description: Last time the condition transitioned from one status @@ -2210,5 +2145,5 @@ status: acceptedNames: kind: "" plural: "" - conditions: [] - storedVersions: [] + conditions: null + storedVersions: null diff --git a/bundle/manifests/operator.ibm.com_operandrequests.yaml b/bundle/manifests/operator.ibm.com_operandrequests.yaml index f6109d5b..8fc3373d 100644 --- a/bundle/manifests/operator.ibm.com_operandrequests.yaml +++ b/bundle/manifests/operator.ibm.com_operandrequests.yaml @@ -2,7 +2,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.6.1 + controller-gen.kubebuilder.io/version: v0.14.0 creationTimestamp: null labels: app.kubernetes.io/instance: operand-deployment-lifecycle-manager @@ -34,17 +34,24 @@ spec: name: v1alpha1 schema: openAPIV3Schema: - description: OperandRequest is the Schema for the operandrequests API. + description: OperandRequest is the Schema for the operandrequests API. Documentation + For additional details regarding install parameters check https://ibm.biz/icpfs39install. + License By installing this product you accept the license terms https://ibm.biz/icpfs39license properties: apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources type: string kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds type: string metadata: type: object @@ -74,13 +81,12 @@ spec: type: string bindings: additionalProperties: - description: Bindable is a Kubernetes resources to be - shared from one namespace to another. List of supported - resources are Secrets, Configmaps, Services, and Routes. - Secrets and Configmaps will be copied such that a - new Secret/Configmap with exactly the same data will - be created in the target namespace. Services and Routes - data will be copied into a configmap in the target + description: |- + Bindable is a Kubernetes resources to be shared from one namespace to another. + List of supported resources are Secrets, Configmaps, Services, and Routes. + Secrets and Configmaps will be copied such that a new Secret/Configmap with + exactly the same data will be created in the target namespace. + Services and Routes data will be copied into a configmap in the target namespace. properties: configmap: @@ -89,15 +95,15 @@ spec: share to the namespace of the OperandRequest. type: string route: - description: Route data will be shared by copying - it into a configmap which is then created in the - target namespace + description: |- + Route data will be shared by copying it into a configmap which is then + created in the target namespace properties: data: additionalProperties: type: string - description: Data is a key-value pair where - the value is a YAML path to a value in the + description: |- + Data is a key-value pair where the value is a YAML path to a value in the OpenShift Route, e.g. .spec.host or .spec.tls.termination type: object name: @@ -111,15 +117,15 @@ spec: of the OperandRequest. type: string service: - description: Service data will be shared by copying - it into a configmap which is then created in the - target namespace + description: |- + Service data will be shared by copying it into a configmap which is then + created in the target namespace properties: data: additionalProperties: type: string - description: Data is a key-value pair where - the value is a YAML path to a value in the + description: |- + Data is a key-value pair where the value is a YAML path to a value in the Kubernetes Service, e.g. .spec.ports[0]port type: object name: @@ -132,22 +138,22 @@ spec: of secret and/or configmap. type: object instanceName: - description: InstanceName is used when users want to deploy - multiple custom resources. It is the name of the custom - resource. + description: |- + InstanceName is used when users want to deploy multiple custom resources. + It is the name of the custom resource. type: string kind: - description: Kind is used when users want to deploy multiple - custom resources. Kind identifies the kind of the custom - resource. + description: |- + Kind is used when users want to deploy multiple custom resources. + Kind identifies the kind of the custom resource. type: string name: description: Name of the operand to be deployed. type: string spec: - description: Spec is used when users want to deploy multiple - custom resources. It is the configuration map of custom - resource. + description: |- + Spec is used when users want to deploy multiple custom resources. + It is the configuration map of custom resource. nullable: true type: object x-kubernetes-preserve-unknown-fields: true @@ -160,9 +166,9 @@ spec: reside. type: string registryNamespace: - description: Specifies the namespace in which the OperandRegistry - reside. The default is the current namespace in which the - request is defined. + description: |- + Specifies the namespace in which the OperandRegistry reside. + The default is the current namespace in which the request is defined. type: string required: - operands @@ -180,8 +186,9 @@ spec: description: Conditions represents the current state of the Request Service. items: - description: Condition represents the current state of the Request - Service. A condition might not show up if it is not happening. + description: |- + Condition represents the current state of the Request Service. + A condition might not show up if it is not happening. properties: lastTransitionTime: description: Last time the condition transitioned from one status @@ -315,5 +322,5 @@ status: acceptedNames: kind: "" plural: "" - conditions: [] - storedVersions: [] + conditions: null + storedVersions: null diff --git a/bundle/manifests/operator.ibm.com_operatorconfigs.yaml b/bundle/manifests/operator.ibm.com_operatorconfigs.yaml index d21f73e4..b7329bbe 100644 --- a/bundle/manifests/operator.ibm.com_operatorconfigs.yaml +++ b/bundle/manifests/operator.ibm.com_operatorconfigs.yaml @@ -2,7 +2,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.6.1 + controller-gen.kubebuilder.io/version: v0.14.0 creationTimestamp: null labels: app.kubernetes.io/instance: operand-deployment-lifecycle-manager @@ -24,14 +24,19 @@ spec: description: OperatorConfig is the Schema for the operatorconfigs API properties: apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources type: string kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds type: string metadata: type: object @@ -57,22 +62,20 @@ spec: the pod. properties: preferredDuringSchedulingIgnoredDuringExecution: - description: The scheduler will prefer to schedule pods - to nodes that satisfy the affinity expressions specified - by this field, but it may choose a node that violates - one or more of the expressions. The node that is most - preferred is the one with the greatest sum of weights, - i.e. for each node that meets all of the scheduling - requirements (resource request, requiredDuringScheduling - affinity expressions, etc.), compute a sum by iterating - through the elements of this field and adding "weight" - to the sum if the node matches the corresponding matchExpressions; - the node(s) with the highest sum are the most preferred. + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node matches the corresponding matchExpressions; the + node(s) with the highest sum are the most preferred. items: - description: An empty preferred scheduling term matches - all objects with implicit weight 0 (i.e. it's a - no-op). A null preferred scheduling term matches - no objects (i.e. is also a no-op). + description: |- + An empty preferred scheduling term matches all objects with implicit weight 0 + (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op). properties: preference: description: A node selector term, associated @@ -82,32 +85,26 @@ spec: description: A list of node selector requirements by node's labels. items: - description: A node selector requirement - is a selector that contains values, a - key, and an operator that relates the - key and values. + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. properties: key: description: The label key that the selector applies to. type: string operator: - description: Represents a key's relationship - to a set of values. Valid operators - are In, NotIn, Exists, DoesNotExist. - Gt, and Lt. + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. type: string values: - description: An array of string values. - If the operator is In or NotIn, the - values array must be non-empty. If - the operator is Exists or DoesNotExist, - the values array must be empty. If - the operator is Gt or Lt, the values - array must have a single element, - which will be interpreted as an integer. - This array is replaced during a strategic - merge patch. + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. items: type: string type: array @@ -120,32 +117,26 @@ spec: description: A list of node selector requirements by node's fields. items: - description: A node selector requirement - is a selector that contains values, a - key, and an operator that relates the - key and values. + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. properties: key: description: The label key that the selector applies to. type: string operator: - description: Represents a key's relationship - to a set of values. Valid operators - are In, NotIn, Exists, DoesNotExist. - Gt, and Lt. + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. type: string values: - description: An array of string values. - If the operator is In or NotIn, the - values array must be non-empty. If - the operator is Exists or DoesNotExist, - the values array must be empty. If - the operator is Gt or Lt, the values - array must have a single element, - which will be interpreted as an integer. - This array is replaced during a strategic - merge patch. + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. items: type: string type: array @@ -155,6 +146,7 @@ spec: type: object type: array type: object + x-kubernetes-map-type: atomic weight: description: Weight associated with matching the corresponding nodeSelectorTerm, in the range @@ -167,53 +159,46 @@ spec: type: object type: array requiredDuringSchedulingIgnoredDuringExecution: - description: If the affinity requirements specified - by this field are not met at scheduling time, the - pod will not be scheduled onto the node. If the affinity - requirements specified by this field cease to be met - at some point during pod execution (e.g. due to an - update), the system may or may not try to eventually - evict the pod from its node. + description: |- + If the affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to an update), the system + may or may not try to eventually evict the pod from its node. properties: nodeSelectorTerms: description: Required. A list of node selector terms. The terms are ORed. items: - description: A null or empty node selector term - matches no objects. The requirements of them - are ANDed. The TopologySelectorTerm type implements - a subset of the NodeSelectorTerm. + description: |- + A null or empty node selector term matches no objects. The requirements of + them are ANDed. + The TopologySelectorTerm type implements a subset of the NodeSelectorTerm. properties: matchExpressions: description: A list of node selector requirements by node's labels. items: - description: A node selector requirement - is a selector that contains values, a - key, and an operator that relates the - key and values. + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. properties: key: description: The label key that the selector applies to. type: string operator: - description: Represents a key's relationship - to a set of values. Valid operators - are In, NotIn, Exists, DoesNotExist. - Gt, and Lt. + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. type: string values: - description: An array of string values. - If the operator is In or NotIn, the - values array must be non-empty. If - the operator is Exists or DoesNotExist, - the values array must be empty. If - the operator is Gt or Lt, the values - array must have a single element, - which will be interpreted as an integer. - This array is replaced during a strategic - merge patch. + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. items: type: string type: array @@ -226,32 +211,26 @@ spec: description: A list of node selector requirements by node's fields. items: - description: A node selector requirement - is a selector that contains values, a - key, and an operator that relates the - key and values. + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. properties: key: description: The label key that the selector applies to. type: string operator: - description: Represents a key's relationship - to a set of values. Valid operators - are In, NotIn, Exists, DoesNotExist. - Gt, and Lt. + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. type: string values: - description: An array of string values. - If the operator is In or NotIn, the - values array must be non-empty. If - the operator is Exists or DoesNotExist, - the values array must be empty. If - the operator is Gt or Lt, the values - array must have a single element, - which will be interpreted as an integer. - This array is replaced during a strategic - merge patch. + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. items: type: string type: array @@ -261,10 +240,12 @@ spec: type: object type: array type: object + x-kubernetes-map-type: atomic type: array required: - nodeSelectorTerms type: object + x-kubernetes-map-type: atomic type: object podAffinity: description: Describes pod affinity scheduling rules (e.g. @@ -272,18 +253,16 @@ spec: other pod(s)). properties: preferredDuringSchedulingIgnoredDuringExecution: - description: The scheduler will prefer to schedule pods - to nodes that satisfy the affinity expressions specified - by this field, but it may choose a node that violates - one or more of the expressions. The node that is most - preferred is the one with the greatest sum of weights, - i.e. for each node that meets all of the scheduling - requirements (resource request, requiredDuringScheduling - affinity expressions, etc.), compute a sum by iterating - through the elements of this field and adding "weight" - to the sum if the node has pods which matches the - corresponding podAffinityTerm; the node(s) with the - highest sum are the most preferred. + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the + node(s) with the highest sum are the most preferred. items: description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred @@ -302,29 +281,24 @@ spec: of label selector requirements. The requirements are ANDed. items: - description: A label selector requirement - is a selector that contains values, - a key, and an operator that relates - the key and values. + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. properties: key: description: key is the label key that the selector applies to. type: string operator: - description: operator represents - a key's relationship to a set - of values. Valid operators are - In, NotIn, Exists and DoesNotExist. + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. type: string values: - description: values is an array - of string values. If the operator - is In or NotIn, the values array - must be non-empty. If the operator - is Exists or DoesNotExist, the - values array must be empty. This - array is replaced during a strategic + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic merge patch. items: type: string @@ -337,52 +311,44 @@ spec: matchLabels: additionalProperties: type: string - description: matchLabels is a map of {key,value} - pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, - whose key field is "key", the operator - is "In", and the values array contains - only "value". The requirements are ANDed. + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. type: object type: object + x-kubernetes-map-type: atomic namespaceSelector: - description: A label query over the set of - namespaces that the term applies to. The - term is applied to the union of the namespaces - selected by this field and the ones listed - in the namespaces field. null selector and - null or empty namespaces list means "this - pod's namespace". An empty selector ({}) - matches all namespaces. + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. properties: matchExpressions: description: matchExpressions is a list of label selector requirements. The requirements are ANDed. items: - description: A label selector requirement - is a selector that contains values, - a key, and an operator that relates - the key and values. + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. properties: key: description: key is the label key that the selector applies to. type: string operator: - description: operator represents - a key's relationship to a set - of values. Valid operators are - In, NotIn, Exists and DoesNotExist. + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. type: string values: - description: values is an array - of string values. If the operator - is In or NotIn, the values array - must be non-empty. If the operator - is Exists or DoesNotExist, the - values array must be empty. This - array is replaced during a strategic + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic merge patch. items: type: string @@ -395,43 +361,37 @@ spec: matchLabels: additionalProperties: type: string - description: matchLabels is a map of {key,value} - pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, - whose key field is "key", the operator - is "In", and the values array contains - only "value". The requirements are ANDed. + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. type: object type: object + x-kubernetes-map-type: atomic namespaces: - description: namespaces specifies a static - list of namespace names that the term applies - to. The term is applied to the union of - the namespaces listed in this field and - the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector - means "this pod's namespace". + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". items: type: string type: array topologyKey: - description: This pod should be co-located - (affinity) or not co-located (anti-affinity) - with the pods matching the labelSelector - in the specified namespaces, where co-located - is defined as running on a node whose value - of the label with key topologyKey matches - that of any node on which any of the selected - pods is running. Empty topologyKey is not - allowed. + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. type: string required: - topologyKey type: object weight: - description: weight associated with matching the - corresponding podAffinityTerm, in the range - 1-100. + description: |- + weight associated with matching the corresponding podAffinityTerm, + in the range 1-100. format: int32 type: integer required: @@ -440,24 +400,22 @@ spec: type: object type: array requiredDuringSchedulingIgnoredDuringExecution: - description: If the affinity requirements specified - by this field are not met at scheduling time, the - pod will not be scheduled onto the node. If the affinity - requirements specified by this field cease to be met - at some point during pod execution (e.g. due to a - pod label update), the system may or may not try to - eventually evict the pod from its node. When there - are multiple elements, the lists of nodes corresponding - to each podAffinityTerm are intersected, i.e. all - terms must be satisfied. + description: |- + If the affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to a pod label update), the + system may or may not try to eventually evict the pod from its node. + When there are multiple elements, the lists of nodes corresponding to each + podAffinityTerm are intersected, i.e. all terms must be satisfied. items: - description: Defines a set of pods (namely those matching - the labelSelector relative to the given namespace(s)) - that this pod should be co-located (affinity) or - not co-located (anti-affinity) with, where co-located - is defined as running on a node whose value of the - label with key matches that of any - node on which a pod of the set of pods is running + description: |- + Defines a set of pods (namely those matching the labelSelector + relative to the given namespace(s)) that this pod should be + co-located (affinity) or not co-located (anti-affinity) with, + where co-located is defined as running on a node whose value of + the label with key matches that of any node on which + a pod of the set of pods is running properties: labelSelector: description: A label query over a set of resources, @@ -468,28 +426,24 @@ spec: label selector requirements. The requirements are ANDed. items: - description: A label selector requirement - is a selector that contains values, a - key, and an operator that relates the - key and values. + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. properties: key: description: key is the label key that the selector applies to. type: string operator: - description: operator represents a key's - relationship to a set of values. Valid - operators are In, NotIn, Exists and - DoesNotExist. + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. type: string values: - description: values is an array of string - values. If the operator is In or NotIn, - the values array must be non-empty. - If the operator is Exists or DoesNotExist, - the values array must be empty. This - array is replaced during a strategic + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic merge patch. items: type: string @@ -502,50 +456,44 @@ spec: matchLabels: additionalProperties: type: string - description: matchLabels is a map of {key,value} - pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, - whose key field is "key", the operator is - "In", and the values array contains only - "value". The requirements are ANDed. + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. type: object type: object + x-kubernetes-map-type: atomic namespaceSelector: - description: A label query over the set of namespaces - that the term applies to. The term is applied - to the union of the namespaces selected by this - field and the ones listed in the namespaces - field. null selector and null or empty namespaces - list means "this pod's namespace". An empty - selector ({}) matches all namespaces. + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. properties: matchExpressions: description: matchExpressions is a list of label selector requirements. The requirements are ANDed. items: - description: A label selector requirement - is a selector that contains values, a - key, and an operator that relates the - key and values. + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. properties: key: description: key is the label key that the selector applies to. type: string operator: - description: operator represents a key's - relationship to a set of values. Valid - operators are In, NotIn, Exists and - DoesNotExist. + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. type: string values: - description: values is an array of string - values. If the operator is In or NotIn, - the values array must be non-empty. - If the operator is Exists or DoesNotExist, - the values array must be empty. This - array is replaced during a strategic + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic merge patch. items: type: string @@ -558,34 +506,29 @@ spec: matchLabels: additionalProperties: type: string - description: matchLabels is a map of {key,value} - pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, - whose key field is "key", the operator is - "In", and the values array contains only - "value". The requirements are ANDed. + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. type: object type: object + x-kubernetes-map-type: atomic namespaces: - description: namespaces specifies a static list - of namespace names that the term applies to. - The term is applied to the union of the namespaces - listed in this field and the ones selected by - namespaceSelector. null or empty namespaces - list and null namespaceSelector means "this - pod's namespace". + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". items: type: string type: array topologyKey: - description: This pod should be co-located (affinity) - or not co-located (anti-affinity) with the pods - matching the labelSelector in the specified - namespaces, where co-located is defined as running - on a node whose value of the label with key - topologyKey matches that of any node on which - any of the selected pods is running. Empty topologyKey - is not allowed. + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. type: string required: - topologyKey @@ -598,18 +541,16 @@ spec: as some other pod(s)). properties: preferredDuringSchedulingIgnoredDuringExecution: - description: The scheduler will prefer to schedule pods - to nodes that satisfy the anti-affinity expressions - specified by this field, but it may choose a node - that violates one or more of the expressions. The - node that is most preferred is the one with the greatest - sum of weights, i.e. for each node that meets all - of the scheduling requirements (resource request, - requiredDuringScheduling anti-affinity expressions, - etc.), compute a sum by iterating through the elements - of this field and adding "weight" to the sum if the - node has pods which matches the corresponding podAffinityTerm; - the node(s) with the highest sum are the most preferred. + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the anti-affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling anti-affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the + node(s) with the highest sum are the most preferred. items: description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred @@ -628,29 +569,24 @@ spec: of label selector requirements. The requirements are ANDed. items: - description: A label selector requirement - is a selector that contains values, - a key, and an operator that relates - the key and values. + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. properties: key: description: key is the label key that the selector applies to. type: string operator: - description: operator represents - a key's relationship to a set - of values. Valid operators are - In, NotIn, Exists and DoesNotExist. + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. type: string values: - description: values is an array - of string values. If the operator - is In or NotIn, the values array - must be non-empty. If the operator - is Exists or DoesNotExist, the - values array must be empty. This - array is replaced during a strategic + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic merge patch. items: type: string @@ -663,52 +599,44 @@ spec: matchLabels: additionalProperties: type: string - description: matchLabels is a map of {key,value} - pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, - whose key field is "key", the operator - is "In", and the values array contains - only "value". The requirements are ANDed. + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. type: object type: object + x-kubernetes-map-type: atomic namespaceSelector: - description: A label query over the set of - namespaces that the term applies to. The - term is applied to the union of the namespaces - selected by this field and the ones listed - in the namespaces field. null selector and - null or empty namespaces list means "this - pod's namespace". An empty selector ({}) - matches all namespaces. + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. properties: matchExpressions: description: matchExpressions is a list of label selector requirements. The requirements are ANDed. items: - description: A label selector requirement - is a selector that contains values, - a key, and an operator that relates - the key and values. + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. properties: key: description: key is the label key that the selector applies to. type: string operator: - description: operator represents - a key's relationship to a set - of values. Valid operators are - In, NotIn, Exists and DoesNotExist. + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. type: string values: - description: values is an array - of string values. If the operator - is In or NotIn, the values array - must be non-empty. If the operator - is Exists or DoesNotExist, the - values array must be empty. This - array is replaced during a strategic + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic merge patch. items: type: string @@ -721,43 +649,37 @@ spec: matchLabels: additionalProperties: type: string - description: matchLabels is a map of {key,value} - pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, - whose key field is "key", the operator - is "In", and the values array contains - only "value". The requirements are ANDed. + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. type: object type: object + x-kubernetes-map-type: atomic namespaces: - description: namespaces specifies a static - list of namespace names that the term applies - to. The term is applied to the union of - the namespaces listed in this field and - the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector - means "this pod's namespace". + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". items: type: string type: array topologyKey: - description: This pod should be co-located - (affinity) or not co-located (anti-affinity) - with the pods matching the labelSelector - in the specified namespaces, where co-located - is defined as running on a node whose value - of the label with key topologyKey matches - that of any node on which any of the selected - pods is running. Empty topologyKey is not - allowed. + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. type: string required: - topologyKey type: object weight: - description: weight associated with matching the - corresponding podAffinityTerm, in the range - 1-100. + description: |- + weight associated with matching the corresponding podAffinityTerm, + in the range 1-100. format: int32 type: integer required: @@ -766,24 +688,22 @@ spec: type: object type: array requiredDuringSchedulingIgnoredDuringExecution: - description: If the anti-affinity requirements specified - by this field are not met at scheduling time, the - pod will not be scheduled onto the node. If the anti-affinity - requirements specified by this field cease to be met - at some point during pod execution (e.g. due to a - pod label update), the system may or may not try to - eventually evict the pod from its node. When there - are multiple elements, the lists of nodes corresponding - to each podAffinityTerm are intersected, i.e. all - terms must be satisfied. + description: |- + If the anti-affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the anti-affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to a pod label update), the + system may or may not try to eventually evict the pod from its node. + When there are multiple elements, the lists of nodes corresponding to each + podAffinityTerm are intersected, i.e. all terms must be satisfied. items: - description: Defines a set of pods (namely those matching - the labelSelector relative to the given namespace(s)) - that this pod should be co-located (affinity) or - not co-located (anti-affinity) with, where co-located - is defined as running on a node whose value of the - label with key matches that of any - node on which a pod of the set of pods is running + description: |- + Defines a set of pods (namely those matching the labelSelector + relative to the given namespace(s)) that this pod should be + co-located (affinity) or not co-located (anti-affinity) with, + where co-located is defined as running on a node whose value of + the label with key matches that of any node on which + a pod of the set of pods is running properties: labelSelector: description: A label query over a set of resources, @@ -794,28 +714,24 @@ spec: label selector requirements. The requirements are ANDed. items: - description: A label selector requirement - is a selector that contains values, a - key, and an operator that relates the - key and values. + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. properties: key: description: key is the label key that the selector applies to. type: string operator: - description: operator represents a key's - relationship to a set of values. Valid - operators are In, NotIn, Exists and - DoesNotExist. + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. type: string values: - description: values is an array of string - values. If the operator is In or NotIn, - the values array must be non-empty. - If the operator is Exists or DoesNotExist, - the values array must be empty. This - array is replaced during a strategic + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic merge patch. items: type: string @@ -828,50 +744,44 @@ spec: matchLabels: additionalProperties: type: string - description: matchLabels is a map of {key,value} - pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, - whose key field is "key", the operator is - "In", and the values array contains only - "value". The requirements are ANDed. + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. type: object type: object + x-kubernetes-map-type: atomic namespaceSelector: - description: A label query over the set of namespaces - that the term applies to. The term is applied - to the union of the namespaces selected by this - field and the ones listed in the namespaces - field. null selector and null or empty namespaces - list means "this pod's namespace". An empty - selector ({}) matches all namespaces. + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. properties: matchExpressions: description: matchExpressions is a list of label selector requirements. The requirements are ANDed. items: - description: A label selector requirement - is a selector that contains values, a - key, and an operator that relates the - key and values. + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. properties: key: description: key is the label key that the selector applies to. type: string operator: - description: operator represents a key's - relationship to a set of values. Valid - operators are In, NotIn, Exists and - DoesNotExist. + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. type: string values: - description: values is an array of string - values. If the operator is In or NotIn, - the values array must be non-empty. - If the operator is Exists or DoesNotExist, - the values array must be empty. This - array is replaced during a strategic + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic merge patch. items: type: string @@ -884,34 +794,29 @@ spec: matchLabels: additionalProperties: type: string - description: matchLabels is a map of {key,value} - pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, - whose key field is "key", the operator is - "In", and the values array contains only - "value". The requirements are ANDed. + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. type: object type: object + x-kubernetes-map-type: atomic namespaces: - description: namespaces specifies a static list - of namespace names that the term applies to. - The term is applied to the union of the namespaces - listed in this field and the ones selected by - namespaceSelector. null or empty namespaces - list and null namespaceSelector means "this - pod's namespace". + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". items: type: string type: array topologyKey: - description: This pod should be co-located (affinity) - or not co-located (anti-affinity) with the pods - matching the labelSelector in the specified - namespaces, where co-located is defined as running - on a node whose value of the label with key - topologyKey matches that of any node on which - any of the selected pods is running. Empty topologyKey - is not allowed. + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. type: string required: - topologyKey @@ -923,30 +828,32 @@ spec: description: Name is the operator name as requested in the OperandRequest. type: string replicas: - description: Number of desired pods. This is a pointer to distinguish - between explicit zero and not specified. Defaults to 1. + description: |- + Number of desired pods. This is a pointer to distinguish between explicit + zero and not specified. Defaults to 1. format: int32 type: integer topologySpreadConstraints: - description: TopologySpreadConstraints describes how a group - of pods ought to spread across topology domains. Scheduler - will schedule pods in a way which abides by the constraints. + description: |- + TopologySpreadConstraints describes how a group of pods ought to spread across topology + domains. Scheduler will schedule pods in a way which abides by the constraints. All topologySpreadConstraints are ANDed. items: description: TopologySpreadConstraint specifies how to spread matching pods among the given topology. properties: labelSelector: - description: LabelSelector is used to find matching pods. - Pods that match this label selector are counted to determine - the number of pods in their corresponding topology domain. + description: |- + LabelSelector is used to find matching pods. + Pods that match this label selector are counted to determine the number of pods + in their corresponding topology domain. properties: matchExpressions: description: matchExpressions is a list of label selector requirements. The requirements are ANDed. items: - description: A label selector requirement is a selector - that contains values, a key, and an operator that + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. properties: key: @@ -954,17 +861,16 @@ spec: applies to. type: string operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, - NotIn, Exists and DoesNotExist. + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. type: string values: - description: values is an array of string values. - If the operator is In or NotIn, the values - array must be non-empty. If the operator is - Exists or DoesNotExist, the values array must - be empty. This array is replaced during a - strategic merge patch. + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. items: type: string type: array @@ -976,93 +882,93 @@ spec: matchLabels: additionalProperties: type: string - description: matchLabels is a map of {key,value} pairs. - A single {key,value} in the matchLabels map is equivalent - to an element of matchExpressions, whose key field - is "key", the operator is "In", and the values array - contains only "value". The requirements are ANDed. + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. type: object type: object + x-kubernetes-map-type: atomic maxSkew: - description: 'MaxSkew describes the degree to which pods - may be unevenly distributed. When `whenUnsatisfiable=DoNotSchedule`, - it is the maximum permitted difference between the number - of matching pods in the target topology and the global - minimum. The global minimum is the minimum number of - matching pods in an eligible domain or zero if the number - of eligible domains is less than MinDomains. For example, - in a 3-zone cluster, MaxSkew is set to 1, and pods with - the same labelSelector spread as 2/2/1: In this case, - the global minimum is 1. | zone1 | zone2 | zone3 | | P - P | P P | P | - if MaxSkew is 1, incoming pod - can only be scheduled to zone3 to become 2/2/2; scheduling - it onto zone1(zone2) would make the ActualSkew(3-1) - on zone1(zone2) violate MaxSkew(1). - if MaxSkew is - 2, incoming pod can be scheduled onto any zone. When - `whenUnsatisfiable=ScheduleAnyway`, it is used to give - higher precedence to topologies that satisfy it. It''s - a required field. Default value is 1 and 0 is not allowed.' + description: |- + MaxSkew describes the degree to which pods may be unevenly distributed. + When `whenUnsatisfiable=DoNotSchedule`, it is the maximum permitted difference + between the number of matching pods in the target topology and the global minimum. + The global minimum is the minimum number of matching pods in an eligible domain + or zero if the number of eligible domains is less than MinDomains. + For example, in a 3-zone cluster, MaxSkew is set to 1, and pods with the same + labelSelector spread as 2/2/1: + In this case, the global minimum is 1. + | zone1 | zone2 | zone3 | + | P P | P P | P | + - if MaxSkew is 1, incoming pod can only be scheduled to zone3 to become 2/2/2; + scheduling it onto zone1(zone2) would make the ActualSkew(3-1) on zone1(zone2) + violate MaxSkew(1). + - if MaxSkew is 2, incoming pod can be scheduled onto any zone. + When `whenUnsatisfiable=ScheduleAnyway`, it is used to give higher precedence + to topologies that satisfy it. + It's a required field. Default value is 1 and 0 is not allowed. format: int32 type: integer minDomains: - description: "MinDomains indicates a minimum number of - eligible domains. When the number of eligible domains - with matching topology keys is less than minDomains, - Pod Topology Spread treats \"global minimum\" as 0, - and then the calculation of Skew is performed. And when - the number of eligible domains with matching topology - keys equals or greater than minDomains, this value has - no effect on scheduling. As a result, when the number - of eligible domains is less than minDomains, scheduler - won't schedule more than maxSkew Pods to those domains. - If value is nil, the constraint behaves as if MinDomains - is equal to 1. Valid values are integers greater than - 0. When value is not nil, WhenUnsatisfiable must be - DoNotSchedule. \n For example, in a 3-zone cluster, - MaxSkew is set to 2, MinDomains is set to 5 and pods - with the same labelSelector spread as 2/2/2: | zone1 - | zone2 | zone3 | | P P | P P | P P | The number - of domains is less than 5(MinDomains), so \"global minimum\" - is treated as 0. In this situation, new pod with the - same labelSelector cannot be scheduled, because computed - skew will be 3(3 - 0) if new Pod is scheduled to any - of the three zones, it will violate MaxSkew. \n This - is an alpha field and requires enabling MinDomainsInPodTopologySpread - feature gate." + description: |- + MinDomains indicates a minimum number of eligible domains. + When the number of eligible domains with matching topology keys is less than minDomains, + Pod Topology Spread treats "global minimum" as 0, and then the calculation of Skew is performed. + And when the number of eligible domains with matching topology keys equals or greater than minDomains, + this value has no effect on scheduling. + As a result, when the number of eligible domains is less than minDomains, + scheduler won't schedule more than maxSkew Pods to those domains. + If value is nil, the constraint behaves as if MinDomains is equal to 1. + Valid values are integers greater than 0. + When value is not nil, WhenUnsatisfiable must be DoNotSchedule. + + + For example, in a 3-zone cluster, MaxSkew is set to 2, MinDomains is set to 5 and pods with the same + labelSelector spread as 2/2/2: + | zone1 | zone2 | zone3 | + | P P | P P | P P | + The number of domains is less than 5(MinDomains), so "global minimum" is treated as 0. + In this situation, new pod with the same labelSelector cannot be scheduled, + because computed skew will be 3(3 - 0) if new Pod is scheduled to any of the three zones, + it will violate MaxSkew. + + + This is an alpha field and requires enabling MinDomainsInPodTopologySpread feature gate. format: int32 type: integer topologyKey: - description: TopologyKey is the key of node labels. Nodes - that have a label with this key and identical values - are considered to be in the same topology. We consider - each as a "bucket", and try to put balanced - number of pods into each bucket. We define a domain - as a particular instance of a topology. Also, we define - an eligible domain as a domain whose nodes match the - node selector. e.g. If TopologyKey is "kubernetes.io/hostname", - each Node is a domain of that topology. And, if TopologyKey - is "topology.kubernetes.io/zone", each zone is a domain - of that topology. It's a required field. + description: |- + TopologyKey is the key of node labels. Nodes that have a label with this key + and identical values are considered to be in the same topology. + We consider each as a "bucket", and try to put balanced number + of pods into each bucket. + We define a domain as a particular instance of a topology. + Also, we define an eligible domain as a domain whose nodes match the node selector. + e.g. If TopologyKey is "kubernetes.io/hostname", each Node is a domain of that topology. + And, if TopologyKey is "topology.kubernetes.io/zone", each zone is a domain of that topology. + It's a required field. type: string whenUnsatisfiable: - description: 'WhenUnsatisfiable indicates how to deal - with a pod if it doesn''t satisfy the spread constraint. - - DoNotSchedule (default) tells the scheduler not to - schedule it. - ScheduleAnyway tells the scheduler to - schedule the pod in any location, but giving higher - precedence to topologies that would help reduce the skew. - A constraint is considered "Unsatisfiable" for an incoming - pod if and only if every possible node assignment for - that pod would violate "MaxSkew" on some topology. For - example, in a 3-zone cluster, MaxSkew is set to 1, and - pods with the same labelSelector spread as 3/1/1: | - zone1 | zone2 | zone3 | | P P P | P | P | If - WhenUnsatisfiable is set to DoNotSchedule, incoming - pod can only be scheduled to zone2(zone3) to become - 3/2/1(3/1/2) as ActualSkew(2-1) on zone2(zone3) satisfies - MaxSkew(1). In other words, the cluster can still be - imbalanced, but scheduler won''t make it *more* imbalanced. - It''s a required field.' + description: |- + WhenUnsatisfiable indicates how to deal with a pod if it doesn't satisfy + the spread constraint. + - DoNotSchedule (default) tells the scheduler not to schedule it. + - ScheduleAnyway tells the scheduler to schedule the pod in any location, + but giving higher precedence to topologies that would help reduce the + skew. + A constraint is considered "Unsatisfiable" for an incoming pod + if and only if every possible node assignment for that pod would violate + "MaxSkew" on some topology. + For example, in a 3-zone cluster, MaxSkew is set to 1, and pods with the same + labelSelector spread as 3/1/1: + | zone1 | zone2 | zone3 | + | P P P | P | P | + If WhenUnsatisfiable is set to DoNotSchedule, incoming pod can only be scheduled + to zone2(zone3) to become 3/2/1(3/1/2) as ActualSkew(2-1) on zone2(zone3) satisfies + MaxSkew(1). In other words, the cluster can still be imbalanced, but scheduler + won't make it *more* imbalanced. + It's a required field. type: string required: - maxSkew @@ -1094,5 +1000,5 @@ status: acceptedNames: kind: "" plural: "" - conditions: [] - storedVersions: [] + conditions: null + storedVersions: null diff --git a/bundle/metadata/annotations.yaml b/bundle/metadata/annotations.yaml index f3bfce43..e4758c86 100644 --- a/bundle/metadata/annotations.yaml +++ b/bundle/metadata/annotations.yaml @@ -6,7 +6,7 @@ annotations: operators.operatorframework.io.bundle.package.v1: ibm-odlm operators.operatorframework.io.bundle.channels.v1: v4.3 operators.operatorframework.io.bundle.channel.default.v1: v4.3 - operators.operatorframework.io.metrics.builder: operator-sdk-v1.29.0 + operators.operatorframework.io.metrics.builder: operator-sdk-v1.32.0 operators.operatorframework.io.metrics.mediatype.v1: metrics+v1 operators.operatorframework.io.metrics.project_layout: go.kubebuilder.io/v3 # Annotations for testing. diff --git a/config/crd/bases/operator.ibm.com_operandbindinfos.yaml b/config/crd/bases/operator.ibm.com_operandbindinfos.yaml index c9b0f10e..8d39a398 100644 --- a/config/crd/bases/operator.ibm.com_operandbindinfos.yaml +++ b/config/crd/bases/operator.ibm.com_operandbindinfos.yaml @@ -1,11 +1,9 @@ - --- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.6.1 - creationTimestamp: null + controller-gen.kubebuilder.io/version: v0.14.0 name: operandbindinfos.operator.ibm.com spec: group: operator.ibm.com @@ -33,16 +31,24 @@ spec: schema: openAPIV3Schema: description: OperandBindInfo is the Schema for the operandbindinfoes API. + Documentation For additional details regarding install parameters check + https://ibm.biz/icpfs39install. License By installing this product you accept + the license terms https://ibm.biz/icpfs39license properties: apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources type: string kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds type: string metadata: type: object @@ -51,12 +57,13 @@ spec: properties: bindings: additionalProperties: - description: Bindable is a Kubernetes resources to be shared from - one namespace to another. List of supported resources are Secrets, - Configmaps, Services, and Routes. Secrets and Configmaps will - be copied such that a new Secret/Configmap with exactly the same - data will be created in the target namespace. Services and Routes - data will be copied into a configmap in the target namespace. + description: |- + Bindable is a Kubernetes resources to be shared from one namespace to another. + List of supported resources are Secrets, Configmaps, Services, and Routes. + Secrets and Configmaps will be copied such that a new Secret/Configmap with + exactly the same data will be created in the target namespace. + Services and Routes data will be copied into a configmap in the target + namespace. properties: configmap: description: The configmap identifies an existing configmap @@ -64,15 +71,16 @@ spec: of the OperandRequest. type: string route: - description: Route data will be shared by copying it into a - configmap which is then created in the target namespace + description: |- + Route data will be shared by copying it into a configmap which is then + created in the target namespace properties: data: additionalProperties: type: string - description: Data is a key-value pair where the value is - a YAML path to a value in the OpenShift Route, e.g. .spec.host - or .spec.tls.termination + description: |- + Data is a key-value pair where the value is a YAML path to a value in the + OpenShift Route, e.g. .spec.host or .spec.tls.termination type: object name: description: Name is the name of the OpenShift Route resource @@ -83,15 +91,16 @@ spec: exists, the ODLM will share to the namespace of the OperandRequest. type: string service: - description: Service data will be shared by copying it into - a configmap which is then created in the target namespace + description: |- + Service data will be shared by copying it into a configmap which is then + created in the target namespace properties: data: additionalProperties: type: string - description: Data is a key-value pair where the value is - a YAML path to a value in the Kubernetes Service, e.g. - .spec.ports[0]port + description: |- + Data is a key-value pair where the value is a YAML path to a value in the + Kubernetes Service, e.g. .spec.ports[0]port type: object name: description: Name is the name of the Kubernetes Service @@ -105,7 +114,8 @@ spec: description: type: string operand: - description: The deployed service identifies itself with its operand. + description: |- + The deployed service identifies itself with its operand. This must match the name in the OperandRegistry in the current namespace. type: string registry: @@ -113,9 +123,9 @@ spec: CR from which this operand deployment is being requested. type: string registryNamespace: - description: Specifies the namespace in which the OperandRegistry - reside. The default is the current namespace in which the request - is defined. + description: |- + Specifies the namespace in which the OperandRegistry reside. + The default is the current namespace in which the request is defined. type: string required: - operand @@ -140,9 +150,3 @@ spec: storage: true subresources: status: {} -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] diff --git a/config/crd/bases/operator.ibm.com_operandconfigs.yaml b/config/crd/bases/operator.ibm.com_operandconfigs.yaml index 74d6d140..25503e44 100644 --- a/config/crd/bases/operator.ibm.com_operandconfigs.yaml +++ b/config/crd/bases/operator.ibm.com_operandconfigs.yaml @@ -1,11 +1,9 @@ - --- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.6.1 - creationTimestamp: null + controller-gen.kubebuilder.io/version: v0.14.0 name: operandconfigs.operator.ibm.com spec: group: operator.ibm.com @@ -32,17 +30,24 @@ spec: name: v1alpha1 schema: openAPIV3Schema: - description: OperandConfig is the Schema for the operandconfigs API. + description: OperandConfig is the Schema for the operandconfigs API. Documentation + For additional details regarding install parameters check https://ibm.biz/icpfs39install. + License By installing this product you accept the license terms https://ibm.biz/icpfs39license properties: apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources type: string kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds type: string metadata: type: object @@ -108,14 +113,16 @@ spec: description: API version of the referent. type: string blockOwnerDeletion: - description: If true, AND if the owner has the "foregroundDeletion" - finalizer, then the owner cannot be deleted from - the key-value store until this reference is removed. + description: |- + If true, AND if the owner has the "foregroundDeletion" finalizer, then + the owner cannot be deleted from the key-value store until this + reference is removed. Defaults to false. type: boolean controller: - description: If true, this reference points to the - managing controller. Default is false. + description: |- + If true, this reference points to the managing controller. + Default is false. type: boolean kind: description: Kind of the referent. @@ -177,9 +184,3 @@ spec: storage: true subresources: status: {} -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] diff --git a/config/crd/bases/operator.ibm.com_operandregistries.yaml b/config/crd/bases/operator.ibm.com_operandregistries.yaml index 2b74874a..b452d559 100644 --- a/config/crd/bases/operator.ibm.com_operandregistries.yaml +++ b/config/crd/bases/operator.ibm.com_operandregistries.yaml @@ -1,11 +1,9 @@ - --- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.6.1 - creationTimestamp: null + controller-gen.kubebuilder.io/version: v0.14.0 name: operandregistries.operator.ibm.com spec: group: operator.ibm.com @@ -33,16 +31,24 @@ spec: schema: openAPIV3Schema: description: OperandRegistry is the Schema for the operandregistries API. + Documentation For additional details regarding install parameters check + https://ibm.biz/icpfs39install. License By installing this product you accept + the license terms https://ibm.biz/icpfs39license properties: apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources type: string kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds type: string metadata: type: object @@ -61,27 +67,28 @@ spec: description: Description of a common service. type: string installMode: - description: 'The install mode of an operator, either namespace - or cluster. Valid values are: - "namespace" (default): operator - is deployed in namespace of OperandRegistry; - "cluster": - operator is deployed in "openshift-operators" namespace; - - "no-op": operator is not supported to be fresh deployed;' + description: |- + The install mode of an operator, either namespace or cluster. + Valid values are: + - "namespace" (default): operator is deployed in namespace of OperandRegistry; + - "cluster": operator is deployed in "openshift-operators" namespace; + - "no-op": operator is not supported to be fresh deployed; type: string installPlanApproval: - description: 'Approval mode for emitted InstallPlans. Valid - values are: - "Automatic" (default): operator will be installed - automatically; - "Manual": operator installation will be pending - until users approve it;' + description: |- + Approval mode for emitted InstallPlans. + Valid values are: + - "Automatic" (default): operator will be installed automatically; + - "Manual": operator installation will be pending until users approve it; type: string name: description: A unique name for the operator whose operand may be deployed. type: string namespace: - description: The namespace in which operator should be deployed - when InstallMode is empty or set to "namespace". If the namespace - is not set, the operator namespace is the same as OperandRegistry - Namespace + description: |- + The namespace in which operator should be deployed when InstallMode is empty or set to "namespace". + If the namespace is not set, the operator namespace is the same as OperandRegistry Namespace type: string operatorConfig: description: OperatorConfig is the name of the OperatorConfig @@ -90,10 +97,11 @@ spec: description: Name of the package that defines the applications. type: string scope: - description: 'A scope indicator, either public or private. Valid - values are: - "private" (default): deployment only request - from the containing names; - "public": deployment can be requested - from other namespaces;' + description: |- + A scope indicator, either public or private. + Valid values are: + - "private" (default): deployment only request from the containing names; + - "public": deployment can be requested from other namespaces; enum: - public - private @@ -114,8 +122,9 @@ spec: configuration. properties: env: - description: Env is a list of environment variables to set - in the container. Cannot be updated. + description: |- + Env is a list of environment variables to set in the container. + Cannot be updated. items: description: EnvVar represents an environment variable present in a Container. @@ -125,17 +134,16 @@ spec: be a C_IDENTIFIER. type: string value: - description: 'Variable references $(VAR_NAME) are - expanded using the previously defined environment - variables in the container and any service environment - variables. If a variable cannot be resolved, the - reference in the input string will be unchanged. - Double $$ are reduced to a single $, which allows - for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" - will produce the string literal "$(VAR_NAME)". Escaped - references will never be expanded, regardless of - whether the variable exists or not. Defaults to - "".' + description: |- + Variable references $(VAR_NAME) are expanded + using the previously defined environment variables in the container and + any service environment variables. If a variable cannot be resolved, + the reference in the input string will be unchanged. Double $$ are reduced + to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. + "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". + Escaped references will never be expanded, regardless of whether the variable + exists or not. + Defaults to "". type: string valueFrom: description: Source for the environment variable's @@ -148,10 +156,10 @@ spec: description: The key to select. type: string name: - description: 'Name of the referent. More info: - https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, - kind, uid?' + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? type: string optional: description: Specify whether the ConfigMap @@ -160,12 +168,11 @@ spec: required: - key type: object + x-kubernetes-map-type: atomic fieldRef: - description: 'Selects a field of the pod: supports - metadata.name, metadata.namespace, `metadata.labels['''']`, - `metadata.annotations['''']`, spec.nodeName, - spec.serviceAccountName, status.hostIP, status.podIP, - status.podIPs.' + description: |- + Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['']`, `metadata.annotations['']`, + spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs. properties: apiVersion: description: Version of the schema the FieldPath @@ -178,12 +185,11 @@ spec: required: - fieldPath type: object + x-kubernetes-map-type: atomic resourceFieldRef: - description: 'Selects a resource of the container: - only resources limits and requests (limits.cpu, - limits.memory, limits.ephemeral-storage, requests.cpu, - requests.memory and requests.ephemeral-storage) - are currently supported.' + description: |- + Selects a resource of the container: only resources limits and requests + (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported. properties: containerName: description: 'Container name: required for @@ -203,6 +209,7 @@ spec: required: - resource type: object + x-kubernetes-map-type: atomic secretKeyRef: description: Selects a key of a secret in the pod's namespace @@ -212,10 +219,10 @@ spec: from. Must be a valid secret key. type: string name: - description: 'Name of the referent. More info: - https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, - kind, uid?' + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? type: string optional: description: Specify whether the Secret or @@ -224,19 +231,20 @@ spec: required: - key type: object + x-kubernetes-map-type: atomic type: object required: - name type: object type: array envFrom: - description: EnvFrom is a list of sources to populate environment - variables in the container. The keys defined within a - source must be a C_IDENTIFIER. All invalid keys will be - reported as an event when the container is starting. When - a key exists in multiple sources, the value associated - with the last source will take precedence. Values defined - by an Env with a duplicate key will take precedence. Immutable. + description: |- + EnvFrom is a list of sources to populate environment variables in the container. + The keys defined within a source must be a C_IDENTIFIER. All invalid keys + will be reported as an event when the container is starting. When a key exists in multiple + sources, the value associated with the last source will take precedence. + Values defined by an Env with a duplicate key will take precedence. + Immutable. items: description: EnvFromSource represents the source of a set of ConfigMaps @@ -245,16 +253,17 @@ spec: description: The ConfigMap to select from properties: name: - description: 'Name of the referent. More info: - https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, kind, - uid?' + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? type: string optional: description: Specify whether the ConfigMap must be defined type: boolean type: object + x-kubernetes-map-type: atomic prefix: description: An optional identifier to prepend to each key in the ConfigMap. Must be a C_IDENTIFIER. @@ -263,29 +272,32 @@ spec: description: The Secret to select from properties: name: - description: 'Name of the referent. More info: - https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, kind, - uid?' + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? type: string optional: description: Specify whether the Secret must be defined type: boolean type: object + x-kubernetes-map-type: atomic type: object type: array nodeSelector: additionalProperties: type: string - description: 'NodeSelector is a selector which must be true - for the pod to fit on a node. Selector which must match - a node''s labels for the pod to be scheduled on that node. - More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/' + description: |- + NodeSelector is a selector which must be true for the pod to fit on a node. + Selector which must match a node's labels for the pod to be scheduled on that node. + More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ type: object resources: - description: 'Resources represents compute resources required - by this container. Immutable. More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/' + description: |- + Resources represents compute resources required by this container. + Immutable. + More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/ properties: limits: additionalProperties: @@ -294,8 +306,9 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: 'Limits describes the maximum amount of - compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object requests: additionalProperties: @@ -304,25 +317,26 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: 'Requests describes the minimum amount - of compute resources required. If Requests is omitted - for a container, it defaults to Limits if that is - explicitly specified, otherwise to an implementation-defined - value. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object type: object selector: - description: Selector is the label selector for pods to - be configured. Existing ReplicaSets whose pods are selected - by this will be the ones affected by this deployment. + description: |- + Selector is the label selector for pods to be configured. + Existing ReplicaSets whose pods are + selected by this will be the ones affected by this deployment. It must match the pod template's labels. properties: matchExpressions: description: matchExpressions is a list of label selector requirements. The requirements are ANDed. items: - description: A label selector requirement is a selector - that contains values, a key, and an operator that + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. properties: key: @@ -330,17 +344,16 @@ spec: applies to. type: string operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, - NotIn, Exists and DoesNotExist. + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. type: string values: - description: values is an array of string values. - If the operator is In or NotIn, the values array - must be non-empty. If the operator is Exists - or DoesNotExist, the values array must be empty. - This array is replaced during a strategic merge - patch. + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. items: type: string type: array @@ -352,53 +365,49 @@ spec: matchLabels: additionalProperties: type: string - description: matchLabels is a map of {key,value} pairs. - A single {key,value} in the matchLabels map is equivalent - to an element of matchExpressions, whose key field - is "key", the operator is "In", and the values array - contains only "value". The requirements are ANDed. + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. type: object type: object + x-kubernetes-map-type: atomic tolerations: description: Tolerations are the pod's tolerations. items: - description: The pod this Toleration is attached to tolerates - any taint that matches the triple - using the matching operator . + description: |- + The pod this Toleration is attached to tolerates any taint that matches + the triple using the matching operator . properties: effect: - description: Effect indicates the taint effect to - match. Empty means match all taint effects. When - specified, allowed values are NoSchedule, PreferNoSchedule - and NoExecute. + description: |- + Effect indicates the taint effect to match. Empty means match all taint effects. + When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. type: string key: - description: Key is the taint key that the toleration - applies to. Empty means match all taint keys. If - the key is empty, operator must be Exists; this - combination means to match all values and all keys. + description: |- + Key is the taint key that the toleration applies to. Empty means match all taint keys. + If the key is empty, operator must be Exists; this combination means to match all values and all keys. type: string operator: - description: Operator represents a key's relationship - to the value. Valid operators are Exists and Equal. - Defaults to Equal. Exists is equivalent to wildcard - for value, so that a pod can tolerate all taints - of a particular category. + description: |- + Operator represents a key's relationship to the value. + Valid operators are Exists and Equal. Defaults to Equal. + Exists is equivalent to wildcard for value, so that a pod can + tolerate all taints of a particular category. type: string tolerationSeconds: - description: TolerationSeconds represents the period - of time the toleration (which must be of effect - NoExecute, otherwise this field is ignored) tolerates - the taint. By default, it is not set, which means - tolerate the taint forever (do not evict). Zero - and negative values will be treated as 0 (evict - immediately) by the system. + description: |- + TolerationSeconds represents the period of time the toleration (which must be + of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, + it is not set, which means tolerate the taint forever (do not evict). Zero and + negative values will be treated as 0 (evict immediately) by the system. format: int64 type: integer value: - description: Value is the taint value the toleration - matches to. If the operator is Exists, the value - should be empty, otherwise just a regular string. + description: |- + Value is the taint value the toleration matches to. + If the operator is Exists, the value should be empty, otherwise just a regular string. type: string type: object type: array @@ -409,34 +418,36 @@ spec: within a container. properties: mountPath: - description: Path within the container at which the - volume should be mounted. Must not contain ':'. + description: |- + Path within the container at which the volume should be mounted. Must + not contain ':'. type: string mountPropagation: - description: mountPropagation determines how mounts - are propagated from the host to container and the - other way around. When not set, MountPropagationNone - is used. This field is beta in 1.10. + description: |- + mountPropagation determines how mounts are propagated from the host + to container and the other way around. + When not set, MountPropagationNone is used. + This field is beta in 1.10. type: string name: description: This must match the Name of a Volume. type: string readOnly: - description: Mounted read-only if true, read-write - otherwise (false or unspecified). Defaults to false. + description: |- + Mounted read-only if true, read-write otherwise (false or unspecified). + Defaults to false. type: boolean subPath: - description: Path within the volume from which the - container's volume should be mounted. Defaults to - "" (volume's root). + description: |- + Path within the volume from which the container's volume should be mounted. + Defaults to "" (volume's root). type: string subPathExpr: - description: Expanded path within the volume from - which the container's volume should be mounted. - Behaves similarly to SubPath but environment variable - references $(VAR_NAME) are expanded using the container's - environment. Defaults to "" (volume's root). SubPathExpr - and SubPath are mutually exclusive. + description: |- + Expanded path within the volume from which the container's volume should be mounted. + Behaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment. + Defaults to "" (volume's root). + SubPathExpr and SubPath are mutually exclusive. type: string required: - mountPath @@ -450,40 +461,36 @@ spec: that may be accessed by any container in the pod. properties: awsElasticBlockStore: - description: 'awsElasticBlockStore represents an AWS - Disk resource that is attached to a kubelet''s host - machine and then exposed to the pod. More info: - https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' + description: |- + awsElasticBlockStore represents an AWS Disk resource that is attached to a + kubelet's host machine and then exposed to the pod. + More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore properties: fsType: - description: 'fsType is the filesystem type of - the volume that you want to mount. Tip: Ensure - that the filesystem type is supported by the - host operating system. Examples: "ext4", "xfs", - "ntfs". Implicitly inferred to be "ext4" if - unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore - TODO: how do we prevent errors in the filesystem - from compromising the machine' + description: |- + fsType is the filesystem type of the volume that you want to mount. + Tip: Ensure that the filesystem type is supported by the host operating system. + Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore + TODO: how do we prevent errors in the filesystem from compromising the machine type: string partition: - description: 'partition is the partition in the - volume that you want to mount. If omitted, the - default is to mount by volume name. Examples: - For volume /dev/sda1, you specify the partition - as "1". Similarly, the volume partition for - /dev/sda is "0" (or you can leave the property - empty).' + description: |- + partition is the partition in the volume that you want to mount. + If omitted, the default is to mount by volume name. + Examples: For volume /dev/sda1, you specify the partition as "1". + Similarly, the volume partition for /dev/sda is "0" (or you can leave the property empty). format: int32 type: integer readOnly: - description: 'readOnly value true will force the - readOnly setting in VolumeMounts. More info: - https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' + description: |- + readOnly value true will force the readOnly setting in VolumeMounts. + More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore type: boolean volumeID: - description: 'volumeID is unique ID of the persistent - disk resource in AWS (Amazon EBS volume). More - info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' + description: |- + volumeID is unique ID of the persistent disk resource in AWS (Amazon EBS volume). + More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore type: string required: - volumeID @@ -505,10 +512,10 @@ spec: the blob storage type: string fsType: - description: fsType is Filesystem type to mount. - Must be a filesystem type supported by the host - operating system. Ex. "ext4", "xfs", "ntfs". - Implicitly inferred to be "ext4" if unspecified. + description: |- + fsType is Filesystem type to mount. + Must be a filesystem type supported by the host operating system. + Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. type: string kind: description: 'kind expected values are Shared: @@ -518,9 +525,9 @@ spec: set). defaults to shared' type: string readOnly: - description: readOnly Defaults to false (read/write). - ReadOnly here will force the ReadOnly setting - in VolumeMounts. + description: |- + readOnly Defaults to false (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. type: boolean required: - diskName @@ -531,9 +538,9 @@ spec: mount on the host and bind mount to the pod. properties: readOnly: - description: readOnly defaults to false (read/write). - ReadOnly here will force the ReadOnly setting - in VolumeMounts. + description: |- + readOnly defaults to false (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. type: boolean secretName: description: secretName is the name of secret @@ -552,8 +559,9 @@ spec: the host that shares a pod's lifetime properties: monitors: - description: 'monitors is Required: Monitors is - a collection of Ceph monitors More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + description: |- + monitors is Required: Monitors is a collection of Ceph monitors + More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it items: type: string type: array @@ -563,67 +571,72 @@ spec: is /' type: string readOnly: - description: 'readOnly is Optional: Defaults to - false (read/write). ReadOnly here will force - the ReadOnly setting in VolumeMounts. More info: - https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + description: |- + readOnly is Optional: Defaults to false (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. + More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it type: boolean secretFile: - description: 'secretFile is Optional: SecretFile - is the path to key ring for User, default is - /etc/ceph/user.secret More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + description: |- + secretFile is Optional: SecretFile is the path to key ring for User, default is /etc/ceph/user.secret + More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it type: string secretRef: - description: 'secretRef is Optional: SecretRef - is reference to the authentication secret for - User, default is empty. More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + description: |- + secretRef is Optional: SecretRef is reference to the authentication secret for User, default is empty. + More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it properties: name: - description: 'Name of the referent. More info: - https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, - kind, uid?' + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? type: string type: object + x-kubernetes-map-type: atomic user: - description: 'user is optional: User is the rados - user name, default is admin More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + description: |- + user is optional: User is the rados user name, default is admin + More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it type: string required: - monitors type: object cinder: - description: 'cinder represents a cinder volume attached - and mounted on kubelets host machine. More info: - https://examples.k8s.io/mysql-cinder-pd/README.md' + description: |- + cinder represents a cinder volume attached and mounted on kubelets host machine. + More info: https://examples.k8s.io/mysql-cinder-pd/README.md properties: fsType: - description: 'fsType is the filesystem type to - mount. Must be a filesystem type supported by - the host operating system. Examples: "ext4", - "xfs", "ntfs". Implicitly inferred to be "ext4" - if unspecified. More info: https://examples.k8s.io/mysql-cinder-pd/README.md' + description: |- + fsType is the filesystem type to mount. + Must be a filesystem type supported by the host operating system. + Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + More info: https://examples.k8s.io/mysql-cinder-pd/README.md type: string readOnly: - description: 'readOnly defaults to false (read/write). - ReadOnly here will force the ReadOnly setting - in VolumeMounts. More info: https://examples.k8s.io/mysql-cinder-pd/README.md' + description: |- + readOnly defaults to false (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. + More info: https://examples.k8s.io/mysql-cinder-pd/README.md type: boolean secretRef: - description: 'secretRef is optional: points to - a secret object containing parameters used to - connect to OpenStack.' + description: |- + secretRef is optional: points to a secret object containing parameters used to connect + to OpenStack. properties: name: - description: 'Name of the referent. More info: - https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, - kind, uid?' + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? type: string type: object + x-kubernetes-map-type: atomic volumeID: - description: 'volumeID used to identify the volume - in cinder. More info: https://examples.k8s.io/mysql-cinder-pd/README.md' + description: |- + volumeID used to identify the volume in cinder. + More info: https://examples.k8s.io/mysql-cinder-pd/README.md type: string required: - volumeID @@ -633,31 +646,25 @@ spec: should populate this volume properties: defaultMode: - description: 'defaultMode is optional: mode bits - used to set permissions on created files by - default. Must be an octal value between 0000 - and 0777 or a decimal value between 0 and 511. - YAML accepts both octal and decimal values, - JSON requires decimal values for mode bits. - Defaults to 0644. Directories within the path - are not affected by this setting. This might - be in conflict with other options that affect - the file mode, like fsGroup, and the result - can be other mode bits set.' + description: |- + defaultMode is optional: mode bits used to set permissions on created files by default. + Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. + Defaults to 0644. + Directories within the path are not affected by this setting. + This might be in conflict with other options that affect the file + mode, like fsGroup, and the result can be other mode bits set. format: int32 type: integer items: - description: items if unspecified, each key-value - pair in the Data field of the referenced ConfigMap - will be projected into the volume as a file - whose name is the key and content is the value. - If specified, the listed keys will be projected - into the specified paths, and unlisted keys - will not be present. If a key is specified which - is not present in the ConfigMap, the volume - setup will error unless it is marked optional. - Paths must be relative and may not contain the - '..' path or start with '..'. + description: |- + items if unspecified, each key-value pair in the Data field of the referenced + ConfigMap will be projected into the volume as a file whose name is the + key and content is the value. If specified, the listed keys will be + projected into the specified paths, and unlisted keys will not be + present. If a key is specified which is not present in the ConfigMap, + the volume setup will error unless it is marked optional. Paths must be + relative and may not contain the '..' path or start with '..'. items: description: Maps a string key to a path within a volume. @@ -666,25 +673,21 @@ spec: description: key is the key to project. type: string mode: - description: 'mode is Optional: mode bits - used to set permissions on this file. - Must be an octal value between 0000 and - 0777 or a decimal value between 0 and - 511. YAML accepts both octal and decimal - values, JSON requires decimal values for - mode bits. If not specified, the volume - defaultMode will be used. This might be - in conflict with other options that affect - the file mode, like fsGroup, and the result - can be other mode bits set.' + description: |- + mode is Optional: mode bits used to set permissions on this file. + Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. + If not specified, the volume defaultMode will be used. + This might be in conflict with other options that affect the file + mode, like fsGroup, and the result can be other mode bits set. format: int32 type: integer path: - description: path is the relative path of - the file to map the key to. May not be - an absolute path. May not contain the - path element '..'. May not start with - the string '..'. + description: |- + path is the relative path of the file to map the key to. + May not be an absolute path. + May not contain the path element '..'. + May not start with the string '..'. type: string required: - key @@ -692,61 +695,60 @@ spec: type: object type: array name: - description: 'Name of the referent. More info: - https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, kind, - uid?' + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? type: string optional: description: optional specify whether the ConfigMap or its keys must be defined type: boolean type: object + x-kubernetes-map-type: atomic csi: description: csi (Container Storage Interface) represents ephemeral storage that is handled by certain external CSI drivers (Beta feature). properties: driver: - description: driver is the name of the CSI driver - that handles this volume. Consult with your - admin for the correct name as registered in - the cluster. + description: |- + driver is the name of the CSI driver that handles this volume. + Consult with your admin for the correct name as registered in the cluster. type: string fsType: - description: fsType to mount. Ex. "ext4", "xfs", - "ntfs". If not provided, the empty value is - passed to the associated CSI driver which will - determine the default filesystem to apply. + description: |- + fsType to mount. Ex. "ext4", "xfs", "ntfs". + If not provided, the empty value is passed to the associated CSI driver + which will determine the default filesystem to apply. type: string nodePublishSecretRef: - description: nodePublishSecretRef is a reference - to the secret object containing sensitive information - to pass to the CSI driver to complete the CSI + description: |- + nodePublishSecretRef is a reference to the secret object containing + sensitive information to pass to the CSI driver to complete the CSI NodePublishVolume and NodeUnpublishVolume calls. - This field is optional, and may be empty if - no secret is required. If the secret object - contains more than one secret, all secret references - are passed. + This field is optional, and may be empty if no secret is required. If the + secret object contains more than one secret, all secret references are passed. properties: name: - description: 'Name of the referent. More info: - https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, - kind, uid?' + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? type: string type: object + x-kubernetes-map-type: atomic readOnly: - description: readOnly specifies a read-only configuration - for the volume. Defaults to false (read/write). + description: |- + readOnly specifies a read-only configuration for the volume. + Defaults to false (read/write). type: boolean volumeAttributes: additionalProperties: type: string - description: volumeAttributes stores driver-specific - properties that are passed to the CSI driver. - Consult your driver's documentation for supported - values. + description: |- + volumeAttributes stores driver-specific properties that are passed to the CSI + driver. Consult your driver's documentation for supported values. type: object required: - driver @@ -756,18 +758,15 @@ spec: the pod that should populate this volume properties: defaultMode: - description: 'Optional: mode bits to use on created - files by default. Must be a Optional: mode bits - used to set permissions on created files by - default. Must be an octal value between 0000 - and 0777 or a decimal value between 0 and 511. - YAML accepts both octal and decimal values, - JSON requires decimal values for mode bits. - Defaults to 0644. Directories within the path - are not affected by this setting. This might - be in conflict with other options that affect - the file mode, like fsGroup, and the result - can be other mode bits set.' + description: |- + Optional: mode bits to use on created files by default. Must be a + Optional: mode bits used to set permissions on created files by default. + Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. + Defaults to 0644. + Directories within the path are not affected by this setting. + This might be in conflict with other options that affect the file + mode, like fsGroup, and the result can be other mode bits set. format: int32 type: integer items: @@ -795,18 +794,15 @@ spec: required: - fieldPath type: object + x-kubernetes-map-type: atomic mode: - description: 'Optional: mode bits used to - set permissions on this file, must be - an octal value between 0000 and 0777 or - a decimal value between 0 and 511. YAML - accepts both octal and decimal values, - JSON requires decimal values for mode - bits. If not specified, the volume defaultMode - will be used. This might be in conflict - with other options that affect the file - mode, like fsGroup, and the result can - be other mode bits set.' + description: |- + Optional: mode bits used to set permissions on this file, must be an octal value + between 0000 and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. + If not specified, the volume defaultMode will be used. + This might be in conflict with other options that affect the file + mode, like fsGroup, and the result can be other mode bits set. format: int32 type: integer path: @@ -818,10 +814,9 @@ spec: with ''..''' type: string resourceFieldRef: - description: 'Selects a resource of the - container: only resources limits and requests - (limits.cpu, limits.memory, requests.cpu - and requests.memory) are currently supported.' + description: |- + Selects a resource of the container: only resources limits and requests + (limits.cpu, limits.memory, requests.cpu and requests.memory) are currently supported. properties: containerName: description: 'Container name: required @@ -843,127 +838,131 @@ spec: required: - resource type: object + x-kubernetes-map-type: atomic required: - path type: object type: array type: object emptyDir: - description: 'emptyDir represents a temporary directory - that shares a pod''s lifetime. More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir' + description: |- + emptyDir represents a temporary directory that shares a pod's lifetime. + More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir properties: medium: - description: 'medium represents what type of storage - medium should back this directory. The default - is "" which means to use the node''s default - medium. Must be an empty string (default) or - Memory. More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir' + description: |- + medium represents what type of storage medium should back this directory. + The default is "" which means to use the node's default medium. + Must be an empty string (default) or Memory. + More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir type: string sizeLimit: anyOf: - type: integer - type: string - description: 'sizeLimit is the total amount of - local storage required for this EmptyDir volume. - The size limit is also applicable for memory - medium. The maximum usage on memory medium EmptyDir - would be the minimum value between the SizeLimit - specified here and the sum of memory limits - of all containers in a pod. The default is nil - which means that the limit is undefined. More - info: http://kubernetes.io/docs/user-guide/volumes#emptydir' + description: |- + sizeLimit is the total amount of local storage required for this EmptyDir volume. + The size limit is also applicable for memory medium. + The maximum usage on memory medium EmptyDir would be the minimum value between + the SizeLimit specified here and the sum of memory limits of all containers in a pod. + The default is nil which means that the limit is undefined. + More info: http://kubernetes.io/docs/user-guide/volumes#emptydir pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true type: object ephemeral: - description: "ephemeral represents a volume that is - handled by a cluster storage driver. The volume's - lifecycle is tied to the pod that defines it - it - will be created before the pod starts, and deleted - when the pod is removed. \n Use this if: a) the - volume is only needed while the pod runs, b) features - of normal volumes like restoring from snapshot or - capacity tracking are needed, c) the storage - driver is specified through a storage class, and - d) the storage driver supports dynamic volume provisioning - through a PersistentVolumeClaim (see EphemeralVolumeSource - for more information on the connection between - this volume type and PersistentVolumeClaim). - \n Use PersistentVolumeClaim or one of the vendor-specific - APIs for volumes that persist for longer than the - lifecycle of an individual pod. \n Use CSI for light-weight - local ephemeral volumes if the CSI driver is meant - to be used that way - see the documentation of the - driver for more information. \n A pod can use both - types of ephemeral volumes and persistent volumes - at the same time." + description: |- + ephemeral represents a volume that is handled by a cluster storage driver. + The volume's lifecycle is tied to the pod that defines it - it will be created before the pod starts, + and deleted when the pod is removed. + + + Use this if: + a) the volume is only needed while the pod runs, + b) features of normal volumes like restoring from snapshot or capacity + tracking are needed, + c) the storage driver is specified through a storage class, and + d) the storage driver supports dynamic volume provisioning through + a PersistentVolumeClaim (see EphemeralVolumeSource for more + information on the connection between this volume type + and PersistentVolumeClaim). + + + Use PersistentVolumeClaim or one of the vendor-specific + APIs for volumes that persist for longer than the lifecycle + of an individual pod. + + + Use CSI for light-weight local ephemeral volumes if the CSI driver is meant to + be used that way - see the documentation of the driver for + more information. + + + A pod can use both types of ephemeral volumes and + persistent volumes at the same time. properties: volumeClaimTemplate: - description: "Will be used to create a stand-alone - PVC to provision the volume. The pod in which - this EphemeralVolumeSource is embedded will - be the owner of the PVC, i.e. the PVC will be - deleted together with the pod. The name of - the PVC will be `-` where - `` is the name from the `PodSpec.Volumes` - array entry. Pod validation will reject the - pod if the concatenated name is not valid for - a PVC (for example, too long). \n An existing - PVC with that name that is not owned by the - pod will *not* be used for the pod to avoid - using an unrelated volume by mistake. Starting - the pod is then blocked until the unrelated - PVC is removed. If such a pre-created PVC is - meant to be used by the pod, the PVC has to - updated with an owner reference to the pod once - the pod exists. Normally this should not be - necessary, but it may be useful when manually - reconstructing a broken cluster. \n This field - is read-only and no changes will be made by - Kubernetes to the PVC after it has been created. - \n Required, must not be nil." + description: |- + Will be used to create a stand-alone PVC to provision the volume. + The pod in which this EphemeralVolumeSource is embedded will be the + owner of the PVC, i.e. the PVC will be deleted together with the + pod. The name of the PVC will be `-` where + `` is the name from the `PodSpec.Volumes` array + entry. Pod validation will reject the pod if the concatenated name + is not valid for a PVC (for example, too long). + + + An existing PVC with that name that is not owned by the pod + will *not* be used for the pod to avoid using an unrelated + volume by mistake. Starting the pod is then blocked until + the unrelated PVC is removed. If such a pre-created PVC is + meant to be used by the pod, the PVC has to updated with an + owner reference to the pod once the pod exists. Normally + this should not be necessary, but it may be useful when + manually reconstructing a broken cluster. + + + This field is read-only and no changes will be made by Kubernetes + to the PVC after it has been created. + + + Required, must not be nil. properties: metadata: - description: May contain labels and annotations - that will be copied into the PVC when creating - it. No other fields are allowed and will - be rejected during validation. + description: |- + May contain labels and annotations that will be copied into the PVC + when creating it. No other fields are allowed and will be rejected during + validation. type: object spec: - description: The specification for the PersistentVolumeClaim. - The entire content is copied unchanged into - the PVC that gets created from this template. - The same fields as in a PersistentVolumeClaim + description: |- + The specification for the PersistentVolumeClaim. The entire content is + copied unchanged into the PVC that gets created from this + template. The same fields as in a PersistentVolumeClaim are also valid here. properties: accessModes: - description: 'accessModes contains the - desired access modes the volume should - have. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1' + description: |- + accessModes contains the desired access modes the volume should have. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1 items: type: string type: array dataSource: - description: 'dataSource field can be - used to specify either: * An existing - VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) + description: |- + dataSource field can be used to specify either: + * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) * An existing PVC (PersistentVolumeClaim) - If the provisioner or an external controller - can support the specified data source, - it will create a new volume based on - the contents of the specified data source. - If the AnyVolumeDataSource feature gate - is enabled, this field will always have - the same contents as the DataSourceRef - field.' + If the provisioner or an external controller can support the specified data source, + it will create a new volume based on the contents of the specified data source. + If the AnyVolumeDataSource feature gate is enabled, this field will always have + the same contents as the DataSourceRef field. properties: apiGroup: - description: APIGroup is the group - for the resource being referenced. - If APIGroup is not specified, the - specified Kind must be in the core - API group. For any other third-party - types, APIGroup is required. + description: |- + APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in the core API group. + For any other third-party types, APIGroup is required. type: string kind: description: Kind is the type of resource @@ -977,44 +976,32 @@ spec: - kind - name type: object + x-kubernetes-map-type: atomic dataSourceRef: - description: 'dataSourceRef specifies - the object from which to populate the - volume with data, if a non-empty volume - is desired. This may be any local object - from a non-empty API group (non core - object) or a PersistentVolumeClaim object. - When this field is specified, volume - binding will only succeed if the type - of the specified object matches some - installed volume populator or dynamic - provisioner. This field will replace - the functionality of the DataSource - field and as such if both fields are - non-empty, they must have the same value. - For backwards compatibility, both fields - (DataSource and DataSourceRef) will - be set to the same value automatically - if one of them is empty and the other - is non-empty. There are two important - differences between DataSource and DataSourceRef: - * While DataSource only allows two specific - types of objects, DataSourceRef allows - any non-core object, as well as PersistentVolumeClaim - objects. * While DataSource ignores - disallowed values (dropping them), DataSourceRef preserves - all values, and generates an error if - a disallowed value is specified. (Beta) - Using this field requires the AnyVolumeDataSource - feature gate to be enabled.' + description: |- + dataSourceRef specifies the object from which to populate the volume with data, if a non-empty + volume is desired. This may be any local object from a non-empty API group (non + core object) or a PersistentVolumeClaim object. + When this field is specified, volume binding will only succeed if the type of + the specified object matches some installed volume populator or dynamic + provisioner. + This field will replace the functionality of the DataSource field and as such + if both fields are non-empty, they must have the same value. For backwards + compatibility, both fields (DataSource and DataSourceRef) will be set to the same + value automatically if one of them is empty and the other is non-empty. + There are two important differences between DataSource and DataSourceRef: + * While DataSource only allows two specific types of objects, DataSourceRef + allows any non-core object, as well as PersistentVolumeClaim objects. + * While DataSource ignores disallowed values (dropping them), DataSourceRef + preserves all values, and generates an error if a disallowed value is + specified. + (Beta) Using this field requires the AnyVolumeDataSource feature gate to be enabled. properties: apiGroup: - description: APIGroup is the group - for the resource being referenced. - If APIGroup is not specified, the - specified Kind must be in the core - API group. For any other third-party - types, APIGroup is required. + description: |- + APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in the core API group. + For any other third-party types, APIGroup is required. type: string kind: description: Kind is the type of resource @@ -1028,16 +1015,14 @@ spec: - kind - name type: object + x-kubernetes-map-type: atomic resources: - description: 'resources represents the - minimum resources the volume should - have. If RecoverVolumeExpansionFailure - feature is enabled users are allowed - to specify resource requirements that - are lower than previous value but must - still be higher than capacity recorded - in the status field of the claim. More - info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources' + description: |- + resources represents the minimum resources the volume should have. + If RecoverVolumeExpansionFailure feature is enabled users are allowed to specify resource requirements + that are lower than previous value but must still be higher than capacity recorded in the + status field of the claim. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources properties: limits: additionalProperties: @@ -1046,9 +1031,9 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: 'Limits describes the - maximum amount of compute resources - allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object requests: additionalProperties: @@ -1057,13 +1042,11 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: 'Requests describes the - minimum amount of compute resources - required. If Requests is omitted - for a container, it defaults to - Limits if that is explicitly specified, - otherwise to an implementation-defined - value. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object type: object selector: @@ -1075,10 +1058,9 @@ spec: list of label selector requirements. The requirements are ANDed. items: - description: A label selector requirement - is a selector that contains values, - a key, and an operator that relates - the key and values. + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. properties: key: description: key is the label @@ -1086,21 +1068,15 @@ spec: to. type: string operator: - description: operator represents - a key's relationship to a - set of values. Valid operators - are In, NotIn, Exists and - DoesNotExist. + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. type: string values: - description: values is an array - of string values. If the operator - is In or NotIn, the values - array must be non-empty. If - the operator is Exists or - DoesNotExist, the values array - must be empty. This array - is replaced during a strategic + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic merge patch. items: type: string @@ -1113,26 +1089,22 @@ spec: matchLabels: additionalProperties: type: string - description: matchLabels is a map - of {key,value} pairs. A single {key,value} - in the matchLabels map is equivalent - to an element of matchExpressions, - whose key field is "key", the operator - is "In", and the values array contains - only "value". The requirements are - ANDed. + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. type: object type: object + x-kubernetes-map-type: atomic storageClassName: - description: 'storageClassName is the - name of the StorageClass required by - the claim. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1' + description: |- + storageClassName is the name of the StorageClass required by the claim. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1 type: string volumeMode: - description: volumeMode defines what type - of volume is required by the claim. - Value of Filesystem is implied when - not included in claim spec. + description: |- + volumeMode defines what type of volume is required by the claim. + Value of Filesystem is implied when not included in claim spec. type: string volumeName: description: volumeName is the binding @@ -1150,21 +1122,20 @@ spec: then exposed to the pod. properties: fsType: - description: 'fsType is the filesystem type to - mount. Must be a filesystem type supported by - the host operating system. Ex. "ext4", "xfs", - "ntfs". Implicitly inferred to be "ext4" if - unspecified. TODO: how do we prevent errors - in the filesystem from compromising the machine' + description: |- + fsType is the filesystem type to mount. + Must be a filesystem type supported by the host operating system. + Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + TODO: how do we prevent errors in the filesystem from compromising the machine type: string lun: description: 'lun is Optional: FC target lun number' format: int32 type: integer readOnly: - description: 'readOnly is Optional: Defaults to - false (read/write). ReadOnly here will force - the ReadOnly setting in VolumeMounts.' + description: |- + readOnly is Optional: Defaults to false (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. type: boolean targetWWNs: description: 'targetWWNs is Optional: FC target @@ -1173,29 +1144,27 @@ spec: type: string type: array wwids: - description: 'wwids Optional: FC volume world - wide identifiers (wwids) Either wwids or combination - of targetWWNs and lun must be set, but not both - simultaneously.' + description: |- + wwids Optional: FC volume world wide identifiers (wwids) + Either wwids or combination of targetWWNs and lun must be set, but not both simultaneously. items: type: string type: array type: object flexVolume: - description: flexVolume represents a generic volume - resource that is provisioned/attached using an exec - based plugin. + description: |- + flexVolume represents a generic volume resource that is + provisioned/attached using an exec based plugin. properties: driver: description: driver is the name of the driver to use for this volume. type: string fsType: - description: fsType is the filesystem type to - mount. Must be a filesystem type supported by - the host operating system. Ex. "ext4", "xfs", - "ntfs". The default filesystem depends on FlexVolume - script. + description: |- + fsType is the filesystem type to mount. + Must be a filesystem type supported by the host operating system. + Ex. "ext4", "xfs", "ntfs". The default filesystem depends on FlexVolume script. type: string options: additionalProperties: @@ -1204,26 +1173,26 @@ spec: holds extra command options if any.' type: object readOnly: - description: 'readOnly is Optional: defaults to - false (read/write). ReadOnly here will force - the ReadOnly setting in VolumeMounts.' + description: |- + readOnly is Optional: defaults to false (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. type: boolean secretRef: - description: 'secretRef is Optional: secretRef - is reference to the secret object containing - sensitive information to pass to the plugin - scripts. This may be empty if no secret object - is specified. If the secret object contains - more than one secret, all secrets are passed - to the plugin scripts.' + description: |- + secretRef is Optional: secretRef is reference to the secret object containing + sensitive information to pass to the plugin scripts. This may be + empty if no secret object is specified. If the secret object + contains more than one secret, all secrets are passed to the plugin + scripts. properties: name: - description: 'Name of the referent. More info: - https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, - kind, uid?' + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? type: string type: object + x-kubernetes-map-type: atomic required: - driver type: object @@ -1233,9 +1202,9 @@ spec: Flocker control service being running properties: datasetName: - description: datasetName is Name of the dataset - stored as metadata -> name on the dataset for - Flocker should be considered as deprecated + description: |- + datasetName is Name of the dataset stored as metadata -> name on the dataset for Flocker + should be considered as deprecated type: string datasetUUID: description: datasetUUID is the UUID of the dataset. @@ -1243,57 +1212,54 @@ spec: type: string type: object gcePersistentDisk: - description: 'gcePersistentDisk represents a GCE Disk - resource that is attached to a kubelet''s host machine - and then exposed to the pod. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + description: |- + gcePersistentDisk represents a GCE Disk resource that is attached to a + kubelet's host machine and then exposed to the pod. + More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk properties: fsType: - description: 'fsType is filesystem type of the - volume that you want to mount. Tip: Ensure that - the filesystem type is supported by the host - operating system. Examples: "ext4", "xfs", "ntfs". - Implicitly inferred to be "ext4" if unspecified. + description: |- + fsType is filesystem type of the volume that you want to mount. + Tip: Ensure that the filesystem type is supported by the host operating system. + Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk - TODO: how do we prevent errors in the filesystem - from compromising the machine' + TODO: how do we prevent errors in the filesystem from compromising the machine type: string partition: - description: 'partition is the partition in the - volume that you want to mount. If omitted, the - default is to mount by volume name. Examples: - For volume /dev/sda1, you specify the partition - as "1". Similarly, the volume partition for - /dev/sda is "0" (or you can leave the property - empty). More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + description: |- + partition is the partition in the volume that you want to mount. + If omitted, the default is to mount by volume name. + Examples: For volume /dev/sda1, you specify the partition as "1". + Similarly, the volume partition for /dev/sda is "0" (or you can leave the property empty). + More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk format: int32 type: integer pdName: - description: 'pdName is unique name of the PD - resource in GCE. Used to identify the disk in - GCE. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + description: |- + pdName is unique name of the PD resource in GCE. Used to identify the disk in GCE. + More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk type: string readOnly: - description: 'readOnly here will force the ReadOnly - setting in VolumeMounts. Defaults to false. - More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + description: |- + readOnly here will force the ReadOnly setting in VolumeMounts. + Defaults to false. + More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk type: boolean required: - pdName type: object gitRepo: - description: 'gitRepo represents a git repository - at a particular revision. DEPRECATED: GitRepo is - deprecated. To provision a container with a git - repo, mount an EmptyDir into an InitContainer that - clones the repo using git, then mount the EmptyDir - into the Pod''s container.' + description: |- + gitRepo represents a git repository at a particular revision. + DEPRECATED: GitRepo is deprecated. To provision a container with a git repo, mount an + EmptyDir into an InitContainer that clones the repo using git, then mount the EmptyDir + into the Pod's container. properties: directory: - description: directory is the target directory - name. Must not contain or start with '..'. If - '.' is supplied, the volume directory will be - the git repository. Otherwise, if specified, - the volume will contain the git repository in + description: |- + directory is the target directory name. + Must not contain or start with '..'. If '.' is supplied, the volume directory will be the + git repository. Otherwise, if specified, the volume will contain the git repository in the subdirectory with the given name. type: string repository: @@ -1307,54 +1273,61 @@ spec: - repository type: object glusterfs: - description: 'glusterfs represents a Glusterfs mount - on the host that shares a pod''s lifetime. More - info: https://examples.k8s.io/volumes/glusterfs/README.md' + description: |- + glusterfs represents a Glusterfs mount on the host that shares a pod's lifetime. + More info: https://examples.k8s.io/volumes/glusterfs/README.md properties: endpoints: - description: 'endpoints is the endpoint name that - details Glusterfs topology. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod' + description: |- + endpoints is the endpoint name that details Glusterfs topology. + More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod type: string path: - description: 'path is the Glusterfs volume path. - More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod' + description: |- + path is the Glusterfs volume path. + More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod type: string readOnly: - description: 'readOnly here will force the Glusterfs - volume to be mounted with read-only permissions. - Defaults to false. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod' + description: |- + readOnly here will force the Glusterfs volume to be mounted with read-only permissions. + Defaults to false. + More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod type: boolean required: - endpoints - path type: object hostPath: - description: 'hostPath represents a pre-existing file - or directory on the host machine that is directly - exposed to the container. This is generally used - for system agents or other privileged things that - are allowed to see the host machine. Most containers - will NOT need this. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath - --- TODO(jonesdl) We need to restrict who can use - host directory mounts and who can/can not mount - host directories as read/write.' + description: |- + hostPath represents a pre-existing file or directory on the host + machine that is directly exposed to the container. This is generally + used for system agents or other privileged things that are allowed + to see the host machine. Most containers will NOT need this. + More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath + --- + TODO(jonesdl) We need to restrict who can use host directory mounts and who can/can not + mount host directories as read/write. properties: path: - description: 'path of the directory on the host. - If the path is a symlink, it will follow the - link to the real path. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath' + description: |- + path of the directory on the host. + If the path is a symlink, it will follow the link to the real path. + More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath type: string type: - description: 'type for HostPath Volume Defaults - to "" More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath' + description: |- + type for HostPath Volume + Defaults to "" + More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath type: string required: - path type: object iscsi: - description: 'iscsi represents an ISCSI Disk resource - that is attached to a kubelet''s host machine and - then exposed to the pod. More info: https://examples.k8s.io/volumes/iscsi/README.md' + description: |- + iscsi represents an ISCSI Disk resource that is attached to a + kubelet's host machine and then exposed to the pod. + More info: https://examples.k8s.io/volumes/iscsi/README.md properties: chapAuthDiscovery: description: chapAuthDiscovery defines whether @@ -1365,63 +1338,60 @@ spec: iSCSI Session CHAP authentication type: boolean fsType: - description: 'fsType is the filesystem type of - the volume that you want to mount. Tip: Ensure - that the filesystem type is supported by the - host operating system. Examples: "ext4", "xfs", - "ntfs". Implicitly inferred to be "ext4" if - unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#iscsi - TODO: how do we prevent errors in the filesystem - from compromising the machine' + description: |- + fsType is the filesystem type of the volume that you want to mount. + Tip: Ensure that the filesystem type is supported by the host operating system. + Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + More info: https://kubernetes.io/docs/concepts/storage/volumes#iscsi + TODO: how do we prevent errors in the filesystem from compromising the machine type: string initiatorName: - description: initiatorName is the custom iSCSI - Initiator Name. If initiatorName is specified - with iscsiInterface simultaneously, new iSCSI - interface : will - be created for the connection. + description: |- + initiatorName is the custom iSCSI Initiator Name. + If initiatorName is specified with iscsiInterface simultaneously, new iSCSI interface + : will be created for the connection. type: string iqn: description: iqn is the target iSCSI Qualified Name. type: string iscsiInterface: - description: iscsiInterface is the interface Name - that uses an iSCSI transport. Defaults to 'default' - (tcp). + description: |- + iscsiInterface is the interface Name that uses an iSCSI transport. + Defaults to 'default' (tcp). type: string lun: description: lun represents iSCSI Target Lun number. format: int32 type: integer portals: - description: portals is the iSCSI Target Portal - List. The portal is either an IP or ip_addr:port - if the port is other than default (typically - TCP ports 860 and 3260). + description: |- + portals is the iSCSI Target Portal List. The portal is either an IP or ip_addr:port if the port + is other than default (typically TCP ports 860 and 3260). items: type: string type: array readOnly: - description: readOnly here will force the ReadOnly - setting in VolumeMounts. Defaults to false. + description: |- + readOnly here will force the ReadOnly setting in VolumeMounts. + Defaults to false. type: boolean secretRef: description: secretRef is the CHAP Secret for iSCSI target and initiator authentication properties: name: - description: 'Name of the referent. More info: - https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, - kind, uid?' + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? type: string type: object + x-kubernetes-map-type: atomic targetPortal: - description: targetPortal is iSCSI Target Portal. - The Portal is either an IP or ip_addr:port if - the port is other than default (typically TCP - ports 860 and 3260). + description: |- + targetPortal is iSCSI Target Portal. The Portal is either an IP or ip_addr:port if the port + is other than default (typically TCP ports 860 and 3260). type: string required: - iqn @@ -1429,43 +1399,51 @@ spec: - targetPortal type: object name: - description: 'name of the volume. Must be a DNS_LABEL - and unique within the pod. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + description: |- + name of the volume. + Must be a DNS_LABEL and unique within the pod. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string nfs: - description: 'nfs represents an NFS mount on the host - that shares a pod''s lifetime More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' + description: |- + nfs represents an NFS mount on the host that shares a pod's lifetime + More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs properties: path: - description: 'path that is exported by the NFS - server. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' + description: |- + path that is exported by the NFS server. + More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs type: string readOnly: - description: 'readOnly here will force the NFS - export to be mounted with read-only permissions. - Defaults to false. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' + description: |- + readOnly here will force the NFS export to be mounted with read-only permissions. + Defaults to false. + More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs type: boolean server: - description: 'server is the hostname or IP address - of the NFS server. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' + description: |- + server is the hostname or IP address of the NFS server. + More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs type: string required: - path - server type: object persistentVolumeClaim: - description: 'persistentVolumeClaimVolumeSource represents - a reference to a PersistentVolumeClaim in the same - namespace. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims' + description: |- + persistentVolumeClaimVolumeSource represents a reference to a + PersistentVolumeClaim in the same namespace. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims properties: claimName: - description: 'claimName is the name of a PersistentVolumeClaim - in the same namespace as the pod using this - volume. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims' + description: |- + claimName is the name of a PersistentVolumeClaim in the same namespace as the pod using this volume. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims type: string readOnly: - description: readOnly Will force the ReadOnly - setting in VolumeMounts. Default false. + description: |- + readOnly Will force the ReadOnly setting in VolumeMounts. + Default false. type: boolean required: - claimName @@ -1476,11 +1454,10 @@ spec: host machine properties: fsType: - description: fsType is the filesystem type to - mount. Must be a filesystem type supported by - the host operating system. Ex. "ext4", "xfs", - "ntfs". Implicitly inferred to be "ext4" if - unspecified. + description: |- + fsType is the filesystem type to mount. + Must be a filesystem type supported by the host operating system. + Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. type: string pdID: description: pdID is the ID that identifies Photon @@ -1494,15 +1471,15 @@ spec: volume attached and mounted on kubelets host machine properties: fsType: - description: fSType represents the filesystem - type to mount Must be a filesystem type supported - by the host operating system. Ex. "ext4", "xfs". - Implicitly inferred to be "ext4" if unspecified. + description: |- + fSType represents the filesystem type to mount + Must be a filesystem type supported by the host operating system. + Ex. "ext4", "xfs". Implicitly inferred to be "ext4" if unspecified. type: string readOnly: - description: readOnly defaults to false (read/write). - ReadOnly here will force the ReadOnly setting - in VolumeMounts. + description: |- + readOnly defaults to false (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. type: boolean volumeID: description: volumeID uniquely identifies a Portworx @@ -1516,16 +1493,13 @@ spec: secrets, configmaps, and downward API properties: defaultMode: - description: defaultMode are the mode bits used - to set permissions on created files by default. - Must be an octal value between 0000 and 0777 - or a decimal value between 0 and 511. YAML accepts - both octal and decimal values, JSON requires - decimal values for mode bits. Directories within - the path are not affected by this setting. This - might be in conflict with other options that - affect the file mode, like fsGroup, and the - result can be other mode bits set. + description: |- + defaultMode are the mode bits used to set permissions on created files by default. + Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. + Directories within the path are not affected by this setting. + This might be in conflict with other options that affect the file + mode, like fsGroup, and the result can be other mode bits set. format: int32 type: integer sources: @@ -1539,20 +1513,14 @@ spec: the configMap data to project properties: items: - description: items if unspecified, each - key-value pair in the Data field of - the referenced ConfigMap will be projected - into the volume as a file whose name - is the key and content is the value. - If specified, the listed keys will - be projected into the specified paths, - and unlisted keys will not be present. - If a key is specified which is not - present in the ConfigMap, the volume - setup will error unless it is marked - optional. Paths must be relative and - may not contain the '..' path or start - with '..'. + description: |- + items if unspecified, each key-value pair in the Data field of the referenced + ConfigMap will be projected into the volume as a file whose name is the + key and content is the value. If specified, the listed keys will be + projected into the specified paths, and unlisted keys will not be + present. If a key is specified which is not present in the ConfigMap, + the volume setup will error unless it is marked optional. Paths must be + relative and may not contain the '..' path or start with '..'. items: description: Maps a string key to a path within a volume. @@ -1562,30 +1530,21 @@ spec: project. type: string mode: - description: 'mode is Optional: - mode bits used to set permissions - on this file. Must be an octal - value between 0000 and 0777 - or a decimal value between 0 - and 511. YAML accepts both octal - and decimal values, JSON requires - decimal values for mode bits. - If not specified, the volume - defaultMode will be used. This - might be in conflict with other - options that affect the file - mode, like fsGroup, and the - result can be other mode bits - set.' + description: |- + mode is Optional: mode bits used to set permissions on this file. + Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. + If not specified, the volume defaultMode will be used. + This might be in conflict with other options that affect the file + mode, like fsGroup, and the result can be other mode bits set. format: int32 type: integer path: - description: path is the relative - path of the file to map the - key to. May not be an absolute - path. May not contain the path - element '..'. May not start - with the string '..'. + description: |- + path is the relative path of the file to map the key to. + May not be an absolute path. + May not contain the path element '..'. + May not start with the string '..'. type: string required: - key @@ -1593,10 +1552,10 @@ spec: type: object type: array name: - description: 'Name of the referent. + description: |- + Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, - kind, uid?' + TODO: Add other useful fields. apiVersion, kind, uid? type: string optional: description: optional specify whether @@ -1604,6 +1563,7 @@ spec: defined type: boolean type: object + x-kubernetes-map-type: atomic downwardAPI: description: downwardAPI information about the downwardAPI data to project @@ -1636,21 +1596,15 @@ spec: required: - fieldPath type: object + x-kubernetes-map-type: atomic mode: - description: 'Optional: mode bits - used to set permissions on this - file, must be an octal value - between 0000 and 0777 or a decimal - value between 0 and 511. YAML - accepts both octal and decimal - values, JSON requires decimal - values for mode bits. If not - specified, the volume defaultMode - will be used. This might be - in conflict with other options - that affect the file mode, like - fsGroup, and the result can - be other mode bits set.' + description: |- + Optional: mode bits used to set permissions on this file, must be an octal value + between 0000 and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. + If not specified, the volume defaultMode will be used. + This might be in conflict with other options that affect the file + mode, like fsGroup, and the result can be other mode bits set. format: int32 type: integer path: @@ -1663,12 +1617,9 @@ spec: not start with ''..''' type: string resourceFieldRef: - description: 'Selects a resource - of the container: only resources - limits and requests (limits.cpu, - limits.memory, requests.cpu - and requests.memory) are currently - supported.' + description: |- + Selects a resource of the container: only resources limits and requests + (limits.cpu, limits.memory, requests.cpu and requests.memory) are currently supported. properties: containerName: description: 'Container name: @@ -1691,6 +1642,7 @@ spec: required: - resource type: object + x-kubernetes-map-type: atomic required: - path type: object @@ -1701,20 +1653,14 @@ spec: secret data to project properties: items: - description: items if unspecified, each - key-value pair in the Data field of - the referenced Secret will be projected - into the volume as a file whose name - is the key and content is the value. - If specified, the listed keys will - be projected into the specified paths, - and unlisted keys will not be present. - If a key is specified which is not - present in the Secret, the volume - setup will error unless it is marked - optional. Paths must be relative and - may not contain the '..' path or start - with '..'. + description: |- + items if unspecified, each key-value pair in the Data field of the referenced + Secret will be projected into the volume as a file whose name is the + key and content is the value. If specified, the listed keys will be + projected into the specified paths, and unlisted keys will not be + present. If a key is specified which is not present in the Secret, + the volume setup will error unless it is marked optional. Paths must be + relative and may not contain the '..' path or start with '..'. items: description: Maps a string key to a path within a volume. @@ -1724,30 +1670,21 @@ spec: project. type: string mode: - description: 'mode is Optional: - mode bits used to set permissions - on this file. Must be an octal - value between 0000 and 0777 - or a decimal value between 0 - and 511. YAML accepts both octal - and decimal values, JSON requires - decimal values for mode bits. - If not specified, the volume - defaultMode will be used. This - might be in conflict with other - options that affect the file - mode, like fsGroup, and the - result can be other mode bits - set.' + description: |- + mode is Optional: mode bits used to set permissions on this file. + Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. + If not specified, the volume defaultMode will be used. + This might be in conflict with other options that affect the file + mode, like fsGroup, and the result can be other mode bits set. format: int32 type: integer path: - description: path is the relative - path of the file to map the - key to. May not be an absolute - path. May not contain the path - element '..'. May not start - with the string '..'. + description: |- + path is the relative path of the file to map the key to. + May not be an absolute path. + May not contain the path element '..'. + May not start with the string '..'. type: string required: - key @@ -1755,10 +1692,10 @@ spec: type: object type: array name: - description: 'Name of the referent. + description: |- + Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, - kind, uid?' + TODO: Add other useful fields. apiVersion, kind, uid? type: string optional: description: optional field specify @@ -1766,38 +1703,33 @@ spec: be defined type: boolean type: object + x-kubernetes-map-type: atomic serviceAccountToken: description: serviceAccountToken is information about the serviceAccountToken data to project properties: audience: - description: audience is the intended - audience of the token. A recipient - of a token must identify itself with - an identifier specified in the audience - of the token, and otherwise should - reject the token. The audience defaults - to the identifier of the apiserver. + description: |- + audience is the intended audience of the token. A recipient of a token + must identify itself with an identifier specified in the audience of the + token, and otherwise should reject the token. The audience defaults to the + identifier of the apiserver. type: string expirationSeconds: - description: expirationSeconds is the - requested duration of validity of - the service account token. As the - token approaches expiration, the kubelet - volume plugin will proactively rotate - the service account token. The kubelet - will start trying to rotate the token - if the token is older than 80 percent - of its time to live or if the token - is older than 24 hours.Defaults to - 1 hour and must be at least 10 minutes. + description: |- + expirationSeconds is the requested duration of validity of the service + account token. As the token approaches expiration, the kubelet volume + plugin will proactively rotate the service account token. The kubelet will + start trying to rotate the token if the token is older than 80 percent of + its time to live or if the token is older than 24 hours.Defaults to 1 hour + and must be at least 10 minutes. format: int64 type: integer path: - description: path is the path relative - to the mount point of the file to - project the token into. + description: |- + path is the path relative to the mount point of the file to project the + token into. type: string required: - path @@ -1810,29 +1742,30 @@ spec: the host that shares a pod's lifetime properties: group: - description: group to map volume access to Default - is no group + description: |- + group to map volume access to + Default is no group type: string readOnly: - description: readOnly here will force the Quobyte - volume to be mounted with read-only permissions. + description: |- + readOnly here will force the Quobyte volume to be mounted with read-only permissions. Defaults to false. type: boolean registry: - description: registry represents a single or multiple - Quobyte Registry services specified as a string - as host:port pair (multiple entries are separated - with commas) which acts as the central registry - for volumes + description: |- + registry represents a single or multiple Quobyte Registry services + specified as a string as host:port pair (multiple entries are separated with commas) + which acts as the central registry for volumes type: string tenant: - description: tenant owning the given Quobyte volume - in the Backend Used with dynamically provisioned - Quobyte volumes, value is set by the plugin + description: |- + tenant owning the given Quobyte volume in the Backend + Used with dynamically provisioned Quobyte volumes, value is set by the plugin type: string user: - description: user to map volume access to Defaults - to serivceaccount user + description: |- + user to map volume access to + Defaults to serivceaccount user type: string volume: description: volume is a string that references @@ -1843,59 +1776,68 @@ spec: - volume type: object rbd: - description: 'rbd represents a Rados Block Device - mount on the host that shares a pod''s lifetime. - More info: https://examples.k8s.io/volumes/rbd/README.md' + description: |- + rbd represents a Rados Block Device mount on the host that shares a pod's lifetime. + More info: https://examples.k8s.io/volumes/rbd/README.md properties: fsType: - description: 'fsType is the filesystem type of - the volume that you want to mount. Tip: Ensure - that the filesystem type is supported by the - host operating system. Examples: "ext4", "xfs", - "ntfs". Implicitly inferred to be "ext4" if - unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#rbd - TODO: how do we prevent errors in the filesystem - from compromising the machine' + description: |- + fsType is the filesystem type of the volume that you want to mount. + Tip: Ensure that the filesystem type is supported by the host operating system. + Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + More info: https://kubernetes.io/docs/concepts/storage/volumes#rbd + TODO: how do we prevent errors in the filesystem from compromising the machine type: string image: - description: 'image is the rados image name. More - info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + description: |- + image is the rados image name. + More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it type: string keyring: - description: 'keyring is the path to key ring - for RBDUser. Default is /etc/ceph/keyring. More - info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + description: |- + keyring is the path to key ring for RBDUser. + Default is /etc/ceph/keyring. + More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it type: string monitors: - description: 'monitors is a collection of Ceph - monitors. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + description: |- + monitors is a collection of Ceph monitors. + More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it items: type: string type: array pool: - description: 'pool is the rados pool name. Default - is rbd. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + description: |- + pool is the rados pool name. + Default is rbd. + More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it type: string readOnly: - description: 'readOnly here will force the ReadOnly - setting in VolumeMounts. Defaults to false. - More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + description: |- + readOnly here will force the ReadOnly setting in VolumeMounts. + Defaults to false. + More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it type: boolean secretRef: - description: 'secretRef is name of the authentication - secret for RBDUser. If provided overrides keyring. - Default is nil. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + description: |- + secretRef is name of the authentication secret for RBDUser. If provided + overrides keyring. + Default is nil. + More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it properties: name: - description: 'Name of the referent. More info: - https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, - kind, uid?' + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? type: string type: object + x-kubernetes-map-type: atomic user: - description: 'user is the rados user name. Default - is admin. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + description: |- + user is the rados user name. + Default is admin. + More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it type: string required: - image @@ -1906,10 +1848,11 @@ spec: volume attached and mounted on Kubernetes nodes. properties: fsType: - description: fsType is the filesystem type to - mount. Must be a filesystem type supported by - the host operating system. Ex. "ext4", "xfs", - "ntfs". Default is "xfs". + description: |- + fsType is the filesystem type to mount. + Must be a filesystem type supported by the host operating system. + Ex. "ext4", "xfs", "ntfs". + Default is "xfs". type: string gateway: description: gateway is the host address of the @@ -1921,31 +1864,31 @@ spec: storage. type: string readOnly: - description: readOnly Defaults to false (read/write). - ReadOnly here will force the ReadOnly setting - in VolumeMounts. + description: |- + readOnly Defaults to false (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. type: boolean secretRef: - description: secretRef references to the secret - for ScaleIO user and other sensitive information. - If this is not provided, Login operation will - fail. + description: |- + secretRef references to the secret for ScaleIO user and other + sensitive information. If this is not provided, Login operation will fail. properties: name: - description: 'Name of the referent. More info: - https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, - kind, uid?' + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? type: string type: object + x-kubernetes-map-type: atomic sslEnabled: description: sslEnabled Flag enable/disable SSL communication with Gateway, default false type: boolean storageMode: - description: storageMode indicates whether the - storage for a volume should be ThickProvisioned - or ThinProvisioned. Default is ThinProvisioned. + description: |- + storageMode indicates whether the storage for a volume should be ThickProvisioned or ThinProvisioned. + Default is ThinProvisioned. type: string storagePool: description: storagePool is the ScaleIO Storage @@ -1956,9 +1899,9 @@ spec: system as configured in ScaleIO. type: string volumeName: - description: volumeName is the name of a volume - already created in the ScaleIO system that is - associated with this volume source. + description: |- + volumeName is the name of a volume already created in the ScaleIO system + that is associated with this volume source. type: string required: - gateway @@ -1966,35 +1909,30 @@ spec: - system type: object secret: - description: 'secret represents a secret that should - populate this volume. More info: https://kubernetes.io/docs/concepts/storage/volumes#secret' + description: |- + secret represents a secret that should populate this volume. + More info: https://kubernetes.io/docs/concepts/storage/volumes#secret properties: defaultMode: - description: 'defaultMode is Optional: mode bits - used to set permissions on created files by - default. Must be an octal value between 0000 - and 0777 or a decimal value between 0 and 511. - YAML accepts both octal and decimal values, - JSON requires decimal values for mode bits. - Defaults to 0644. Directories within the path - are not affected by this setting. This might - be in conflict with other options that affect - the file mode, like fsGroup, and the result - can be other mode bits set.' + description: |- + defaultMode is Optional: mode bits used to set permissions on created files by default. + Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, JSON requires decimal values + for mode bits. Defaults to 0644. + Directories within the path are not affected by this setting. + This might be in conflict with other options that affect the file + mode, like fsGroup, and the result can be other mode bits set. format: int32 type: integer items: - description: items If unspecified, each key-value - pair in the Data field of the referenced Secret - will be projected into the volume as a file - whose name is the key and content is the value. - If specified, the listed keys will be projected - into the specified paths, and unlisted keys - will not be present. If a key is specified which - is not present in the Secret, the volume setup - will error unless it is marked optional. Paths - must be relative and may not contain the '..' - path or start with '..'. + description: |- + items If unspecified, each key-value pair in the Data field of the referenced + Secret will be projected into the volume as a file whose name is the + key and content is the value. If specified, the listed keys will be + projected into the specified paths, and unlisted keys will not be + present. If a key is specified which is not present in the Secret, + the volume setup will error unless it is marked optional. Paths must be + relative and may not contain the '..' path or start with '..'. items: description: Maps a string key to a path within a volume. @@ -2003,25 +1941,21 @@ spec: description: key is the key to project. type: string mode: - description: 'mode is Optional: mode bits - used to set permissions on this file. - Must be an octal value between 0000 and - 0777 or a decimal value between 0 and - 511. YAML accepts both octal and decimal - values, JSON requires decimal values for - mode bits. If not specified, the volume - defaultMode will be used. This might be - in conflict with other options that affect - the file mode, like fsGroup, and the result - can be other mode bits set.' + description: |- + mode is Optional: mode bits used to set permissions on this file. + Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. + If not specified, the volume defaultMode will be used. + This might be in conflict with other options that affect the file + mode, like fsGroup, and the result can be other mode bits set. format: int32 type: integer path: - description: path is the relative path of - the file to map the key to. May not be - an absolute path. May not contain the - path element '..'. May not start with - the string '..'. + description: |- + path is the relative path of the file to map the key to. + May not be an absolute path. + May not contain the path element '..'. + May not start with the string '..'. type: string required: - key @@ -2033,8 +1967,9 @@ spec: Secret or its keys must be defined type: boolean secretName: - description: 'secretName is the name of the secret - in the pod''s namespace to use. More info: https://kubernetes.io/docs/concepts/storage/volumes#secret' + description: |- + secretName is the name of the secret in the pod's namespace to use. + More info: https://kubernetes.io/docs/concepts/storage/volumes#secret type: string type: object storageos: @@ -2042,45 +1977,42 @@ spec: attached and mounted on Kubernetes nodes. properties: fsType: - description: fsType is the filesystem type to - mount. Must be a filesystem type supported by - the host operating system. Ex. "ext4", "xfs", - "ntfs". Implicitly inferred to be "ext4" if - unspecified. + description: |- + fsType is the filesystem type to mount. + Must be a filesystem type supported by the host operating system. + Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. type: string readOnly: - description: readOnly defaults to false (read/write). - ReadOnly here will force the ReadOnly setting - in VolumeMounts. + description: |- + readOnly defaults to false (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. type: boolean secretRef: - description: secretRef specifies the secret to - use for obtaining the StorageOS API credentials. If - not specified, default values will be attempted. + description: |- + secretRef specifies the secret to use for obtaining the StorageOS API + credentials. If not specified, default values will be attempted. properties: name: - description: 'Name of the referent. More info: - https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, - kind, uid?' + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? type: string type: object + x-kubernetes-map-type: atomic volumeName: - description: volumeName is the human-readable - name of the StorageOS volume. Volume names - are only unique within a namespace. + description: |- + volumeName is the human-readable name of the StorageOS volume. Volume + names are only unique within a namespace. type: string volumeNamespace: - description: volumeNamespace specifies the scope - of the volume within StorageOS. If no namespace - is specified then the Pod's namespace will be - used. This allows the Kubernetes name scoping - to be mirrored within StorageOS for tighter - integration. Set VolumeName to any name to override - the default behaviour. Set to "default" if you - are not using namespaces within StorageOS. Namespaces - that do not pre-exist within StorageOS will - be created. + description: |- + volumeNamespace specifies the scope of the volume within StorageOS. If no + namespace is specified then the Pod's namespace will be used. This allows the + Kubernetes name scoping to be mirrored within StorageOS for tighter integration. + Set VolumeName to any name to override the default behaviour. + Set to "default" if you are not using namespaces within StorageOS. + Namespaces that do not pre-exist within StorageOS will be created. type: string type: object vsphereVolume: @@ -2088,10 +2020,10 @@ spec: attached and mounted on kubelets host machine properties: fsType: - description: fsType is filesystem type to mount. - Must be a filesystem type supported by the host - operating system. Ex. "ext4", "xfs", "ntfs". - Implicitly inferred to be "ext4" if unspecified. + description: |- + fsType is filesystem type to mount. + Must be a filesystem type supported by the host operating system. + Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. type: string storagePolicyID: description: storagePolicyID is the storage Policy @@ -2135,8 +2067,9 @@ spec: description: Conditions represents the current state of the Request Service. items: - description: Condition represents the current state of the Request - Service. A condition might not show up if it is not happening. + description: |- + Condition represents the current state of the Request Service. + A condition might not show up if it is not happening. properties: lastTransitionTime: description: Last time the condition transitioned from one status @@ -2204,9 +2137,3 @@ spec: storage: true subresources: status: {} -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] diff --git a/config/crd/bases/operator.ibm.com_operandrequests.yaml b/config/crd/bases/operator.ibm.com_operandrequests.yaml index b6935961..047888fe 100644 --- a/config/crd/bases/operator.ibm.com_operandrequests.yaml +++ b/config/crd/bases/operator.ibm.com_operandrequests.yaml @@ -1,11 +1,9 @@ - --- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.6.1 - creationTimestamp: null + controller-gen.kubebuilder.io/version: v0.14.0 name: operandrequests.operator.ibm.com spec: group: operator.ibm.com @@ -32,17 +30,24 @@ spec: name: v1alpha1 schema: openAPIV3Schema: - description: OperandRequest is the Schema for the operandrequests API. + description: OperandRequest is the Schema for the operandrequests API. Documentation + For additional details regarding install parameters check https://ibm.biz/icpfs39install. + License By installing this product you accept the license terms https://ibm.biz/icpfs39license properties: apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources type: string kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds type: string metadata: type: object @@ -72,13 +77,12 @@ spec: type: string bindings: additionalProperties: - description: Bindable is a Kubernetes resources to be - shared from one namespace to another. List of supported - resources are Secrets, Configmaps, Services, and Routes. - Secrets and Configmaps will be copied such that a - new Secret/Configmap with exactly the same data will - be created in the target namespace. Services and Routes - data will be copied into a configmap in the target + description: |- + Bindable is a Kubernetes resources to be shared from one namespace to another. + List of supported resources are Secrets, Configmaps, Services, and Routes. + Secrets and Configmaps will be copied such that a new Secret/Configmap with + exactly the same data will be created in the target namespace. + Services and Routes data will be copied into a configmap in the target namespace. properties: configmap: @@ -87,15 +91,15 @@ spec: share to the namespace of the OperandRequest. type: string route: - description: Route data will be shared by copying - it into a configmap which is then created in the - target namespace + description: |- + Route data will be shared by copying it into a configmap which is then + created in the target namespace properties: data: additionalProperties: type: string - description: Data is a key-value pair where - the value is a YAML path to a value in the + description: |- + Data is a key-value pair where the value is a YAML path to a value in the OpenShift Route, e.g. .spec.host or .spec.tls.termination type: object name: @@ -109,15 +113,15 @@ spec: of the OperandRequest. type: string service: - description: Service data will be shared by copying - it into a configmap which is then created in the - target namespace + description: |- + Service data will be shared by copying it into a configmap which is then + created in the target namespace properties: data: additionalProperties: type: string - description: Data is a key-value pair where - the value is a YAML path to a value in the + description: |- + Data is a key-value pair where the value is a YAML path to a value in the Kubernetes Service, e.g. .spec.ports[0]port type: object name: @@ -130,22 +134,22 @@ spec: of secret and/or configmap. type: object instanceName: - description: InstanceName is used when users want to deploy - multiple custom resources. It is the name of the custom - resource. + description: |- + InstanceName is used when users want to deploy multiple custom resources. + It is the name of the custom resource. type: string kind: - description: Kind is used when users want to deploy multiple - custom resources. Kind identifies the kind of the custom - resource. + description: |- + Kind is used when users want to deploy multiple custom resources. + Kind identifies the kind of the custom resource. type: string name: description: Name of the operand to be deployed. type: string spec: - description: Spec is used when users want to deploy multiple - custom resources. It is the configuration map of custom - resource. + description: |- + Spec is used when users want to deploy multiple custom resources. + It is the configuration map of custom resource. nullable: true type: object x-kubernetes-preserve-unknown-fields: true @@ -158,9 +162,9 @@ spec: reside. type: string registryNamespace: - description: Specifies the namespace in which the OperandRegistry - reside. The default is the current namespace in which the - request is defined. + description: |- + Specifies the namespace in which the OperandRegistry reside. + The default is the current namespace in which the request is defined. type: string required: - operands @@ -178,8 +182,9 @@ spec: description: Conditions represents the current state of the Request Service. items: - description: Condition represents the current state of the Request - Service. A condition might not show up if it is not happening. + description: |- + Condition represents the current state of the Request Service. + A condition might not show up if it is not happening. properties: lastTransitionTime: description: Last time the condition transitioned from one status @@ -309,9 +314,3 @@ spec: storage: true subresources: status: {} -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] diff --git a/config/crd/bases/operator.ibm.com_operatorconfigs.yaml b/config/crd/bases/operator.ibm.com_operatorconfigs.yaml index 768e5240..5a8daa1c 100644 --- a/config/crd/bases/operator.ibm.com_operatorconfigs.yaml +++ b/config/crd/bases/operator.ibm.com_operatorconfigs.yaml @@ -1,11 +1,9 @@ - --- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.6.1 - creationTimestamp: null + controller-gen.kubebuilder.io/version: v0.14.0 name: operatorconfigs.operator.ibm.com spec: group: operator.ibm.com @@ -22,14 +20,19 @@ spec: description: OperatorConfig is the Schema for the operatorconfigs API properties: apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources type: string kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds type: string metadata: type: object @@ -55,22 +58,20 @@ spec: the pod. properties: preferredDuringSchedulingIgnoredDuringExecution: - description: The scheduler will prefer to schedule pods - to nodes that satisfy the affinity expressions specified - by this field, but it may choose a node that violates - one or more of the expressions. The node that is most - preferred is the one with the greatest sum of weights, - i.e. for each node that meets all of the scheduling - requirements (resource request, requiredDuringScheduling - affinity expressions, etc.), compute a sum by iterating - through the elements of this field and adding "weight" - to the sum if the node matches the corresponding matchExpressions; - the node(s) with the highest sum are the most preferred. + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node matches the corresponding matchExpressions; the + node(s) with the highest sum are the most preferred. items: - description: An empty preferred scheduling term matches - all objects with implicit weight 0 (i.e. it's a - no-op). A null preferred scheduling term matches - no objects (i.e. is also a no-op). + description: |- + An empty preferred scheduling term matches all objects with implicit weight 0 + (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op). properties: preference: description: A node selector term, associated @@ -80,32 +81,26 @@ spec: description: A list of node selector requirements by node's labels. items: - description: A node selector requirement - is a selector that contains values, a - key, and an operator that relates the - key and values. + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. properties: key: description: The label key that the selector applies to. type: string operator: - description: Represents a key's relationship - to a set of values. Valid operators - are In, NotIn, Exists, DoesNotExist. - Gt, and Lt. + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. type: string values: - description: An array of string values. - If the operator is In or NotIn, the - values array must be non-empty. If - the operator is Exists or DoesNotExist, - the values array must be empty. If - the operator is Gt or Lt, the values - array must have a single element, - which will be interpreted as an integer. - This array is replaced during a strategic - merge patch. + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. items: type: string type: array @@ -118,32 +113,26 @@ spec: description: A list of node selector requirements by node's fields. items: - description: A node selector requirement - is a selector that contains values, a - key, and an operator that relates the - key and values. + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. properties: key: description: The label key that the selector applies to. type: string operator: - description: Represents a key's relationship - to a set of values. Valid operators - are In, NotIn, Exists, DoesNotExist. - Gt, and Lt. + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. type: string values: - description: An array of string values. - If the operator is In or NotIn, the - values array must be non-empty. If - the operator is Exists or DoesNotExist, - the values array must be empty. If - the operator is Gt or Lt, the values - array must have a single element, - which will be interpreted as an integer. - This array is replaced during a strategic - merge patch. + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. items: type: string type: array @@ -153,6 +142,7 @@ spec: type: object type: array type: object + x-kubernetes-map-type: atomic weight: description: Weight associated with matching the corresponding nodeSelectorTerm, in the range @@ -165,53 +155,46 @@ spec: type: object type: array requiredDuringSchedulingIgnoredDuringExecution: - description: If the affinity requirements specified - by this field are not met at scheduling time, the - pod will not be scheduled onto the node. If the affinity - requirements specified by this field cease to be met - at some point during pod execution (e.g. due to an - update), the system may or may not try to eventually - evict the pod from its node. + description: |- + If the affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to an update), the system + may or may not try to eventually evict the pod from its node. properties: nodeSelectorTerms: description: Required. A list of node selector terms. The terms are ORed. items: - description: A null or empty node selector term - matches no objects. The requirements of them - are ANDed. The TopologySelectorTerm type implements - a subset of the NodeSelectorTerm. + description: |- + A null or empty node selector term matches no objects. The requirements of + them are ANDed. + The TopologySelectorTerm type implements a subset of the NodeSelectorTerm. properties: matchExpressions: description: A list of node selector requirements by node's labels. items: - description: A node selector requirement - is a selector that contains values, a - key, and an operator that relates the - key and values. + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. properties: key: description: The label key that the selector applies to. type: string operator: - description: Represents a key's relationship - to a set of values. Valid operators - are In, NotIn, Exists, DoesNotExist. - Gt, and Lt. + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. type: string values: - description: An array of string values. - If the operator is In or NotIn, the - values array must be non-empty. If - the operator is Exists or DoesNotExist, - the values array must be empty. If - the operator is Gt or Lt, the values - array must have a single element, - which will be interpreted as an integer. - This array is replaced during a strategic - merge patch. + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. items: type: string type: array @@ -224,32 +207,26 @@ spec: description: A list of node selector requirements by node's fields. items: - description: A node selector requirement - is a selector that contains values, a - key, and an operator that relates the - key and values. + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. properties: key: description: The label key that the selector applies to. type: string operator: - description: Represents a key's relationship - to a set of values. Valid operators - are In, NotIn, Exists, DoesNotExist. - Gt, and Lt. + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. type: string values: - description: An array of string values. - If the operator is In or NotIn, the - values array must be non-empty. If - the operator is Exists or DoesNotExist, - the values array must be empty. If - the operator is Gt or Lt, the values - array must have a single element, - which will be interpreted as an integer. - This array is replaced during a strategic - merge patch. + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. items: type: string type: array @@ -259,10 +236,12 @@ spec: type: object type: array type: object + x-kubernetes-map-type: atomic type: array required: - nodeSelectorTerms type: object + x-kubernetes-map-type: atomic type: object podAffinity: description: Describes pod affinity scheduling rules (e.g. @@ -270,18 +249,16 @@ spec: other pod(s)). properties: preferredDuringSchedulingIgnoredDuringExecution: - description: The scheduler will prefer to schedule pods - to nodes that satisfy the affinity expressions specified - by this field, but it may choose a node that violates - one or more of the expressions. The node that is most - preferred is the one with the greatest sum of weights, - i.e. for each node that meets all of the scheduling - requirements (resource request, requiredDuringScheduling - affinity expressions, etc.), compute a sum by iterating - through the elements of this field and adding "weight" - to the sum if the node has pods which matches the - corresponding podAffinityTerm; the node(s) with the - highest sum are the most preferred. + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the + node(s) with the highest sum are the most preferred. items: description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred @@ -300,29 +277,24 @@ spec: of label selector requirements. The requirements are ANDed. items: - description: A label selector requirement - is a selector that contains values, - a key, and an operator that relates - the key and values. + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. properties: key: description: key is the label key that the selector applies to. type: string operator: - description: operator represents - a key's relationship to a set - of values. Valid operators are - In, NotIn, Exists and DoesNotExist. + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. type: string values: - description: values is an array - of string values. If the operator - is In or NotIn, the values array - must be non-empty. If the operator - is Exists or DoesNotExist, the - values array must be empty. This - array is replaced during a strategic + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic merge patch. items: type: string @@ -335,52 +307,44 @@ spec: matchLabels: additionalProperties: type: string - description: matchLabels is a map of {key,value} - pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, - whose key field is "key", the operator - is "In", and the values array contains - only "value". The requirements are ANDed. + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. type: object type: object + x-kubernetes-map-type: atomic namespaceSelector: - description: A label query over the set of - namespaces that the term applies to. The - term is applied to the union of the namespaces - selected by this field and the ones listed - in the namespaces field. null selector and - null or empty namespaces list means "this - pod's namespace". An empty selector ({}) - matches all namespaces. + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. properties: matchExpressions: description: matchExpressions is a list of label selector requirements. The requirements are ANDed. items: - description: A label selector requirement - is a selector that contains values, - a key, and an operator that relates - the key and values. + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. properties: key: description: key is the label key that the selector applies to. type: string operator: - description: operator represents - a key's relationship to a set - of values. Valid operators are - In, NotIn, Exists and DoesNotExist. + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. type: string values: - description: values is an array - of string values. If the operator - is In or NotIn, the values array - must be non-empty. If the operator - is Exists or DoesNotExist, the - values array must be empty. This - array is replaced during a strategic + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic merge patch. items: type: string @@ -393,43 +357,37 @@ spec: matchLabels: additionalProperties: type: string - description: matchLabels is a map of {key,value} - pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, - whose key field is "key", the operator - is "In", and the values array contains - only "value". The requirements are ANDed. + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. type: object type: object + x-kubernetes-map-type: atomic namespaces: - description: namespaces specifies a static - list of namespace names that the term applies - to. The term is applied to the union of - the namespaces listed in this field and - the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector - means "this pod's namespace". + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". items: type: string type: array topologyKey: - description: This pod should be co-located - (affinity) or not co-located (anti-affinity) - with the pods matching the labelSelector - in the specified namespaces, where co-located - is defined as running on a node whose value - of the label with key topologyKey matches - that of any node on which any of the selected - pods is running. Empty topologyKey is not - allowed. + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. type: string required: - topologyKey type: object weight: - description: weight associated with matching the - corresponding podAffinityTerm, in the range - 1-100. + description: |- + weight associated with matching the corresponding podAffinityTerm, + in the range 1-100. format: int32 type: integer required: @@ -438,24 +396,22 @@ spec: type: object type: array requiredDuringSchedulingIgnoredDuringExecution: - description: If the affinity requirements specified - by this field are not met at scheduling time, the - pod will not be scheduled onto the node. If the affinity - requirements specified by this field cease to be met - at some point during pod execution (e.g. due to a - pod label update), the system may or may not try to - eventually evict the pod from its node. When there - are multiple elements, the lists of nodes corresponding - to each podAffinityTerm are intersected, i.e. all - terms must be satisfied. + description: |- + If the affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to a pod label update), the + system may or may not try to eventually evict the pod from its node. + When there are multiple elements, the lists of nodes corresponding to each + podAffinityTerm are intersected, i.e. all terms must be satisfied. items: - description: Defines a set of pods (namely those matching - the labelSelector relative to the given namespace(s)) - that this pod should be co-located (affinity) or - not co-located (anti-affinity) with, where co-located - is defined as running on a node whose value of the - label with key matches that of any - node on which a pod of the set of pods is running + description: |- + Defines a set of pods (namely those matching the labelSelector + relative to the given namespace(s)) that this pod should be + co-located (affinity) or not co-located (anti-affinity) with, + where co-located is defined as running on a node whose value of + the label with key matches that of any node on which + a pod of the set of pods is running properties: labelSelector: description: A label query over a set of resources, @@ -466,28 +422,24 @@ spec: label selector requirements. The requirements are ANDed. items: - description: A label selector requirement - is a selector that contains values, a - key, and an operator that relates the - key and values. + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. properties: key: description: key is the label key that the selector applies to. type: string operator: - description: operator represents a key's - relationship to a set of values. Valid - operators are In, NotIn, Exists and - DoesNotExist. + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. type: string values: - description: values is an array of string - values. If the operator is In or NotIn, - the values array must be non-empty. - If the operator is Exists or DoesNotExist, - the values array must be empty. This - array is replaced during a strategic + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic merge patch. items: type: string @@ -500,50 +452,44 @@ spec: matchLabels: additionalProperties: type: string - description: matchLabels is a map of {key,value} - pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, - whose key field is "key", the operator is - "In", and the values array contains only - "value". The requirements are ANDed. + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. type: object type: object + x-kubernetes-map-type: atomic namespaceSelector: - description: A label query over the set of namespaces - that the term applies to. The term is applied - to the union of the namespaces selected by this - field and the ones listed in the namespaces - field. null selector and null or empty namespaces - list means "this pod's namespace". An empty - selector ({}) matches all namespaces. + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. properties: matchExpressions: description: matchExpressions is a list of label selector requirements. The requirements are ANDed. items: - description: A label selector requirement - is a selector that contains values, a - key, and an operator that relates the - key and values. + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. properties: key: description: key is the label key that the selector applies to. type: string operator: - description: operator represents a key's - relationship to a set of values. Valid - operators are In, NotIn, Exists and - DoesNotExist. + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. type: string values: - description: values is an array of string - values. If the operator is In or NotIn, - the values array must be non-empty. - If the operator is Exists or DoesNotExist, - the values array must be empty. This - array is replaced during a strategic + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic merge patch. items: type: string @@ -556,34 +502,29 @@ spec: matchLabels: additionalProperties: type: string - description: matchLabels is a map of {key,value} - pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, - whose key field is "key", the operator is - "In", and the values array contains only - "value". The requirements are ANDed. + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. type: object type: object + x-kubernetes-map-type: atomic namespaces: - description: namespaces specifies a static list - of namespace names that the term applies to. - The term is applied to the union of the namespaces - listed in this field and the ones selected by - namespaceSelector. null or empty namespaces - list and null namespaceSelector means "this - pod's namespace". + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". items: type: string type: array topologyKey: - description: This pod should be co-located (affinity) - or not co-located (anti-affinity) with the pods - matching the labelSelector in the specified - namespaces, where co-located is defined as running - on a node whose value of the label with key - topologyKey matches that of any node on which - any of the selected pods is running. Empty topologyKey - is not allowed. + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. type: string required: - topologyKey @@ -596,18 +537,16 @@ spec: as some other pod(s)). properties: preferredDuringSchedulingIgnoredDuringExecution: - description: The scheduler will prefer to schedule pods - to nodes that satisfy the anti-affinity expressions - specified by this field, but it may choose a node - that violates one or more of the expressions. The - node that is most preferred is the one with the greatest - sum of weights, i.e. for each node that meets all - of the scheduling requirements (resource request, - requiredDuringScheduling anti-affinity expressions, - etc.), compute a sum by iterating through the elements - of this field and adding "weight" to the sum if the - node has pods which matches the corresponding podAffinityTerm; - the node(s) with the highest sum are the most preferred. + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the anti-affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling anti-affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the + node(s) with the highest sum are the most preferred. items: description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred @@ -626,29 +565,24 @@ spec: of label selector requirements. The requirements are ANDed. items: - description: A label selector requirement - is a selector that contains values, - a key, and an operator that relates - the key and values. + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. properties: key: description: key is the label key that the selector applies to. type: string operator: - description: operator represents - a key's relationship to a set - of values. Valid operators are - In, NotIn, Exists and DoesNotExist. + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. type: string values: - description: values is an array - of string values. If the operator - is In or NotIn, the values array - must be non-empty. If the operator - is Exists or DoesNotExist, the - values array must be empty. This - array is replaced during a strategic + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic merge patch. items: type: string @@ -661,52 +595,44 @@ spec: matchLabels: additionalProperties: type: string - description: matchLabels is a map of {key,value} - pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, - whose key field is "key", the operator - is "In", and the values array contains - only "value". The requirements are ANDed. + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. type: object type: object + x-kubernetes-map-type: atomic namespaceSelector: - description: A label query over the set of - namespaces that the term applies to. The - term is applied to the union of the namespaces - selected by this field and the ones listed - in the namespaces field. null selector and - null or empty namespaces list means "this - pod's namespace". An empty selector ({}) - matches all namespaces. + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. properties: matchExpressions: description: matchExpressions is a list of label selector requirements. The requirements are ANDed. items: - description: A label selector requirement - is a selector that contains values, - a key, and an operator that relates - the key and values. + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. properties: key: description: key is the label key that the selector applies to. type: string operator: - description: operator represents - a key's relationship to a set - of values. Valid operators are - In, NotIn, Exists and DoesNotExist. + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. type: string values: - description: values is an array - of string values. If the operator - is In or NotIn, the values array - must be non-empty. If the operator - is Exists or DoesNotExist, the - values array must be empty. This - array is replaced during a strategic + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic merge patch. items: type: string @@ -719,43 +645,37 @@ spec: matchLabels: additionalProperties: type: string - description: matchLabels is a map of {key,value} - pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, - whose key field is "key", the operator - is "In", and the values array contains - only "value". The requirements are ANDed. + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. type: object type: object + x-kubernetes-map-type: atomic namespaces: - description: namespaces specifies a static - list of namespace names that the term applies - to. The term is applied to the union of - the namespaces listed in this field and - the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector - means "this pod's namespace". + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". items: type: string type: array topologyKey: - description: This pod should be co-located - (affinity) or not co-located (anti-affinity) - with the pods matching the labelSelector - in the specified namespaces, where co-located - is defined as running on a node whose value - of the label with key topologyKey matches - that of any node on which any of the selected - pods is running. Empty topologyKey is not - allowed. + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. type: string required: - topologyKey type: object weight: - description: weight associated with matching the - corresponding podAffinityTerm, in the range - 1-100. + description: |- + weight associated with matching the corresponding podAffinityTerm, + in the range 1-100. format: int32 type: integer required: @@ -764,24 +684,22 @@ spec: type: object type: array requiredDuringSchedulingIgnoredDuringExecution: - description: If the anti-affinity requirements specified - by this field are not met at scheduling time, the - pod will not be scheduled onto the node. If the anti-affinity - requirements specified by this field cease to be met - at some point during pod execution (e.g. due to a - pod label update), the system may or may not try to - eventually evict the pod from its node. When there - are multiple elements, the lists of nodes corresponding - to each podAffinityTerm are intersected, i.e. all - terms must be satisfied. + description: |- + If the anti-affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the anti-affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to a pod label update), the + system may or may not try to eventually evict the pod from its node. + When there are multiple elements, the lists of nodes corresponding to each + podAffinityTerm are intersected, i.e. all terms must be satisfied. items: - description: Defines a set of pods (namely those matching - the labelSelector relative to the given namespace(s)) - that this pod should be co-located (affinity) or - not co-located (anti-affinity) with, where co-located - is defined as running on a node whose value of the - label with key matches that of any - node on which a pod of the set of pods is running + description: |- + Defines a set of pods (namely those matching the labelSelector + relative to the given namespace(s)) that this pod should be + co-located (affinity) or not co-located (anti-affinity) with, + where co-located is defined as running on a node whose value of + the label with key matches that of any node on which + a pod of the set of pods is running properties: labelSelector: description: A label query over a set of resources, @@ -792,28 +710,24 @@ spec: label selector requirements. The requirements are ANDed. items: - description: A label selector requirement - is a selector that contains values, a - key, and an operator that relates the - key and values. + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. properties: key: description: key is the label key that the selector applies to. type: string operator: - description: operator represents a key's - relationship to a set of values. Valid - operators are In, NotIn, Exists and - DoesNotExist. + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. type: string values: - description: values is an array of string - values. If the operator is In or NotIn, - the values array must be non-empty. - If the operator is Exists or DoesNotExist, - the values array must be empty. This - array is replaced during a strategic + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic merge patch. items: type: string @@ -826,50 +740,44 @@ spec: matchLabels: additionalProperties: type: string - description: matchLabels is a map of {key,value} - pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, - whose key field is "key", the operator is - "In", and the values array contains only - "value". The requirements are ANDed. + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. type: object type: object + x-kubernetes-map-type: atomic namespaceSelector: - description: A label query over the set of namespaces - that the term applies to. The term is applied - to the union of the namespaces selected by this - field and the ones listed in the namespaces - field. null selector and null or empty namespaces - list means "this pod's namespace". An empty - selector ({}) matches all namespaces. + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. properties: matchExpressions: description: matchExpressions is a list of label selector requirements. The requirements are ANDed. items: - description: A label selector requirement - is a selector that contains values, a - key, and an operator that relates the - key and values. + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. properties: key: description: key is the label key that the selector applies to. type: string operator: - description: operator represents a key's - relationship to a set of values. Valid - operators are In, NotIn, Exists and - DoesNotExist. + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. type: string values: - description: values is an array of string - values. If the operator is In or NotIn, - the values array must be non-empty. - If the operator is Exists or DoesNotExist, - the values array must be empty. This - array is replaced during a strategic + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic merge patch. items: type: string @@ -882,34 +790,29 @@ spec: matchLabels: additionalProperties: type: string - description: matchLabels is a map of {key,value} - pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, - whose key field is "key", the operator is - "In", and the values array contains only - "value". The requirements are ANDed. + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. type: object type: object + x-kubernetes-map-type: atomic namespaces: - description: namespaces specifies a static list - of namespace names that the term applies to. - The term is applied to the union of the namespaces - listed in this field and the ones selected by - namespaceSelector. null or empty namespaces - list and null namespaceSelector means "this - pod's namespace". + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". items: type: string type: array topologyKey: - description: This pod should be co-located (affinity) - or not co-located (anti-affinity) with the pods - matching the labelSelector in the specified - namespaces, where co-located is defined as running - on a node whose value of the label with key - topologyKey matches that of any node on which - any of the selected pods is running. Empty topologyKey - is not allowed. + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. type: string required: - topologyKey @@ -921,30 +824,32 @@ spec: description: Name is the operator name as requested in the OperandRequest. type: string replicas: - description: Number of desired pods. This is a pointer to distinguish - between explicit zero and not specified. Defaults to 1. + description: |- + Number of desired pods. This is a pointer to distinguish between explicit + zero and not specified. Defaults to 1. format: int32 type: integer topologySpreadConstraints: - description: TopologySpreadConstraints describes how a group - of pods ought to spread across topology domains. Scheduler - will schedule pods in a way which abides by the constraints. + description: |- + TopologySpreadConstraints describes how a group of pods ought to spread across topology + domains. Scheduler will schedule pods in a way which abides by the constraints. All topologySpreadConstraints are ANDed. items: description: TopologySpreadConstraint specifies how to spread matching pods among the given topology. properties: labelSelector: - description: LabelSelector is used to find matching pods. - Pods that match this label selector are counted to determine - the number of pods in their corresponding topology domain. + description: |- + LabelSelector is used to find matching pods. + Pods that match this label selector are counted to determine the number of pods + in their corresponding topology domain. properties: matchExpressions: description: matchExpressions is a list of label selector requirements. The requirements are ANDed. items: - description: A label selector requirement is a selector - that contains values, a key, and an operator that + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. properties: key: @@ -952,17 +857,16 @@ spec: applies to. type: string operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, - NotIn, Exists and DoesNotExist. + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. type: string values: - description: values is an array of string values. - If the operator is In or NotIn, the values - array must be non-empty. If the operator is - Exists or DoesNotExist, the values array must - be empty. This array is replaced during a - strategic merge patch. + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. items: type: string type: array @@ -974,93 +878,93 @@ spec: matchLabels: additionalProperties: type: string - description: matchLabels is a map of {key,value} pairs. - A single {key,value} in the matchLabels map is equivalent - to an element of matchExpressions, whose key field - is "key", the operator is "In", and the values array - contains only "value". The requirements are ANDed. + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. type: object type: object + x-kubernetes-map-type: atomic maxSkew: - description: 'MaxSkew describes the degree to which pods - may be unevenly distributed. When `whenUnsatisfiable=DoNotSchedule`, - it is the maximum permitted difference between the number - of matching pods in the target topology and the global - minimum. The global minimum is the minimum number of - matching pods in an eligible domain or zero if the number - of eligible domains is less than MinDomains. For example, - in a 3-zone cluster, MaxSkew is set to 1, and pods with - the same labelSelector spread as 2/2/1: In this case, - the global minimum is 1. | zone1 | zone2 | zone3 | | P - P | P P | P | - if MaxSkew is 1, incoming pod - can only be scheduled to zone3 to become 2/2/2; scheduling - it onto zone1(zone2) would make the ActualSkew(3-1) - on zone1(zone2) violate MaxSkew(1). - if MaxSkew is - 2, incoming pod can be scheduled onto any zone. When - `whenUnsatisfiable=ScheduleAnyway`, it is used to give - higher precedence to topologies that satisfy it. It''s - a required field. Default value is 1 and 0 is not allowed.' + description: |- + MaxSkew describes the degree to which pods may be unevenly distributed. + When `whenUnsatisfiable=DoNotSchedule`, it is the maximum permitted difference + between the number of matching pods in the target topology and the global minimum. + The global minimum is the minimum number of matching pods in an eligible domain + or zero if the number of eligible domains is less than MinDomains. + For example, in a 3-zone cluster, MaxSkew is set to 1, and pods with the same + labelSelector spread as 2/2/1: + In this case, the global minimum is 1. + | zone1 | zone2 | zone3 | + | P P | P P | P | + - if MaxSkew is 1, incoming pod can only be scheduled to zone3 to become 2/2/2; + scheduling it onto zone1(zone2) would make the ActualSkew(3-1) on zone1(zone2) + violate MaxSkew(1). + - if MaxSkew is 2, incoming pod can be scheduled onto any zone. + When `whenUnsatisfiable=ScheduleAnyway`, it is used to give higher precedence + to topologies that satisfy it. + It's a required field. Default value is 1 and 0 is not allowed. format: int32 type: integer minDomains: - description: "MinDomains indicates a minimum number of - eligible domains. When the number of eligible domains - with matching topology keys is less than minDomains, - Pod Topology Spread treats \"global minimum\" as 0, - and then the calculation of Skew is performed. And when - the number of eligible domains with matching topology - keys equals or greater than minDomains, this value has - no effect on scheduling. As a result, when the number - of eligible domains is less than minDomains, scheduler - won't schedule more than maxSkew Pods to those domains. - If value is nil, the constraint behaves as if MinDomains - is equal to 1. Valid values are integers greater than - 0. When value is not nil, WhenUnsatisfiable must be - DoNotSchedule. \n For example, in a 3-zone cluster, - MaxSkew is set to 2, MinDomains is set to 5 and pods - with the same labelSelector spread as 2/2/2: | zone1 - | zone2 | zone3 | | P P | P P | P P | The number - of domains is less than 5(MinDomains), so \"global minimum\" - is treated as 0. In this situation, new pod with the - same labelSelector cannot be scheduled, because computed - skew will be 3(3 - 0) if new Pod is scheduled to any - of the three zones, it will violate MaxSkew. \n This - is an alpha field and requires enabling MinDomainsInPodTopologySpread - feature gate." + description: |- + MinDomains indicates a minimum number of eligible domains. + When the number of eligible domains with matching topology keys is less than minDomains, + Pod Topology Spread treats "global minimum" as 0, and then the calculation of Skew is performed. + And when the number of eligible domains with matching topology keys equals or greater than minDomains, + this value has no effect on scheduling. + As a result, when the number of eligible domains is less than minDomains, + scheduler won't schedule more than maxSkew Pods to those domains. + If value is nil, the constraint behaves as if MinDomains is equal to 1. + Valid values are integers greater than 0. + When value is not nil, WhenUnsatisfiable must be DoNotSchedule. + + + For example, in a 3-zone cluster, MaxSkew is set to 2, MinDomains is set to 5 and pods with the same + labelSelector spread as 2/2/2: + | zone1 | zone2 | zone3 | + | P P | P P | P P | + The number of domains is less than 5(MinDomains), so "global minimum" is treated as 0. + In this situation, new pod with the same labelSelector cannot be scheduled, + because computed skew will be 3(3 - 0) if new Pod is scheduled to any of the three zones, + it will violate MaxSkew. + + + This is an alpha field and requires enabling MinDomainsInPodTopologySpread feature gate. format: int32 type: integer topologyKey: - description: TopologyKey is the key of node labels. Nodes - that have a label with this key and identical values - are considered to be in the same topology. We consider - each as a "bucket", and try to put balanced - number of pods into each bucket. We define a domain - as a particular instance of a topology. Also, we define - an eligible domain as a domain whose nodes match the - node selector. e.g. If TopologyKey is "kubernetes.io/hostname", - each Node is a domain of that topology. And, if TopologyKey - is "topology.kubernetes.io/zone", each zone is a domain - of that topology. It's a required field. + description: |- + TopologyKey is the key of node labels. Nodes that have a label with this key + and identical values are considered to be in the same topology. + We consider each as a "bucket", and try to put balanced number + of pods into each bucket. + We define a domain as a particular instance of a topology. + Also, we define an eligible domain as a domain whose nodes match the node selector. + e.g. If TopologyKey is "kubernetes.io/hostname", each Node is a domain of that topology. + And, if TopologyKey is "topology.kubernetes.io/zone", each zone is a domain of that topology. + It's a required field. type: string whenUnsatisfiable: - description: 'WhenUnsatisfiable indicates how to deal - with a pod if it doesn''t satisfy the spread constraint. - - DoNotSchedule (default) tells the scheduler not to - schedule it. - ScheduleAnyway tells the scheduler to - schedule the pod in any location, but giving higher - precedence to topologies that would help reduce the skew. - A constraint is considered "Unsatisfiable" for an incoming - pod if and only if every possible node assignment for - that pod would violate "MaxSkew" on some topology. For - example, in a 3-zone cluster, MaxSkew is set to 1, and - pods with the same labelSelector spread as 3/1/1: | - zone1 | zone2 | zone3 | | P P P | P | P | If - WhenUnsatisfiable is set to DoNotSchedule, incoming - pod can only be scheduled to zone2(zone3) to become - 3/2/1(3/1/2) as ActualSkew(2-1) on zone2(zone3) satisfies - MaxSkew(1). In other words, the cluster can still be - imbalanced, but scheduler won''t make it *more* imbalanced. - It''s a required field.' + description: |- + WhenUnsatisfiable indicates how to deal with a pod if it doesn't satisfy + the spread constraint. + - DoNotSchedule (default) tells the scheduler not to schedule it. + - ScheduleAnyway tells the scheduler to schedule the pod in any location, + but giving higher precedence to topologies that would help reduce the + skew. + A constraint is considered "Unsatisfiable" for an incoming pod + if and only if every possible node assignment for that pod would violate + "MaxSkew" on some topology. + For example, in a 3-zone cluster, MaxSkew is set to 1, and pods with the same + labelSelector spread as 3/1/1: + | zone1 | zone2 | zone3 | + | P P P | P | P | + If WhenUnsatisfiable is set to DoNotSchedule, incoming pod can only be scheduled + to zone2(zone3) to become 3/2/1(3/1/2) as ActualSkew(2-1) on zone2(zone3) satisfies + MaxSkew(1). In other words, the cluster can still be imbalanced, but scheduler + won't make it *more* imbalanced. + It's a required field. type: string required: - maxSkew @@ -1088,9 +992,3 @@ spec: storage: true subresources: status: {} -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] diff --git a/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml b/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml index 744719d0..4a7f0229 100644 --- a/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml +++ b/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml @@ -28,7 +28,9 @@ spec: apiservicedefinitions: {} customresourcedefinitions: owned: - - description: OperandBindInfo is the Schema for the operandbindinfoes API. + - description: OperandBindInfo is the Schema for the operandbindinfoes API. Documentation + For additional details regarding install parameters check https://ibm.biz/icpfs39install. + License By installing this product you accept the license terms https://ibm.biz/icpfs39license displayName: OperandBindInfo kind: OperandBindInfo name: operandbindinfos.operator.ibm.com @@ -39,7 +41,9 @@ spec: x-descriptors: - urn:alm:descriptor:io.kubernetes.phase version: v1alpha1 - - description: OperandConfig is the Schema for the operandconfigs API. + - description: OperandConfig is the Schema for the operandconfigs API. Documentation + For additional details regarding install parameters check https://ibm.biz/icpfs39install. + License By installing this product you accept the license terms https://ibm.biz/icpfs39license displayName: OperandConfig kind: OperandConfig name: operandconfigs.operator.ibm.com @@ -54,7 +58,9 @@ spec: x-descriptors: - urn:alm:descriptor:io.kubernetes.phase version: v1alpha1 - - description: OperandRegistry is the Schema for the operandregistries API. + - description: OperandRegistry is the Schema for the operandregistries API. Documentation + For additional details regarding install parameters check https://ibm.biz/icpfs39install. + License By installing this product you accept the license terms https://ibm.biz/icpfs39license displayName: OperandRegistry kind: OperandRegistry name: operandregistries.operator.ibm.com @@ -74,7 +80,9 @@ spec: x-descriptors: - urn:alm:descriptor:io.kubernetes.phase version: v1alpha1 - - description: OperandRequest is the Schema for the operandrequests API. + - description: OperandRequest is the Schema for the operandrequests API. Documentation + For additional details regarding install parameters check https://ibm.biz/icpfs39install. + License By installing this product you accept the license terms https://ibm.biz/icpfs39license displayName: OperandRequest kind: OperandRequest name: operandrequests.operator.ibm.com @@ -94,6 +102,11 @@ spec: x-descriptors: - urn:alm:descriptor:io.kubernetes.phase version: v1alpha1 + - description: OperatorConfig is the Schema for the operatorconfigs API + displayName: Operator Config + kind: OperatorConfig + name: operatorconfigs.operator.ibm.com + version: v1alpha1 description: |- # Introduction diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml index fdd077c2..bcc71a55 100644 --- a/config/rbac/role.yaml +++ b/config/rbac/role.yaml @@ -1,29 +1,45 @@ +--- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: operand-deployment-lifecycle-manager rules: - apiGroups: - - operators.coreos.com + - operator.ibm.com resources: - - catalogsources + - auditloggings + - certmanagers verbs: + - delete - get - apiGroups: - - operator.ibm.com + - operators.coreos.com resources: - - certmanagers - - auditloggings + - catalogsources verbs: - get - - delete --- apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: - creationTimestamp: null name: operand-deployment-lifecycle-manager + namespace: placeholder rules: +- apiGroups: + - "" + resources: + - configmaps + - namespaces + - secrets + - services + verbs: + - create + - delete + - get + - list + - patch + - update + - watch - apiGroups: - '*' resources: @@ -36,7 +52,12 @@ rules: - patch - update - watch -- verbs: +- apiGroups: + - k8s.keycloak.org + resources: + - keycloakrealmimports + - keycloaks + verbs: - create - delete - get @@ -44,25 +65,41 @@ rules: - patch - update - watch - apiGroups: +- apiGroups: - operator.ibm.com resources: - operandconfigs - - operandconfigs/status - operandconfigs/finalizers + - operandconfigs/status + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - operator.ibm.com + resources: - operandregistries - - operandregistries/status - operandregistries/finalizers + - operandregistries/status + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - operator.ibm.com + resources: - operandrequests - - operandrequests/status - operandrequests/finalizers - - operandbindinfos - - operandbindinfos/status - - operandbindinfos/finalizers - - operatorconfigs - - operatorconfigs/status - - operatorconfigs/finalizers -- verbs: + - operandrequests/status + verbs: - create - delete - get @@ -70,14 +107,13 @@ rules: - patch - update - watch - apiGroups: - - '' +- apiGroups: + - operator.ibm.com resources: - - configmaps - - secrets - - services - - namespaces -- verbs: + - operatorconfigs + - operatorconfigs/finalizers + - operatorconfigs/status + verbs: - create - delete - get @@ -85,11 +121,12 @@ rules: - patch - update - watch - apiGroups: - - route.openshift.io +- apiGroups: + - operators.coreos.com resources: - - routes -- verbs: + - clusterserviceversions + - subscriptions + verbs: - create - delete - get @@ -97,12 +134,12 @@ rules: - patch - update - watch - apiGroups: +- apiGroups: - operators.coreos.com resources: - - operatorgroups - installplans -- verbs: + - operatorgroups + verbs: - create - delete - get @@ -110,10 +147,6 @@ rules: - patch - update - watch - apiGroups: - - k8s.keycloak.org - resources: - - keycloaks - apiGroups: - packages.operators.coreos.com resources: @@ -124,3 +157,15 @@ rules: - patch - update - watch +- apiGroups: + - route.openshift.io + resources: + - routes + verbs: + - create + - delete + - get + - list + - patch + - update + - watch diff --git a/controllers/constant/constant.go b/controllers/constant/constant.go index 5f334292..1157fd1b 100644 --- a/controllers/constant/constant.go +++ b/controllers/constant/constant.go @@ -31,6 +31,9 @@ const ( //OpreqLabel is the label used to label the subscription/CR managed by ODLM OpreqLabel string = "operator.ibm.com/opreq-control" + //InternalOpreqLabel is the label used label the OperandRequest internally created by ODLM + OperandOnlyLabel string = "operator.ibm.com/operand-only" + //ODLMReferenceLabel is the label used to label the resources used for ODLM operand value reference ODLMReferenceLabel string = "operator.ibm.com/referenced-by-odlm-resource" diff --git a/controllers/operandbindinfo/operandbindinfo_controller.go b/controllers/operandbindinfo/operandbindinfo_controller.go index 63d238e7..8e48fce3 100644 --- a/controllers/operandbindinfo/operandbindinfo_controller.go +++ b/controllers/operandbindinfo/operandbindinfo_controller.go @@ -70,6 +70,8 @@ var ( isRouteAPI = false ) +// +kubebuilder:rbac:groups=operator.ibm.com,namespace="placeholder",resources=operandbindinfos;operandbindinfos/status;operandbindinfos/finalizers,verbs=get;list;watch;create;update;patch;delete + // Reconcile reads that state of the cluster for a OperandBindInfo object and makes changes based on the state read // and what is in the OperandBindInfo.Spec // Note: diff --git a/controllers/operandconfig/operandconfig_controller.go b/controllers/operandconfig/operandconfig_controller.go index fd7825f2..df384921 100644 --- a/controllers/operandconfig/operandconfig_controller.go +++ b/controllers/operandconfig/operandconfig_controller.go @@ -54,6 +54,8 @@ type Reconciler struct { *deploy.ODLMOperator } +//+kubebuilder:rbac:groups=operator.ibm.com,namespace="placeholder",resources=operandconfigs;operandconfigs/status;operandconfigs/finalizers,verbs=get;list;watch;create;update;patch;delete + // Reconcile reads that state of the cluster for a OperandConfig object and makes changes based on the state read // and what is in the OperandConfig.Spec // Note: diff --git a/controllers/operandregistry/operandregistry_controller.go b/controllers/operandregistry/operandregistry_controller.go index b1bc9197..e8040988 100644 --- a/controllers/operandregistry/operandregistry_controller.go +++ b/controllers/operandregistry/operandregistry_controller.go @@ -43,6 +43,8 @@ type Reconciler struct { *deploy.ODLMOperator } +// +kubebuilder:rbac:groups=operator.ibm.com,namespace="placeholder",resources=operandregistries;operandregistries/status;operandregistries/finalizers,verbs=get;list;watch;create;update;patch;delete + // Reconcile reads that state of the cluster for a OperandRegistry object and makes changes based on the state read // and what is in the OperandRegistry.Spec // Note: diff --git a/controllers/operandrequest/operandrequest_controller.go b/controllers/operandrequest/operandrequest_controller.go index a0c11af0..9a4be9fc 100644 --- a/controllers/operandrequest/operandrequest_controller.go +++ b/controllers/operandrequest/operandrequest_controller.go @@ -61,6 +61,18 @@ type clusterObjects struct { subscription *olmv1alpha1.Subscription } +//+kubebuilder:rbac:groups=operator.ibm.com,resources=certmanagers;auditloggings,verbs=get;delete +//+kubebuilder:rbac:groups=operators.coreos.com,resources=catalogsources,verbs=get + +//+kubebuilder:rbac:groups=*,namespace="placeholder",resources=*,verbs=create;delete;get;list;patch;update;watch +//+kubebuilder:rbac:groups=operator.ibm.com,namespace="placeholder",resources=operandrequests;operandrequests/status;operandrequests/finalizers,verbs=get;list;watch;create;update;patch;delete +//+kubebuilder:rbac:groups="",namespace="placeholder",resources=configmaps;secrets;services;namespaces,verbs=create;delete;get;list;patch;update;watch +//+kubebuilder:rbac:groups=route.openshift.io,namespace="placeholder",resources=routes,verbs=create;delete;get;list;patch;update;watch +//+kubebuilder:rbac:groups=operators.coreos.com,namespace="placeholder",resources=operatorgroups;installplans,verbs=create;delete;get;list;patch;update;watch +//+kubebuilder:rbac:groups=k8s.keycloak.org,namespace="placeholder",resources=keycloaks;keycloakrealmimports,verbs=create;delete;get;list;patch;update;watch +//+kubebuilder:rbac:groups=packages.operators.coreos.com,namespace="placeholder",resources=packagemanifests,verbs=get;list;patch;update;watch +//+kubebuilder:rbac:groups=operators.coreos.com,namespace="placeholder",resources=clusterserviceversions;subscriptions,verbs=create;delete;get;list;patch;update;watch + // Reconcile reads that state of the cluster for a OperandRequest object and makes changes based on the state read // and what is in the OperandRequest.Spec // Note: diff --git a/controllers/operandrequest/reconcile_operand.go b/controllers/operandrequest/reconcile_operand.go index 7346cd52..bdc94868 100644 --- a/controllers/operandrequest/reconcile_operand.go +++ b/controllers/operandrequest/reconcile_operand.go @@ -1073,8 +1073,7 @@ func (r *Reconciler) updateK8sResource(ctx context.Context, existingK8sRes unstr // Deep copy the existing k8s resource originalK8sRes, err := deepcopy.Anything(existingK8sRes.Object) if err != nil { - klog.Error(err) - return false, err + return false, errors.Wrapf(err, "failed to deep copy k8s resource -- Kind: %s, NamespacedName: %s/%s", kind, namespace, name) } // Update the existing k8s resource with the merged CR diff --git a/controllers/operandrequest/reconcile_operator.go b/controllers/operandrequest/reconcile_operator.go index 0c237d79..82d44b67 100644 --- a/controllers/operandrequest/reconcile_operator.go +++ b/controllers/operandrequest/reconcile_operator.go @@ -406,45 +406,23 @@ func (r *Reconciler) uninstallOperatorsAndOperands(ctx context.Context, operandN return nil } - // remove request info including channel and operator namespace in annotation of subscription - reqName := requestInstance.ObjectMeta.Name - reqNs := requestInstance.ObjectMeta.Namespace - delete(sub.Annotations, reqNs+"."+reqName+"."+op.Name+"/request") - delete(sub.Annotations, reqNs+"."+reqName+"."+op.Name+"/operatorNamespace") - - uninstallOperatorOnly := false - var nsAnnoSlice []string - namespaceReg, _ := regexp.Compile(`^(.*)\.(.*)\.(.*)\/operatorNamespace`) - for anno, ns := range sub.Annotations { - if namespaceReg.MatchString(anno) { - nsAnnoSlice = append(nsAnnoSlice, ns) + uninstallOperator, uninstallOperand := checkSubAnnotationsForUninstall(requestInstance.ObjectMeta.Name, requestInstance.ObjectMeta.Namespace, op.Name, sub) + if !uninstallOperand && !uninstallOperator { + if err = r.updateSubscription(ctx, requestInstance, sub); err != nil { + requestInstance.SetMemberStatus(op.Name, operatorv1alpha1.OperatorFailed, "", &r.Mutex) + return err } - } - if len(nsAnnoSlice) != 0 { - // No OperandRequest is requesting operator in existing subscription's namespace, uninstall Operator only - if !util.Contains(nsAnnoSlice, sub.Namespace) { - uninstallOperatorOnly = true - } else { - // remove the associated request from annotation of subscription - if err = r.updateSubscription(ctx, requestInstance, sub); err != nil { - requestInstance.SetMemberStatus(op.Name, operatorv1alpha1.OperatorFailed, "", &r.Mutex) - return err - } - requestInstance.SetMemberStatus(op.Name, operatorv1alpha1.OperatorUpdating, "", &r.Mutex) + requestInstance.SetMemberStatus(op.Name, operatorv1alpha1.OperatorUpdating, "", &r.Mutex) - klog.V(1).Infof("Did not delete Subscription %s/%s which is requested by other OperandRequests", sub.Namespace, sub.Name) - return nil - } + klog.V(1).Infof("No deletion, subscription %s/%s and its operands are still requested by other OperandRequests", sub.Namespace, sub.Name) + return nil } - csv, err := r.GetClusterServiceVersion(ctx, sub) - // If can't get CSV, requeue the request - if err != nil { + if csv, err := r.GetClusterServiceVersion(ctx, sub); err != nil { + // If can't get CSV, requeue the request return err - } - - if csv != nil { - if !uninstallOperatorOnly { + } else if csv != nil { + if uninstallOperand { klog.V(2).Infof("Deleting all the Custom Resources for CSV, Namespace: %s, Name: %s", csv.Namespace, csv.Name) if err := r.deleteAllCustomResource(ctx, csv, requestInstance, configInstance, operandName, configInstance.Namespace); err != nil { return err @@ -454,34 +432,46 @@ func (r *Reconciler) uninstallOperatorsAndOperands(ctx context.Context, operandN return err } } - if r.checkUninstallLabel(sub) { - klog.V(1).Infof("Operator %s has label operator.ibm.com/opreq-do-not-uninstall. Skip the uninstall", op.Name) - return nil - } + if uninstallOperator { + if r.checkUninstallLabel(sub) { + klog.V(1).Infof("Operator %s has label operator.ibm.com/opreq-do-not-uninstall. Skip the uninstall", op.Name) + return nil + } - klog.V(3).Info("Set Deleting Condition in the operandRequest") - requestInstance.SetDeletingCondition(csv.Name, operatorv1alpha1.ResourceTypeCsv, corev1.ConditionTrue, &r.Mutex) + klog.V(3).Info("Set Deleting Condition in the operandRequest") + requestInstance.SetDeletingCondition(csv.Name, operatorv1alpha1.ResourceTypeCsv, corev1.ConditionTrue, &r.Mutex) - klog.V(1).Infof("Deleting the ClusterServiceVersion, Namespace: %s, Name: %s", csv.Namespace, csv.Name) - if err := r.Delete(ctx, csv); err != nil { - requestInstance.SetDeletingCondition(csv.Name, operatorv1alpha1.ResourceTypeCsv, corev1.ConditionFalse, &r.Mutex) - return errors.Wrap(err, "failed to delete the ClusterServiceVersion") + klog.V(1).Infof("Deleting the ClusterServiceVersion, Namespace: %s, Name: %s", csv.Namespace, csv.Name) + if err := r.Delete(ctx, csv); err != nil { + requestInstance.SetDeletingCondition(csv.Name, operatorv1alpha1.ResourceTypeCsv, corev1.ConditionFalse, &r.Mutex) + return errors.Wrap(err, "failed to delete the ClusterServiceVersion") + } } } - klog.V(2).Infof("Deleting the Subscription, Namespace: %s, Name: %s", namespace, op.Name) - requestInstance.SetDeletingCondition(op.Name, operatorv1alpha1.ResourceTypeSub, corev1.ConditionTrue, &r.Mutex) + if uninstallOperator { + klog.V(2).Infof("Deleting the Subscription, Namespace: %s, Name: %s", namespace, op.Name) + requestInstance.SetDeletingCondition(op.Name, operatorv1alpha1.ResourceTypeSub, corev1.ConditionTrue, &r.Mutex) - if err := r.Delete(ctx, sub); err != nil { - if apierrors.IsNotFound(err) { - klog.Warningf("Subscription %s was not found in namespace %s", op.Name, namespace) - } else { - requestInstance.SetDeletingCondition(op.Name, operatorv1alpha1.ResourceTypeSub, corev1.ConditionFalse, &r.Mutex) - return errors.Wrap(err, "failed to delete subscription") + if err := r.Delete(ctx, sub); err != nil { + if apierrors.IsNotFound(err) { + klog.Warningf("Subscription %s was not found in namespace %s", op.Name, namespace) + } else { + requestInstance.SetDeletingCondition(op.Name, operatorv1alpha1.ResourceTypeSub, corev1.ConditionFalse, &r.Mutex) + return errors.Wrap(err, "failed to delete subscription") + } + } + + klog.V(1).Infof("Subscription %s/%s is deleted", namespace, op.Name) + } else { + if err = r.updateSubscription(ctx, requestInstance, sub); err != nil { + requestInstance.SetMemberStatus(op.Name, operatorv1alpha1.OperatorFailed, "", &r.Mutex) + return err } + requestInstance.SetMemberStatus(op.Name, operatorv1alpha1.OperatorUpdating, "", &r.Mutex) + klog.V(1).Infof("Subscription %s/%s is not deleted due to the annotation from OperandRequest", namespace, op.Name) } - klog.V(1).Infof("Subscription %s/%s is deleted", namespace, op.Name) return nil } @@ -653,3 +643,58 @@ func CheckSingletonServices(operator string) bool { singletonServices := []string{"ibm-cert-manager-operator", "ibm-licensing-operator"} return util.Contains(singletonServices, operator) } + +// checkSubAnnotationsForUninstall checks the annotations of a Subscription object +// to determine whether the operator and operand should be uninstalled. +// It takes the name of the OperandRequest, the namespace of the OperandRequest, +// the name of the operator, and a pointer to the Subscription object as input. +// It returns two boolean values: uninstallOperator and uninstallOperand. +// If uninstallOperator is true, it means the operator should be uninstalled. +// If uninstallOperand is true, it means the operand should be uninstalled. +func checkSubAnnotationsForUninstall(reqName, reqNs, opName string, sub *olmv1alpha1.Subscription) (bool, bool) { + uninstallOperator := true + uninstallOperand := true + + var curChannel string + if sub.GetAnnotations() != nil { + curChannel = sub.Annotations[reqNs+"."+reqName+"."+opName+"/request"] + } + + delete(sub.Annotations, reqNs+"."+reqName+"."+opName+"/request") + delete(sub.Annotations, reqNs+"."+reqName+"."+opName+"/operatorNamespace") + + var opreqNsSlice []string + var operatorNameSlice []string + var channelSlice []string + namespaceReg, _ := regexp.Compile(`^(.*)\.(.*)\.(.*)\/operatorNamespace`) + channelReg, _ := regexp.Compile(`^(.*)\.(.*)\.(.*)\/request`) + + for key, value := range sub.Annotations { + if namespaceReg.MatchString(key) { + opreqNsSlice = append(opreqNsSlice, value) + } + + if channelReg.MatchString(key) { + channelSlice = append(channelSlice, value) + // Extract the operator name from the key + keyParts := strings.Split(key, "/") + annoPrefix := strings.Split(keyParts[0], ".") + operatorNameSlice = append(operatorNameSlice, annoPrefix[len(annoPrefix)-1]) + } + } + + // If one of remaining /operatorNamespace annotations' values is the same as subscription's namespace, + // the operator should NOT be uninstalled. + if util.Contains(opreqNsSlice, sub.Namespace) { + uninstallOperator = false + } + + // If the removed/uninstalled /request annotation's value is NOT the same as all other /request annotation's values. + // or the operator namespace in one of remaining annotation is the same as the operator name in removed/uninstalled /request + // the operand should NOT be uninstalled. + if util.Differs(channelSlice, curChannel) || util.Contains(operatorNameSlice, opName) { + uninstallOperand = false + } + + return uninstallOperator, uninstallOperand +} diff --git a/controllers/operandrequest/reconcile_operator_test.go b/controllers/operandrequest/reconcile_operator_test.go new file mode 100644 index 00000000..d4399d05 --- /dev/null +++ b/controllers/operandrequest/reconcile_operator_test.go @@ -0,0 +1,240 @@ +// +// Copyright 2022 IBM Corporation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package operandrequest + +import ( + "testing" + + olmv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1" + "github.com/stretchr/testify/assert" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + + operatorv1alpha1 "github.com/IBM/operand-deployment-lifecycle-manager/api/v1alpha1" +) + +func TestGenerateClusterObjects(t *testing.T) { + r := &Reconciler{} + + o := &operatorv1alpha1.Operator{ + Namespace: "test-namespace", + TargetNamespaces: []string{"target-namespace"}, + InstallMode: "namespace", + Channel: "test-channel", + PackageName: "test-package", + SourceName: "test-source", + SourceNamespace: "test-source-namespace", + InstallPlanApproval: "Automatic", + StartingCSV: "test-csv", + SubscriptionConfig: &olmv1alpha1.SubscriptionConfig{ + Env: []corev1.EnvVar{ + { + Name: "key", + Value: "value", + }, + }, + }, + } + + registryKey := types.NamespacedName{ + Namespace: "test-registry-namespace", + Name: "test-registry-name", + } + requestKey := types.NamespacedName{ + Namespace: "test-namespace", + Name: "test-opreq", + } + + co := r.generateClusterObjects(o, registryKey, requestKey) + + assert.NotNil(t, co.namespace) + assert.Equal(t, "Namespace", co.namespace.Kind) + assert.Equal(t, "v1", co.namespace.APIVersion) + assert.Equal(t, "test-namespace", co.namespace.Name) + assert.Equal(t, map[string]string{"operator.ibm.com/opreq-control": "true"}, co.namespace.Labels) + + assert.NotNil(t, co.operatorGroup) + assert.Equal(t, "OperatorGroup", co.operatorGroup.Kind) + assert.Equal(t, "test-namespace", co.operatorGroup.Namespace) + assert.Equal(t, []string{"target-namespace"}, co.operatorGroup.Spec.TargetNamespaces) + + assert.NotNil(t, co.subscription) + assert.Equal(t, "Subscription", co.subscription.Kind) + assert.Equal(t, "test-namespace", co.subscription.Namespace) + assert.Equal(t, "test-channel", co.subscription.Spec.Channel) + assert.Equal(t, "test-package", co.subscription.Spec.Package) + assert.Equal(t, "test-source", co.subscription.Spec.CatalogSource) + assert.Equal(t, "test-source-namespace", co.subscription.Spec.CatalogSourceNamespace) + assert.Equal(t, olmv1alpha1.Approval("Automatic"), co.subscription.Spec.InstallPlanApproval) + assert.Equal(t, "test-csv", co.subscription.Spec.StartingCSV) + assert.NotNil(t, co.subscription.Spec.Config) + assert.Equal(t, "value", co.subscription.Spec.Config.Env[0].Value) +} + +func TestCheckSubAnnotationsForUninstall(t *testing.T) { + reqNameA := "common-service" + reqNsA := "ibm-common-services" + opNameA := "ibm-iam" + opChannelA := "v3" + + reqNameB := "other-request" + reqNsB := "other-namespace" + opNameB := "ibm-im" + opChannelB := "v4.0" + + reqNameC := "common-service" + reqNsC := "ibm-common-services" + opNameC := "common-service-postgresql" + opChannelC := "stable-v1" + + reqNameD := "common-service" + reqNsD := "ibm-common-services" + opNameD := "edb-keycloak" + opChannelD := "stable-v1" + + // The annotation key has prefix: ../* + + // When following conditions are met, the operator should be uninstalled: + // If all remaining /operatorNamespace annotations' values are not the same as subscription's namespace, the operator should be uninstalled. + + // When following conditions are met, the operand should be uninstalled: + // 1. The removed/uninstalled /request annotation's value is the same as all other /request annotation's values. + // 2. Operator name in removed/uninstalled /request is different from all other /request annotation's values. + + // Test case 1: uninstallOperator is true, uninstallOperand is true + // The operator and operand should be uninstalled because only the remaining OperandRequest B is internal-opreq: true. + sub := &olmv1alpha1.Subscription{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: reqNsA, + Annotations: map[string]string{ + reqNsA + "." + reqNameA + "." + opNameA + "/request": opChannelA, + reqNsA + "." + reqNameA + "." + opNameA + "/operatorNamespace": reqNsA, + }, + }, + } + + uninstallOperator, uninstallOperand := checkSubAnnotationsForUninstall(reqNameA, reqNsA, opNameA, sub) + + assert.True(t, uninstallOperator) + assert.True(t, uninstallOperand) + + assert.NotContains(t, sub.Annotations, reqNsA+"."+reqNameA+"."+opNameA+"/request") + assert.NotContains(t, sub.Annotations, reqNsA+"."+reqNameA+"."+opNameA+"/operatorNamespace") + + // Test case 2: uninstallOperator is true, uninstallOperand is false + // The operator should be uninstalled because only the remaining Subscription B requesting operator is not in the same namespace as the Subscription. + sub = &olmv1alpha1.Subscription{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: reqNsA, + Annotations: map[string]string{ + reqNsA + "." + reqNameA + "." + opNameA + "/request": opChannelA, + reqNsA + "." + reqNameA + "." + opNameA + "/operatorNamespace": reqNsA, + reqNsB + "." + reqNameB + "." + opNameB + "/request": opChannelB, + reqNsB + "." + reqNameB + "." + opNameB + "/operatorNamespace": reqNsB, + }, + }, + } + + uninstallOperator, uninstallOperand = checkSubAnnotationsForUninstall(reqNameA, reqNsA, opNameA, sub) + + assert.True(t, uninstallOperator) + assert.False(t, uninstallOperand) + + assert.NotContains(t, sub.Annotations, reqNsA+"."+reqNameA+"."+opNameA+"/request") + assert.NotContains(t, sub.Annotations, reqNsA+"."+reqNameA+"."+opNameA+"/operatorNamespace") + assert.Contains(t, sub.Annotations, reqNsB+"."+reqNameB+"."+opNameB+"/request") + assert.Contains(t, sub.Annotations, reqNsB+"."+reqNameB+"."+opNameB+"/operatorNamespace") + + // Test case 3: uninstallOperator is false, uninstallOperand is true + // The operator should not be uninstalled because the remaining Subscription B requesting operator is in the same namespace as the Subscription. + // The operand should be uninstalled because + // 1. the operator name in removed/uninstalled Subscription A is different from all other Subscription annotation's values, + // 2. but the removed/uninstalled /request annotation's value is the same as all other /request annotation's values. + sub = &olmv1alpha1.Subscription{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: reqNsC, + Annotations: map[string]string{ + reqNsC + "." + reqNameC + "." + opNameC + "/request": opChannelC, + reqNsC + "." + reqNameC + "." + opNameC + "/operatorNamespace": reqNsC, + reqNsD + "." + reqNameD + "." + opNameD + "/request": opChannelD, + reqNsD + "." + reqNameD + "." + opNameD + "/operatorNamespace": reqNsD, + }, + }, + } + + uninstallOperator, uninstallOperand = checkSubAnnotationsForUninstall(reqNameC, reqNsC, opNameC, sub) + + assert.False(t, uninstallOperator) + assert.True(t, uninstallOperand) + + assert.NotContains(t, sub.Annotations, reqNsC+"."+reqNameC+"."+opNameC+"/request") + assert.NotContains(t, sub.Annotations, reqNsC+"."+reqNameC+"."+opNameC+"/operatorNamespace") + assert.Contains(t, sub.Annotations, reqNsD+"."+reqNameD+"."+opNameD+"/request") + assert.Contains(t, sub.Annotations, reqNsD+"."+reqNameD+"."+opNameD+"/operatorNamespace") + + // Test case 4: uninstallOperator is false, uninstallOperand is false + // The operator and operand should not be uninstalled because at least one different OperandRequest requesting same operator + // But the annotation of removed OperandRequest should be removed. + sub = &olmv1alpha1.Subscription{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: reqNsA, + Annotations: map[string]string{ + reqNsA + "." + reqNameA + "." + opNameA + "/request": opChannelA, + reqNsA + "." + reqNameA + "." + opNameA + "/operatorNamespace": reqNsA, + // The remaining OperandRequest B is requesting the same operator + reqNsB + "." + reqNameB + "." + opNameA + "/request": opChannelA, + reqNsB + "." + reqNameB + "." + opNameA + "/operatorNamespace": reqNsA, + }, + }, + } + + uninstallOperator, uninstallOperand = checkSubAnnotationsForUninstall(reqNameA, reqNsA, opNameA, sub) + + assert.False(t, uninstallOperator) + assert.False(t, uninstallOperand) + + assert.NotContains(t, sub.Annotations, reqNsA+"."+reqNameA+"."+opNameA+"/request") + assert.NotContains(t, sub.Annotations, reqNsA+"."+reqNameA+"."+opNameA+"/operatorNamespace") + assert.Contains(t, sub.Annotations, reqNsB+"."+reqNameB+"."+opNameA+"/request") + assert.Contains(t, sub.Annotations, reqNsB+"."+reqNameB+"."+opNameA+"/operatorNamespace") + + // Test case 5: uninstallOperator is false, uninstallOperand is false + // The operator and operand should not be uninstalled because at OperandRequest request a different operator name and different channel, but the same operator namespace + // But the annotation of removed OperandRequest should be removed. + sub = &olmv1alpha1.Subscription{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: reqNsA, + Annotations: map[string]string{ + reqNsA + "." + reqNameA + "." + opNameA + "/request": opChannelA, + reqNsA + "." + reqNameA + "." + opNameA + "/operatorNamespace": reqNsA, + reqNsB + "." + reqNameB + "." + opNameB + "/request": opChannelB, + reqNsB + "." + reqNameB + "." + opNameB + "/operatorNamespace": reqNsA, + }, + }, + } + + uninstallOperator, uninstallOperand = checkSubAnnotationsForUninstall(reqNameA, reqNsA, opNameA, sub) + + assert.False(t, uninstallOperator) + assert.False(t, uninstallOperand) + + assert.NotContains(t, sub.Annotations, reqNsA+"."+reqNameA+"."+opNameA+"/request") + assert.NotContains(t, sub.Annotations, reqNsA+"."+reqNameA+"."+opNameA+"/operatorNamespace") + assert.Contains(t, sub.Annotations, reqNsB+"."+reqNameB+"."+opNameB+"/request") + assert.Contains(t, sub.Annotations, reqNsB+"."+reqNameB+"."+opNameB+"/operatorNamespace") +} diff --git a/controllers/operatorconfig/operatorconfig_controller.go b/controllers/operatorconfig/operatorconfig_controller.go index a00f90ae..6a39383b 100644 --- a/controllers/operatorconfig/operatorconfig_controller.go +++ b/controllers/operatorconfig/operatorconfig_controller.go @@ -42,9 +42,7 @@ type Reconciler struct { *deploy.ODLMOperator } -//+kubebuilder:rbac:groups=operator.ibm.com,resources=operatorconfigs,verbs=get;list;watch;create;update;patch;delete -//+kubebuilder:rbac:groups=operator.ibm.com,resources=operatorconfigs/status,verbs=get;update;patch -//+kubebuilder:rbac:groups=operator.ibm.com,resources=operatorconfigs/finalizers,verbs=update +//+kubebuilder:rbac:groups=operator.ibm.com,namespace="placeholder",resources=operatorconfigs;operatorconfigs/status;operatorconfigs/finalizers,verbs=get;list;watch;create;update;patch;delete // Reconcile is part of the main kubernetes reconciliation loop which aims to // move the current state of the cluster closer to the desired state. diff --git a/controllers/util/util.go b/controllers/util/util.go index 728e0f72..fbb1b435 100644 --- a/controllers/util/util.go +++ b/controllers/util/util.go @@ -235,6 +235,15 @@ func Contains(list []string, s string) bool { return false } +func Differs(list []string, s string) bool { + for _, v := range list { + if v != s { + return true + } + } + return false +} + func ObjectToNewUnstructured(obj interface{}) (*unstructured.Unstructured, error) { content, err := runtime.DefaultUnstructuredConverter.ToUnstructured(obj) if err != nil { diff --git a/controllers/util/util_test.go b/controllers/util/util_test.go index 50df8ad2..a76c3d76 100644 --- a/controllers/util/util_test.go +++ b/controllers/util/util_test.go @@ -71,3 +71,43 @@ var _ = Describe("Get environmental variables", func() { }) }) }) + +var _ = Describe("Contains", func() { + It("Should return true if the list contains the string", func() { + list := []string{"apple", "banana", "cherry"} + s := "banana" + Expect(Contains(list, s)).Should(BeTrue()) + }) + + It("Should return false if the list does not contain the string", func() { + list := []string{"apple", "banana", "cherry"} + s := "orange" + Expect(Contains(list, s)).Should(BeFalse()) + }) + + It("Should return false if the list is empty", func() { + list := []string{} + s := "apple" + Expect(Contains(list, s)).Should(BeFalse()) + }) +}) + +var _ = Describe("Differs", func() { + It("Should return true if the list contains a different string", func() { + list := []string{"apple", "banana", "cherry"} + s := "banana" + Expect(Differs(list, s)).Should(BeTrue()) + }) + + It("Should return false if the list contains only the same string", func() { + list := []string{"apple", "apple", "apple"} + s := "apple" + Expect(Differs(list, s)).Should(BeFalse()) + }) + + It("Should return false if the list is empty", func() { + list := []string{} + s := "apple" + Expect(Differs(list, s)).Should(BeFalse()) + }) +}) From e6031a2b6a9deae075b9debb255264910e0af01d Mon Sep 17 00:00:00 2001 From: Travis CI User Date: Tue, 2 Apr 2024 13:19:50 +0000 Subject: [PATCH 091/179] Trigger build with new base image --- base_images.json | 34 ++++++++++------------------------ 1 file changed, 10 insertions(+), 24 deletions(-) diff --git a/base_images.json b/base_images.json index b679ff09..616e9e47 100644 --- a/base_images.json +++ b/base_images.json @@ -29,7 +29,7 @@ "destStage": "edge", "destNamespace": "build-images", "destImage": "ubi9-micro", - "tag": "9.3-13", + "tag": "9.3-15", "updatePackages": [] }, { @@ -40,7 +40,7 @@ "destStage": "edge", "destNamespace": "build-images", "destImage": "ubi9", - "tag": "9.3-1552", + "tag": "9.3-1610", "updatePackages": [] }, { @@ -51,7 +51,7 @@ "destStage": "edge", "destNamespace": "build-images", "destImage": "ubi9-minimal", - "tag": "9.3-1552", + "tag": "9.3-1612", "updatePackages": [] }, { @@ -62,7 +62,7 @@ "destStage": "edge", "destNamespace": "build-images", "destImage": "helm-operator", - "tag": "v1.33.0", + "tag": "v1.34.0", "updatePackages": [] }, { @@ -70,41 +70,27 @@ "sourceImage": "ubi8-minimal", "sourceTag": "8.9-1137", "destImage": "node-v18-ubi8-minimal", - "nodeVersion": "18.19.1" + "nodeVersion": "18.20.0" }, { "imageType": "node", "sourceImage": "ubi8-minimal", "sourceTag": "8.9-1137", "destImage": "node-v20-ubi8-minimal", - "nodeVersion": "20.11.1" + "nodeVersion": "20.12.0" }, { "imageType": "node", "sourceImage": "ubi9-minimal", - "sourceTag": "9.3-1552", + "sourceTag": "9.3-1612", "destImage": "node-v18-ubi9-minimal", - "nodeVersion": "18.19.1" + "nodeVersion": "18.20.0" }, { "imageType": "node", "sourceImage": "ubi9-minimal", - "sourceTag": "9.3-1552", + "sourceTag": "9.3-1612", "destImage": "node-v20-ubi9-minimal", - "nodeVersion": "20.11.1" - }, - { - "imageType": "liberty", - "sourceImage": "node-v18-ubi8-minimal", - "sourceTag": "18.19.1_8.9-1137", - "destImage": "liberty11-ubi8-minimal", - "libertyVersion": "24.0.0.1" - }, - { - "imageType": "liberty", - "sourceImage": "node-v18-ubi9-minimal", - "sourceTag": "18.19.1_9.3-1552", - "destImage": "liberty11-ubi9-minimal", - "libertyVersion": "24.0.0.1" + "nodeVersion": "20.12.0" } ] From ab882eed2f6d7c9ef735b4cddabbc1598a3bb97a Mon Sep 17 00:00:00 2001 From: Travis CI User Date: Wed, 3 Apr 2024 18:14:27 +0000 Subject: [PATCH 092/179] Trigger build with new base image --- base_images.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/base_images.json b/base_images.json index 616e9e47..0a881a8e 100644 --- a/base_images.json +++ b/base_images.json @@ -7,7 +7,7 @@ "destStage": "edge", "destNamespace": "build-images", "destImage": "ubi8", - "tag": "8.9-1136", + "tag": "8.9-1160", "updatePackages": [] }, { @@ -18,7 +18,7 @@ "destStage": "edge", "destNamespace": "build-images", "destImage": "ubi8-minimal", - "tag": "8.9-1137", + "tag": "8.9-1161", "updatePackages": [] }, { @@ -68,14 +68,14 @@ { "imageType": "node", "sourceImage": "ubi8-minimal", - "sourceTag": "8.9-1137", + "sourceTag": "8.9-1161", "destImage": "node-v18-ubi8-minimal", "nodeVersion": "18.20.0" }, { "imageType": "node", "sourceImage": "ubi8-minimal", - "sourceTag": "8.9-1137", + "sourceTag": "8.9-1161", "destImage": "node-v20-ubi8-minimal", "nodeVersion": "20.12.0" }, From 9feb27831201e28fa2d81a62b8ad4f6fb679c2a4 Mon Sep 17 00:00:00 2001 From: Daniel Fan Date: Thu, 4 Apr 2024 01:00:59 -0400 Subject: [PATCH 093/179] Improve UX experience for OperatorConfig (#1033) Signed-off-by: Daniel Fan --- api/v1alpha1/operatorconfig_types.go | 5 +++++ ...fecycle-manager.clusterserviceversion.yaml | 20 ++++++++++++++++--- .../operator.ibm.com_operatorconfigs.yaml | 17 ++++++++++++++-- .../operator.ibm.com_operatorconfigs.yaml | 17 ++++++++++++++-- ...fecycle-manager.clusterserviceversion.yaml | 6 ++++-- config/rbac/role.yaml | 14 +++++++++++++ 6 files changed, 70 insertions(+), 9 deletions(-) diff --git a/api/v1alpha1/operatorconfig_types.go b/api/v1alpha1/operatorconfig_types.go index a35494de..e2661d7d 100644 --- a/api/v1alpha1/operatorconfig_types.go +++ b/api/v1alpha1/operatorconfig_types.go @@ -67,6 +67,11 @@ type OperatorConfigStatus struct { //+kubebuilder:object:root=true //+kubebuilder:subresource:status +// +kubebuilder:resource:path=operatorconfigs,scope=Namespaced +// +kubebuilder:printcolumn:name="Age",type=date,JSONPath=.metadata.creationTimestamp +// +kubebuilder:printcolumn:name="Phase",type=string,JSONPath=.status.phase,description="Current Phase" +// +kubebuilder:printcolumn:name="Created At",type=string,JSONPath=.metadata.creationTimestamp +// +operator-sdk:csv:customresourcedefinitions:displayName="OperatorConfig" // OperatorConfig is the Schema for the operatorconfigs API. Documentation For additional details regarding install parameters check https://ibm.biz/icpfs39install. License By installing this product you accept the license terms https://ibm.biz/icpfs39license type OperatorConfig struct { diff --git a/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml b/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml index 745b750c..bbf94663 100644 --- a/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml +++ b/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml @@ -129,7 +129,7 @@ metadata: categories: Developer Tools, Monitoring, Logging & Tracing, Security certified: "false" containerImage: icr.io/cpopen/odlm:latest - createdAt: "2024-04-02T02:16:34Z" + createdAt: "2024-04-04T03:40:45Z" description: The Operand Deployment Lifecycle Manager provides a Kubernetes CRD-based API to manage the lifecycle of operands. nss.operator.ibm.com/managed-operators: ibm-odlm olm.skipRange: '>=1.2.0 <4.3.0' @@ -215,8 +215,8 @@ spec: x-descriptors: - urn:alm:descriptor:io.kubernetes.phase version: v1alpha1 - - description: OperatorConfig is the Schema for the operatorconfigs API - displayName: Operator Config + - description: OperatorConfig is the Schema for the operatorconfigs API. Documentation For additional details regarding install parameters check https://ibm.biz/icpfs39install. License By installing this product you accept the license terms https://ibm.biz/icpfs39license + displayName: OperatorConfig kind: OperatorConfig name: operatorconfigs.operator.ibm.com version: v1alpha1 @@ -716,6 +716,20 @@ spec: - patch - update - watch + - apiGroups: + - operator.ibm.com + resources: + - operandbindinfos + - operandbindinfos/finalizers + - operandbindinfos/status + verbs: + - create + - delete + - get + - list + - patch + - update + - watch - apiGroups: - operator.ibm.com resources: diff --git a/bundle/manifests/operator.ibm.com_operatorconfigs.yaml b/bundle/manifests/operator.ibm.com_operatorconfigs.yaml index b7329bbe..cb6bdfb9 100644 --- a/bundle/manifests/operator.ibm.com_operatorconfigs.yaml +++ b/bundle/manifests/operator.ibm.com_operatorconfigs.yaml @@ -18,10 +18,23 @@ spec: singular: operatorconfig scope: Namespaced versions: - - name: v1alpha1 + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + - description: Current Phase + jsonPath: .status.phase + name: Phase + type: string + - jsonPath: .metadata.creationTimestamp + name: Created At + type: string + name: v1alpha1 schema: openAPIV3Schema: - description: OperatorConfig is the Schema for the operatorconfigs API + description: OperatorConfig is the Schema for the operatorconfigs API. Documentation + For additional details regarding install parameters check https://ibm.biz/icpfs39install. + License By installing this product you accept the license terms https://ibm.biz/icpfs39license properties: apiVersion: description: |- diff --git a/config/crd/bases/operator.ibm.com_operatorconfigs.yaml b/config/crd/bases/operator.ibm.com_operatorconfigs.yaml index 5a8daa1c..168b1483 100644 --- a/config/crd/bases/operator.ibm.com_operatorconfigs.yaml +++ b/config/crd/bases/operator.ibm.com_operatorconfigs.yaml @@ -14,10 +14,23 @@ spec: singular: operatorconfig scope: Namespaced versions: - - name: v1alpha1 + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + - description: Current Phase + jsonPath: .status.phase + name: Phase + type: string + - jsonPath: .metadata.creationTimestamp + name: Created At + type: string + name: v1alpha1 schema: openAPIV3Schema: - description: OperatorConfig is the Schema for the operatorconfigs API + description: OperatorConfig is the Schema for the operatorconfigs API. Documentation + For additional details regarding install parameters check https://ibm.biz/icpfs39install. + License By installing this product you accept the license terms https://ibm.biz/icpfs39license properties: apiVersion: description: |- diff --git a/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml b/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml index 4a7f0229..b5821718 100644 --- a/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml +++ b/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml @@ -102,8 +102,10 @@ spec: x-descriptors: - urn:alm:descriptor:io.kubernetes.phase version: v1alpha1 - - description: OperatorConfig is the Schema for the operatorconfigs API - displayName: Operator Config + - description: OperatorConfig is the Schema for the operatorconfigs API. Documentation + For additional details regarding install parameters check https://ibm.biz/icpfs39install. + License By installing this product you accept the license terms https://ibm.biz/icpfs39license + displayName: OperatorConfig kind: OperatorConfig name: operatorconfigs.operator.ibm.com version: v1alpha1 diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml index bcc71a55..080d4471 100644 --- a/config/rbac/role.yaml +++ b/config/rbac/role.yaml @@ -65,6 +65,20 @@ rules: - patch - update - watch +- apiGroups: + - operator.ibm.com + resources: + - operandbindinfos + - operandbindinfos/finalizers + - operandbindinfos/status + verbs: + - create + - delete + - get + - list + - patch + - update + - watch - apiGroups: - operator.ibm.com resources: From 7fd4cfc7f5e066096f186bffe1c2181453924bd6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 4 Apr 2024 22:26:01 +0800 Subject: [PATCH 094/179] build(deps): bump golang from 1.22.1-bullseye to 1.22.2-bullseye (#1031) Bumps golang from 1.22.1-bullseye to 1.22.2-bullseye. --- updated-dependencies: - dependency-name: golang dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 2d70dc35..83854f41 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # Build the manager binary -FROM docker.io/golang:1.22.1-bullseye as builder +FROM docker.io/golang:1.22.2-bullseye as builder ARG GOARCH WORKDIR /workspace From 307337c59ba8eeca75d84815381a5bc546220dd0 Mon Sep 17 00:00:00 2001 From: Travis CI User Date: Thu, 4 Apr 2024 19:59:06 +0000 Subject: [PATCH 095/179] Trigger build with new base image --- base_images.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/base_images.json b/base_images.json index 0a881a8e..486a2d72 100644 --- a/base_images.json +++ b/base_images.json @@ -70,27 +70,27 @@ "sourceImage": "ubi8-minimal", "sourceTag": "8.9-1161", "destImage": "node-v18-ubi8-minimal", - "nodeVersion": "18.20.0" + "nodeVersion": "18.20.1" }, { "imageType": "node", "sourceImage": "ubi8-minimal", "sourceTag": "8.9-1161", "destImage": "node-v20-ubi8-minimal", - "nodeVersion": "20.12.0" + "nodeVersion": "20.12.1" }, { "imageType": "node", "sourceImage": "ubi9-minimal", "sourceTag": "9.3-1612", "destImage": "node-v18-ubi9-minimal", - "nodeVersion": "18.20.0" + "nodeVersion": "18.20.1" }, { "imageType": "node", "sourceImage": "ubi9-minimal", "sourceTag": "9.3-1612", "destImage": "node-v20-ubi9-minimal", - "nodeVersion": "20.12.0" + "nodeVersion": "20.12.1" } ] From 935adbb8829bb54ca22f58db3c316034173b1748 Mon Sep 17 00:00:00 2001 From: Daniel Fan Date: Fri, 5 Apr 2024 16:31:01 -0400 Subject: [PATCH 096/179] Update OperatorConfig reconciliation and improve error handling (#1034) * Update OperatorConfig reconciliation and improve error handling Signed-off-by: Daniel Fan * Requeue request every three hours for sync Signed-off-by: Daniel Fan * drop unnecessary else statement Signed-off-by: Daniel Fan --------- Signed-off-by: Daniel Fan --- controllers/operator/manager.go | 5 +++ .../operatorconfig_controller.go | 31 ++++++++++++++----- 2 files changed, 28 insertions(+), 8 deletions(-) diff --git a/controllers/operator/manager.go b/controllers/operator/manager.go index b6bd3500..f12fe7bb 100644 --- a/controllers/operator/manager.go +++ b/controllers/operator/manager.go @@ -392,6 +392,11 @@ func (m *ODLMOperator) GetSubscription(ctx context.Context, name, operatorNs, se // GetClusterServiceVersion gets the ClusterServiceVersion from the subscription func (m *ODLMOperator) GetClusterServiceVersion(ctx context.Context, sub *olmv1alpha1.Subscription) (*olmv1alpha1.ClusterServiceVersion, error) { + // Check if subscription is nil + if sub == nil { + klog.Error("The subscription is nil") + return nil, fmt.Errorf("the subscription is nil") + } // Check the ClusterServiceVersion status in the subscription if sub.Status.InstalledCSV == "" { klog.Warningf("The ClusterServiceVersion for Subscription %s is not ready. Will check it again", sub.Name) diff --git a/controllers/operatorconfig/operatorconfig_controller.go b/controllers/operatorconfig/operatorconfig_controller.go index 6a39383b..be180b1b 100644 --- a/controllers/operatorconfig/operatorconfig_controller.go +++ b/controllers/operatorconfig/operatorconfig_controller.go @@ -34,6 +34,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/source" operatorv1alpha1 "github.com/IBM/operand-deployment-lifecycle-manager/api/v1alpha1" + "github.com/IBM/operand-deployment-lifecycle-manager/controllers/constant" deploy "github.com/IBM/operand-deployment-lifecycle-manager/controllers/operator" ) @@ -73,19 +74,25 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu operand := u operator := registry.GetOperator(operand.Name) if operator.OperatorConfig == "" { - break + continue } var sub *olmv1alpha1.Subscription sub, err = r.GetSubscription(ctx, operator.Name, operator.Namespace, registry.Namespace, operator.PackageName) if err != nil { return ctrl.Result{}, err + } else if sub == nil { + klog.Infof("Subscription for Operator %s/%s not found", operator.Name, operator.PackageName) + return ctrl.Result{RequeueAfter: constant.DefaultRequeueDuration}, nil } var csv *olmv1alpha1.ClusterServiceVersion csv, err = r.GetClusterServiceVersion(ctx, sub) if err != nil { return ctrl.Result{}, err + } else if csv == nil { + klog.Infof("ClusterServiceVersion for Operator %s/%s not found", operator.Name, operator.PackageName) + return ctrl.Result{RequeueAfter: constant.DefaultRequeueDuration}, nil } klog.Infof("Fetching OperatorConfig: %s", operator.OperatorConfig) @@ -94,12 +101,16 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu Name: operator.OperatorConfig, Namespace: registry.Namespace, }, config); err != nil { - return ctrl.Result{}, client.IgnoreNotFound(err) + if client.IgnoreNotFound(err) != nil { + return ctrl.Result{}, err + } + klog.Infof("OperatorConfig %s/%s does not exist for operand %s in request %s, %s", registry.Namespace, operator.OperatorConfig, operator.Name, instance.Namespace, instance.Name) + continue } serviceConfig := config.GetConfigForOperator(operator.Name) if serviceConfig == nil { klog.Infof("OperatorConfig: %s, does not have configuration for operator: %s", operator.OperatorConfig, operator.Name) - return ctrl.Result{}, nil + continue } copyToCast, err := deepcopy.Anything(csv) @@ -108,13 +119,17 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu } csvToUpdate := copyToCast.(*olmv1alpha1.ClusterServiceVersion) klog.Infof("Applying OperatorConfig: %s to Operator: %s via CSV: %s, %s", operator.OperatorConfig, operator.Name, csv.Name, csv.Namespace) - return r.configCsv(ctx, csvToUpdate, serviceConfig) + if err := r.configCsv(ctx, csvToUpdate, serviceConfig); err != nil { + klog.Errorf("Failed to apply OperatorConfig %s/%s to Operator: %s via CSV: %s, %s", registry.Namespace, operator.OperatorConfig, operator.Name, csv.Namespace, csv.Name) + return ctrl.Result{}, err + } } } - return ctrl.Result{}, nil + klog.Infof("Finished reconciling OperatorConfig for request: %s, %s", instance.Namespace, instance.Name) + return ctrl.Result{RequeueAfter: constant.DefaultSyncPeriod}, nil } -func (r *Reconciler) configCsv(ctx context.Context, csv *olmv1alpha1.ClusterServiceVersion, config *operatorv1alpha1.ServiceOperatorConfig) (ctrl.Result, error) { +func (r *Reconciler) configCsv(ctx context.Context, csv *olmv1alpha1.ClusterServiceVersion, config *operatorv1alpha1.ServiceOperatorConfig) error { if config.Replicas != nil { csv.Spec.InstallStrategy.StrategySpec.DeploymentSpecs[0].Spec.Replicas = config.Replicas } @@ -125,9 +140,9 @@ func (r *Reconciler) configCsv(ctx context.Context, csv *olmv1alpha1.ClusterServ csv.Spec.InstallStrategy.StrategySpec.DeploymentSpecs[0].Spec.Template.Spec.TopologySpreadConstraints = config.TopologySpreadConstraints } if err := r.Client.Update(ctx, csv); err != nil { - return ctrl.Result{}, err + return err } - return ctrl.Result{}, nil + return nil } func (r *Reconciler) requestsFromMapFunc(ctx context.Context) handler.MapFunc { From 6ffbe24d25990b0b41f8ea7dea02bdea3771ea24 Mon Sep 17 00:00:00 2001 From: Daniel Fan Date: Sun, 14 Apr 2024 23:32:08 -0400 Subject: [PATCH 097/179] Set channel annotation for no-op equal to spec channel when spec channel is lower (#1035) Signed-off-by: Daniel Fan --- controllers/operandrequest/reconcile_operator.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/controllers/operandrequest/reconcile_operator.go b/controllers/operandrequest/reconcile_operator.go index 82d44b67..281654c8 100644 --- a/controllers/operandrequest/reconcile_operator.go +++ b/controllers/operandrequest/reconcile_operator.go @@ -220,8 +220,11 @@ func (r *Reconciler) reconcileSubscription(ctx context.Context, requestInstance requestInstance.SetNoSuitableRegistryCondition(registryKey.String(), opt.Name+" is in maintenance status", operatorv1alpha1.ResourceTypeOperandRegistry, corev1.ConditionTrue, &r.Mutex) requestInstance.SetMemberStatus(operand.Name, operatorv1alpha1.OperatorRunning, operatorv1alpha1.ServiceRunning, mu) - //set operator channel back to previous one if it is tombstone service - sub.Annotations[requestInstance.Namespace+"."+requestInstance.Name+"."+operand.Name+"/request"] = sub.Spec.Channel + // check if sub.Spec.Channel and opt.Channel are valid semantic version + // set annotation channel back to previous one if sub.Spec.Channel is lower than opt.Channel + if semver.IsValid(sub.Spec.Channel) && semver.IsValid(opt.Channel) && semver.Compare(sub.Spec.Channel, opt.Channel) < 0 { + sub.Annotations[requestInstance.Namespace+"."+requestInstance.Name+"."+operand.Name+"/request"] = sub.Spec.Channel + } } else { requestInstance.SetNotFoundOperatorFromRegistryCondition(operand.Name, operatorv1alpha1.ResourceTypeSub, corev1.ConditionFalse, mu) From b808aacf87082c1cb6eb8484a01d5130cd0e859d Mon Sep 17 00:00:00 2001 From: Daniel Fan Date: Mon, 22 Apr 2024 22:33:12 -0400 Subject: [PATCH 098/179] Bump version to 4.3.1 for 4.6.1 (#1038) Signed-off-by: Daniel Fan --- Makefile | 2 +- ...eployment-lifecycle-manager.clusterserviceversion.yaml | 8 ++++---- ...eployment-lifecycle-manager.clusterserviceversion.yaml | 4 ++-- controllers/operandbindinfo/operandbindinfo_controller.go | 2 +- version/version.go | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Makefile b/Makefile index fe7e856e..c83607d9 100644 --- a/Makefile +++ b/Makefile @@ -84,7 +84,7 @@ OPERATOR_IMAGE_NAME ?= odlm # Current Operator bundle image name BUNDLE_IMAGE_NAME ?= odlm-operator-bundle # Current Operator version -OPERATOR_VERSION ?= 4.3.0 +OPERATOR_VERSION ?= 4.3.1 # Kind cluster name KIND_CLUSTER_NAME ?= "odlm" diff --git a/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml b/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml index bbf94663..0eda067c 100644 --- a/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml +++ b/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml @@ -132,7 +132,7 @@ metadata: createdAt: "2024-04-04T03:40:45Z" description: The Operand Deployment Lifecycle Manager provides a Kubernetes CRD-based API to manage the lifecycle of operands. nss.operator.ibm.com/managed-operators: ibm-odlm - olm.skipRange: '>=1.2.0 <4.3.0' + olm.skipRange: '>=1.2.0 <4.3.1' operators.openshift.io/infrastructure-features: '["disconnected"]' operators.operatorframework.io/builder: operator-sdk-v1.32.0 operators.operatorframework.io/project_layout: go.kubebuilder.io/v3 @@ -143,7 +143,7 @@ metadata: operatorframework.io/arch.ppc64le: supported operatorframework.io/arch.s390x: supported operatorframework.io/os.linux: supported - name: operand-deployment-lifecycle-manager.v4.3.0 + name: operand-deployment-lifecycle-manager.v4.3.1 namespace: placeholder spec: apiservicedefinitions: {} @@ -860,7 +860,7 @@ spec: minKubeVersion: 1.19.0 provider: name: IBM - version: 4.3.0 + version: 4.3.1 relatedImages: - - image: icr.io/cpopen/odlm:4.3.0 + - image: icr.io/cpopen/odlm:4.3.1 name: ODLM_IMAGE diff --git a/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml b/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml index b5821718..070a2957 100644 --- a/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml +++ b/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml @@ -11,7 +11,7 @@ metadata: description: The Operand Deployment Lifecycle Manager provides a Kubernetes CRD-based API to manage the lifecycle of operands. nss.operator.ibm.com/managed-operators: ibm-odlm - olm.skipRange: '>=1.2.0 <4.3.0' + olm.skipRange: '>=1.2.0 <4.3.1' operators.openshift.io/infrastructure-features: '["disconnected"]' operators.operatorframework.io/builder: operator-sdk-v1.2.0 operators.operatorframework.io/project_layout: go.kubebuilder.io/v2 @@ -482,6 +482,6 @@ spec: provider: name: IBM relatedImages: - - image: icr.io/cpopen/odlm:4.3.0 + - image: icr.io/cpopen/odlm:4.3.1 name: ODLM_IMAGE version: 0.0.0 diff --git a/controllers/operandbindinfo/operandbindinfo_controller.go b/controllers/operandbindinfo/operandbindinfo_controller.go index 8e48fce3..40d4dd3a 100644 --- a/controllers/operandbindinfo/operandbindinfo_controller.go +++ b/controllers/operandbindinfo/operandbindinfo_controller.go @@ -100,7 +100,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctrl.Re klog.V(1).Infof("Reconciling OperandBindInfo: %s", req.NamespacedName) if isRouteAPI { - klog.Info("Route API enabled") + klog.V(2).Info("Route API enabled") } else { klog.Info("Route API disabled") } diff --git a/version/version.go b/version/version.go index d494af85..58d53ca2 100644 --- a/version/version.go +++ b/version/version.go @@ -17,5 +17,5 @@ package version var ( - Version = "4.3.0" + Version = "4.3.1" ) From 83e2a381faf6f0c9f15e8add4f7a706cc234fdc4 Mon Sep 17 00:00:00 2001 From: YuChen Shen <59578388+YCShen1010@users.noreply.github.com> Date: Mon, 22 Apr 2024 23:41:13 -0400 Subject: [PATCH 099/179] overwrite the array in deep merge logic (#1037) Signed-off-by: YuChen --- controllers/util/merge.go | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/controllers/util/merge.go b/controllers/util/merge.go index 0a8a5635..fc3b83c3 100644 --- a/controllers/util/merge.go +++ b/controllers/util/merge.go @@ -80,10 +80,7 @@ func checkKeyBeforeMerging(key string, defaultMap interface{}, changedMap interf changedMapRef := changedMap.([]interface{}) for i := range defaultMapRef { if _, ok := defaultMapRef[i].(map[string]interface{}); ok { - if len(changedMapRef) <= i { - finalMap[key] = append(finalMap[key].([]interface{}), defaultMapRef[i]) - } else { - + if len(changedMapRef) > i { for newKey := range defaultMapRef[i].(map[string]interface{}) { checkKeyBeforeMerging(newKey, defaultMapRef[i].(map[string]interface{})[newKey], changedMapRef[i].(map[string]interface{})[newKey], finalMap[key].([]interface{})[i].(map[string]interface{})) } From a60f12c45fd2bac7f200542e9052d5cece7210c9 Mon Sep 17 00:00:00 2001 From: Adam Shank <42580017+ashank07@users.noreply.github.com> Date: Wed, 24 Apr 2024 14:40:44 -0400 Subject: [PATCH 100/179] Retrigger build after prow fix --- triggerfile | 1 + 1 file changed, 1 insertion(+) create mode 100644 triggerfile diff --git a/triggerfile b/triggerfile new file mode 100644 index 00000000..03e90c99 --- /dev/null +++ b/triggerfile @@ -0,0 +1 @@ +20240424-1440 From 480bca5a77c1f48868a7442f757c76ee025d3da4 Mon Sep 17 00:00:00 2001 From: Travis CI User Date: Fri, 26 Apr 2024 17:04:43 +0000 Subject: [PATCH 101/179] Trigger build with new base image --- base_images.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/base_images.json b/base_images.json index 486a2d72..57096b34 100644 --- a/base_images.json +++ b/base_images.json @@ -70,27 +70,27 @@ "sourceImage": "ubi8-minimal", "sourceTag": "8.9-1161", "destImage": "node-v18-ubi8-minimal", - "nodeVersion": "18.20.1" + "nodeVersion": "18.20.2" }, { "imageType": "node", "sourceImage": "ubi8-minimal", "sourceTag": "8.9-1161", "destImage": "node-v20-ubi8-minimal", - "nodeVersion": "20.12.1" + "nodeVersion": "20.12.2" }, { "imageType": "node", "sourceImage": "ubi9-minimal", "sourceTag": "9.3-1612", "destImage": "node-v18-ubi9-minimal", - "nodeVersion": "18.20.1" + "nodeVersion": "18.20.2" }, { "imageType": "node", "sourceImage": "ubi9-minimal", "sourceTag": "9.3-1612", "destImage": "node-v20-ubi9-minimal", - "nodeVersion": "20.12.1" + "nodeVersion": "20.12.2" } ] From b053b5d4c4b3566d2314101dc6825596187e5760 Mon Sep 17 00:00:00 2001 From: Daniel Fan Date: Mon, 29 Apr 2024 23:28:23 -0400 Subject: [PATCH 102/179] remove discontinued quay configuration (#1042) Signed-off-by: Daniel Fan --- Makefile | 1 - common/Makefile.common.mk | 3 --- common/scripts/quay_config_docker.sh | 28 ---------------------------- 3 files changed, 32 deletions(-) delete mode 100755 common/scripts/quay_config_docker.sh diff --git a/Makefile b/Makefile index c83607d9..25ed9673 100644 --- a/Makefile +++ b/Makefile @@ -109,7 +109,6 @@ endif ifeq ($(BUILD_LOCALLY),0) export CONFIG_DOCKER_TARGET = config-docker - export CONFIG_DOCKER_TARGET_QUAY = config-docker-quay endif include common/Makefile.common.mk diff --git a/common/Makefile.common.mk b/common/Makefile.common.mk index 50fe01ed..b7c20102 100644 --- a/common/Makefile.common.mk +++ b/common/Makefile.common.mk @@ -39,9 +39,6 @@ endif config-docker: get-cluster-credentials @common/scripts/artifactory_config_docker.sh -config-docker-quay: get-cluster-credentials - @common/scripts/quay_config_docker.sh - # find or download operator-sdk # download operator-sdk if necessary operator-sdk: diff --git a/common/scripts/quay_config_docker.sh b/common/scripts/quay_config_docker.sh deleted file mode 100755 index bea1ee9a..00000000 --- a/common/scripts/quay_config_docker.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/bash -# -# Copyright 2022 IBM Corporation -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -KUBECTL=$(command -v kubectl) -DOCKER_REGISTRY="quay.io" -DOCKER_USERNAME="multicloudlab" -DOCKER_PASSWORD=$(${KUBECTL} -n default get secret quay-cred -o jsonpath='{.data.password}' | base64 --decode) - -# support other container tools, e.g. podman -CONTAINER_CLI=${CONTAINER_CLI:-docker} - -# login the docker registry -${CONTAINER_CLI} login "${DOCKER_REGISTRY}" -u "${DOCKER_USERNAME}" -p "${DOCKER_PASSWORD}" - From 3705eadbafe69c1a0e9741ec0e4b32eb8051742e Mon Sep 17 00:00:00 2001 From: Daniel Fan Date: Mon, 29 Apr 2024 23:40:18 -0400 Subject: [PATCH 103/179] Fix nil pointer issue when operator is not found in OperandRegistry (#1040) Signed-off-by: Daniel Fan --- .../operatorconfig/operatorconfig_controller.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/controllers/operatorconfig/operatorconfig_controller.go b/controllers/operatorconfig/operatorconfig_controller.go index be180b1b..cd30e196 100644 --- a/controllers/operatorconfig/operatorconfig_controller.go +++ b/controllers/operatorconfig/operatorconfig_controller.go @@ -62,7 +62,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu return ctrl.Result{}, client.IgnoreNotFound(err) } - klog.Infof("Reconciling OperatorConfig for request: %s, %s", instance.Namespace, instance.Name) + klog.Infof("Reconciling OperatorConfig for OperandRequest: %s/%s", instance.Namespace, instance.Name) for _, v := range instance.Spec.Requests { reqBlock := v @@ -73,7 +73,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu for _, u := range reqBlock.Operands { operand := u operator := registry.GetOperator(operand.Name) - if operator.OperatorConfig == "" { + if operator == nil || operator.OperatorConfig == "" { continue } @@ -104,12 +104,12 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu if client.IgnoreNotFound(err) != nil { return ctrl.Result{}, err } - klog.Infof("OperatorConfig %s/%s does not exist for operand %s in request %s, %s", registry.Namespace, operator.OperatorConfig, operator.Name, instance.Namespace, instance.Name) + klog.Infof("OperatorConfig %s/%s does not exist for operand %s in OperandRequest %s/%s", registry.Namespace, operator.OperatorConfig, operator.Name, instance.Namespace, instance.Name) continue } serviceConfig := config.GetConfigForOperator(operator.Name) if serviceConfig == nil { - klog.Infof("OperatorConfig: %s, does not have configuration for operator: %s", operator.OperatorConfig, operator.Name) + klog.Infof("OperatorConfig %s does not have configuration for operator: %s", operator.OperatorConfig, operator.Name) continue } @@ -125,7 +125,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu } } } - klog.Infof("Finished reconciling OperatorConfig for request: %s, %s", instance.Namespace, instance.Name) + klog.Infof("Finished reconciling OperatorConfig for OperandRequest %s/%s", instance.Namespace, instance.Name) return ctrl.Result{RequeueAfter: constant.DefaultSyncPeriod}, nil } From 00b22c215a9d9c5d7bd7ed48278c4534c05e43f5 Mon Sep 17 00:00:00 2001 From: Ben Luzarraga <31223504+bluzarraga@users.noreply.github.com> Date: Wed, 1 May 2024 10:45:20 -0500 Subject: [PATCH 104/179] Update pkgs for security vulnerabilities for 4.6.2 (#1043) * update net package for twistlock Signed-off-by: Ben Luzarraga * update apimachinery for whitesource Signed-off-by: Ben Luzarraga * update controller runtime Signed-off-by: Ben Luzarraga * change controller runtime versions Signed-off-by: Ben Luzarraga * revert to 24.17 Signed-off-by: Ben Luzarraga --------- Signed-off-by: Ben Luzarraga --- go.mod | 14 +++++++------- go.sum | 22 ++++++++++++---------- 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/go.mod b/go.mod index fdda194f..d61cf275 100644 --- a/go.mod +++ b/go.mod @@ -20,8 +20,7 @@ require ( github.com/stretchr/testify v1.9.0 golang.org/x/mod v0.8.0 k8s.io/api v0.24.3 - k8s.io/apiextensions-apiserver v0.24.2 - k8s.io/apimachinery v0.24.3 + k8s.io/apimachinery v0.24.17 k8s.io/client-go v0.24.3 k8s.io/klog v1.0.0 k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9 @@ -86,11 +85,11 @@ require ( go.uber.org/atomic v1.7.0 // indirect go.uber.org/multierr v1.6.0 // indirect go.uber.org/zap v1.19.1 // indirect - golang.org/x/net v0.17.0 // indirect + golang.org/x/net v0.23.0 // indirect golang.org/x/oauth2 v0.11.0 // indirect - golang.org/x/sys v0.13.0 // indirect - golang.org/x/term v0.13.0 // indirect - golang.org/x/text v0.13.0 // indirect + golang.org/x/sys v0.18.0 // indirect + golang.org/x/term v0.18.0 // indirect + golang.org/x/text v0.14.0 // indirect golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect google.golang.org/appengine v1.6.7 // indirect @@ -102,11 +101,12 @@ require ( gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect + k8s.io/apiextensions-apiserver v0.24.2 // indirect k8s.io/component-base v0.24.2 // indirect k8s.io/klog/v2 v2.60.1 // indirect k8s.io/kube-openapi v0.0.0-20220627174259-011e075b9cb8 // indirect sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2 // indirect - sigs.k8s.io/structured-merge-diff/v4 v4.2.1 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect sigs.k8s.io/yaml v1.3.0 // indirect ) diff --git a/go.sum b/go.sum index a02dea1d..c17e0561 100644 --- a/go.sum +++ b/go.sum @@ -1166,8 +1166,8 @@ golang.org/x/net v0.0.0-20210825183410-e898025ed96a/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= -golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= +golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1291,12 +1291,12 @@ golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= -golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= +golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek= -golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= +golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8= +golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1307,8 +1307,8 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= -golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -1620,8 +1620,9 @@ k8s.io/apimachinery v0.18.9/go.mod h1:PF5taHbXgTEJLU+xMypMmYTXTWPJ5LaW8bfsisxnEX k8s.io/apimachinery v0.20.1/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= k8s.io/apimachinery v0.23.0/go.mod h1:fFCTTBKvKcwTPFzjlcxp91uPFZr+JA0FubU4fLzzFYc= k8s.io/apimachinery v0.24.2/go.mod h1:82Bi4sCzVBdpYjyI4jY6aHX+YCUchUIrZrXKedjd2UM= -k8s.io/apimachinery v0.24.3 h1:hrFiNSA2cBZqllakVYyH/VyEh4B581bQRmqATJSeQTg= k8s.io/apimachinery v0.24.3/go.mod h1:82Bi4sCzVBdpYjyI4jY6aHX+YCUchUIrZrXKedjd2UM= +k8s.io/apimachinery v0.24.17 h1:mewWCeZ3Swr4EAfatVAhHXJHGzCHojphWA/5UJW4pPY= +k8s.io/apimachinery v0.24.17/go.mod h1:kSzhCwldu9XB172NDdLffRN0sJ3x95RR7Bmyc4SHhs0= k8s.io/apiserver v0.17.2/go.mod h1:lBmw/TtQdtxvrTk0e2cgtOxHizXI+d0mmGQURIHQZlo= k8s.io/apiserver v0.18.2/go.mod h1:Xbh066NqrZO8cbsoenCwyDJ1OSi8Ag8I2lezeHxzwzw= k8s.io/apiserver v0.18.9/go.mod h1:vXQzMtUCLsGg1Bh+7Jo2mZKHpHZFCZn8eTNSepcIA1M= @@ -1721,8 +1722,9 @@ sigs.k8s.io/structured-merge-diff/v3 v3.0.0-20200116222232-67a7b8c61874/go.mod h sigs.k8s.io/structured-merge-diff/v3 v3.0.0/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= sigs.k8s.io/structured-merge-diff/v4 v4.1.2/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= -sigs.k8s.io/structured-merge-diff/v4 v4.2.1 h1:bKCqE9GvQ5tiVHn5rfn1r+yao3aLQEaLzkkmAkf+A6Y= sigs.k8s.io/structured-merge-diff/v4 v4.2.1/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= +sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE= +sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= From b3ed4f6f1805060ac572d9d26a29ab2991529ea2 Mon Sep 17 00:00:00 2001 From: Daniel Fan Date: Fri, 3 May 2024 14:24:21 -0400 Subject: [PATCH 105/179] Update ODLM module to match major version v4 (#1039) Signed-off-by: Daniel Fan --- PROJECT | 10 ++++---- .../namespacescope_controler_test.go | 6 ++--- .../namespacescope_controller.go | 8 +++---- .../namespacescope_suite_test.go | 8 +++---- .../operandbindinfo_controller.go | 8 +++---- .../operandbindinfo_controller_test.go | 4 ++-- .../operandbindinfo_suite_test.go | 8 +++---- .../operandconfig/operandconfig_controller.go | 8 +++---- .../operandconfig_controller_test.go | 4 ++-- .../operandconfig/operandconfig_suite_test.go | 8 +++---- .../operandregistry_controller.go | 4 ++-- .../operandregistry_controller_test.go | 4 ++-- .../operandregistry_suite_test.go | 8 +++---- .../operandrequest_controller.go | 6 ++--- .../operandrequest_controller_test.go | 4 ++-- .../operandrequest_suite_test.go | 4 ++-- .../operandrequest/reconcile_operand.go | 6 ++--- .../operandrequest/reconcile_operand_test.go | 4 ++-- .../operandrequest/reconcile_operator.go | 6 ++--- .../operandrequest/reconcile_operator_test.go | 2 +- controllers/operator/manager.go | 6 ++--- .../operatorchecker_controller.go | 4 ++-- .../operatorconfig_controller.go | 6 ++--- .../operatorconfig_suite_test.go | 2 +- controllers/testutil/test_util.go | 4 ++-- go.mod | 2 +- main.go | 24 +++++++++---------- test/e2e/helpers_test.go | 2 +- test/e2e/odlm_test.go | 2 +- test/e2e/utils_test.go | 2 +- 30 files changed, 87 insertions(+), 87 deletions(-) diff --git a/PROJECT b/PROJECT index faf71aed..a0883df7 100644 --- a/PROJECT +++ b/PROJECT @@ -15,25 +15,25 @@ resources: domain: ibm.com group: operator kind: OperandRequest - path: github.com/IBM/operand-deployment-lifecycle-manager/api/v1alpha1 + path: github.com/IBM/operand-deployment-lifecycle-manager/v4/api/v1alpha1 version: v1alpha1 - controller: true domain: ibm.com group: operator kind: OperandRegistry - path: github.com/IBM/operand-deployment-lifecycle-manager/api/v1alpha1 + path: github.com/IBM/operand-deployment-lifecycle-manager/v4/api/v1alpha1 version: v1alpha1 - controller: true domain: ibm.com group: operator kind: OperandConfig - path: github.com/IBM/operand-deployment-lifecycle-manager/api/v1alpha1 + path: github.com/IBM/operand-deployment-lifecycle-manager/v4/api/v1alpha1 version: v1alpha1 - controller: true domain: ibm.com group: operator kind: OperandBindInfo - path: github.com/IBM/operand-deployment-lifecycle-manager/api/v1alpha1 + path: github.com/IBM/operand-deployment-lifecycle-manager/v4/api/v1alpha1 version: v1alpha1 - api: crdVersion: v1 @@ -42,6 +42,6 @@ resources: domain: ibm.com group: operator kind: OperatorConfig - path: github.com/IBM/operand-deployment-lifecycle-manager/api/v1alpha1 + path: github.com/IBM/operand-deployment-lifecycle-manager/v4/api/v1alpha1 version: v1alpha1 version: "3" diff --git a/controllers/namespacescope/namespacescope_controler_test.go b/controllers/namespacescope/namespacescope_controler_test.go index f5893096..6be317e9 100644 --- a/controllers/namespacescope/namespacescope_controler_test.go +++ b/controllers/namespacescope/namespacescope_controler_test.go @@ -25,9 +25,9 @@ import ( nssv1 "github.com/IBM/ibm-namespace-scope-operator/api/v1" - operatorv1alpha1 "github.com/IBM/operand-deployment-lifecycle-manager/api/v1alpha1" - "github.com/IBM/operand-deployment-lifecycle-manager/controllers/constant" - "github.com/IBM/operand-deployment-lifecycle-manager/controllers/testutil" + operatorv1alpha1 "github.com/IBM/operand-deployment-lifecycle-manager/v4/api/v1alpha1" + "github.com/IBM/operand-deployment-lifecycle-manager/v4/controllers/constant" + "github.com/IBM/operand-deployment-lifecycle-manager/v4/controllers/testutil" ) // +kubebuilder:docs-gen:collapse=Imports diff --git a/controllers/namespacescope/namespacescope_controller.go b/controllers/namespacescope/namespacescope_controller.go index 72fffdac..6d34e4f0 100644 --- a/controllers/namespacescope/namespacescope_controller.go +++ b/controllers/namespacescope/namespacescope_controller.go @@ -33,10 +33,10 @@ import ( nssv1 "github.com/IBM/ibm-namespace-scope-operator/api/v1" - operatorv1alpha1 "github.com/IBM/operand-deployment-lifecycle-manager/api/v1alpha1" - "github.com/IBM/operand-deployment-lifecycle-manager/controllers/constant" - deploy "github.com/IBM/operand-deployment-lifecycle-manager/controllers/operator" - "github.com/IBM/operand-deployment-lifecycle-manager/controllers/util" + operatorv1alpha1 "github.com/IBM/operand-deployment-lifecycle-manager/v4/api/v1alpha1" + "github.com/IBM/operand-deployment-lifecycle-manager/v4/controllers/constant" + deploy "github.com/IBM/operand-deployment-lifecycle-manager/v4/controllers/operator" + "github.com/IBM/operand-deployment-lifecycle-manager/v4/controllers/util" ) var ( diff --git a/controllers/namespacescope/namespacescope_suite_test.go b/controllers/namespacescope/namespacescope_suite_test.go index 652d0cc9..fe72a86a 100644 --- a/controllers/namespacescope/namespacescope_suite_test.go +++ b/controllers/namespacescope/namespacescope_suite_test.go @@ -38,10 +38,10 @@ import ( nssv1 "github.com/IBM/ibm-namespace-scope-operator/api/v1" - apiv1alpha1 "github.com/IBM/operand-deployment-lifecycle-manager/api/v1alpha1" - "github.com/IBM/operand-deployment-lifecycle-manager/controllers/operandregistry" - "github.com/IBM/operand-deployment-lifecycle-manager/controllers/operandrequest" - deploy "github.com/IBM/operand-deployment-lifecycle-manager/controllers/operator" + apiv1alpha1 "github.com/IBM/operand-deployment-lifecycle-manager/v4/api/v1alpha1" + "github.com/IBM/operand-deployment-lifecycle-manager/v4/controllers/operandregistry" + "github.com/IBM/operand-deployment-lifecycle-manager/v4/controllers/operandrequest" + deploy "github.com/IBM/operand-deployment-lifecycle-manager/v4/controllers/operator" // +kubebuilder:scaffold:imports ) diff --git a/controllers/operandbindinfo/operandbindinfo_controller.go b/controllers/operandbindinfo/operandbindinfo_controller.go index 40d4dd3a..41e54892 100644 --- a/controllers/operandbindinfo/operandbindinfo_controller.go +++ b/controllers/operandbindinfo/operandbindinfo_controller.go @@ -50,10 +50,10 @@ import ( "sigs.k8s.io/controller-runtime/pkg/reconcile" "sigs.k8s.io/controller-runtime/pkg/source" - operatorv1alpha1 "github.com/IBM/operand-deployment-lifecycle-manager/api/v1alpha1" - "github.com/IBM/operand-deployment-lifecycle-manager/controllers/constant" - deploy "github.com/IBM/operand-deployment-lifecycle-manager/controllers/operator" - "github.com/IBM/operand-deployment-lifecycle-manager/controllers/util" + operatorv1alpha1 "github.com/IBM/operand-deployment-lifecycle-manager/v4/api/v1alpha1" + "github.com/IBM/operand-deployment-lifecycle-manager/v4/controllers/constant" + deploy "github.com/IBM/operand-deployment-lifecycle-manager/v4/controllers/operator" + "github.com/IBM/operand-deployment-lifecycle-manager/v4/controllers/util" ) // Reconciler reconciles a OperandBindInfo object diff --git a/controllers/operandbindinfo/operandbindinfo_controller_test.go b/controllers/operandbindinfo/operandbindinfo_controller_test.go index c8d94f98..493f2eca 100644 --- a/controllers/operandbindinfo/operandbindinfo_controller_test.go +++ b/controllers/operandbindinfo/operandbindinfo_controller_test.go @@ -25,8 +25,8 @@ import ( "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/types" - operatorv1alpha1 "github.com/IBM/operand-deployment-lifecycle-manager/api/v1alpha1" - "github.com/IBM/operand-deployment-lifecycle-manager/controllers/testutil" + operatorv1alpha1 "github.com/IBM/operand-deployment-lifecycle-manager/v4/api/v1alpha1" + "github.com/IBM/operand-deployment-lifecycle-manager/v4/controllers/testutil" ) // +kubebuilder:docs-gen:collapse=Imports diff --git a/controllers/operandbindinfo/operandbindinfo_suite_test.go b/controllers/operandbindinfo/operandbindinfo_suite_test.go index d9c26cbe..25937857 100644 --- a/controllers/operandbindinfo/operandbindinfo_suite_test.go +++ b/controllers/operandbindinfo/operandbindinfo_suite_test.go @@ -37,10 +37,10 @@ import ( "sigs.k8s.io/controller-runtime/pkg/log/zap" nssv1 "github.com/IBM/ibm-namespace-scope-operator/api/v1" - apiv1alpha1 "github.com/IBM/operand-deployment-lifecycle-manager/api/v1alpha1" - "github.com/IBM/operand-deployment-lifecycle-manager/controllers/operandregistry" - "github.com/IBM/operand-deployment-lifecycle-manager/controllers/operandrequest" - deploy "github.com/IBM/operand-deployment-lifecycle-manager/controllers/operator" + apiv1alpha1 "github.com/IBM/operand-deployment-lifecycle-manager/v4/api/v1alpha1" + "github.com/IBM/operand-deployment-lifecycle-manager/v4/controllers/operandregistry" + "github.com/IBM/operand-deployment-lifecycle-manager/v4/controllers/operandrequest" + deploy "github.com/IBM/operand-deployment-lifecycle-manager/v4/controllers/operator" // +kubebuilder:scaffold:imports ) diff --git a/controllers/operandconfig/operandconfig_controller.go b/controllers/operandconfig/operandconfig_controller.go index df384921..52824ac1 100644 --- a/controllers/operandconfig/operandconfig_controller.go +++ b/controllers/operandconfig/operandconfig_controller.go @@ -43,10 +43,10 @@ import ( "sigs.k8s.io/controller-runtime/pkg/reconcile" "sigs.k8s.io/controller-runtime/pkg/source" - operatorv1alpha1 "github.com/IBM/operand-deployment-lifecycle-manager/api/v1alpha1" - "github.com/IBM/operand-deployment-lifecycle-manager/controllers/constant" - deploy "github.com/IBM/operand-deployment-lifecycle-manager/controllers/operator" - "github.com/IBM/operand-deployment-lifecycle-manager/controllers/util" + operatorv1alpha1 "github.com/IBM/operand-deployment-lifecycle-manager/v4/api/v1alpha1" + "github.com/IBM/operand-deployment-lifecycle-manager/v4/controllers/constant" + deploy "github.com/IBM/operand-deployment-lifecycle-manager/v4/controllers/operator" + "github.com/IBM/operand-deployment-lifecycle-manager/v4/controllers/util" ) // Reconciler reconciles a OperandConfig object diff --git a/controllers/operandconfig/operandconfig_controller_test.go b/controllers/operandconfig/operandconfig_controller_test.go index cd2ecb6f..21b113f4 100644 --- a/controllers/operandconfig/operandconfig_controller_test.go +++ b/controllers/operandconfig/operandconfig_controller_test.go @@ -24,8 +24,8 @@ import ( olmv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1" "k8s.io/apimachinery/pkg/types" - operatorv1alpha1 "github.com/IBM/operand-deployment-lifecycle-manager/api/v1alpha1" - testutil "github.com/IBM/operand-deployment-lifecycle-manager/controllers/testutil" + operatorv1alpha1 "github.com/IBM/operand-deployment-lifecycle-manager/v4/api/v1alpha1" + testutil "github.com/IBM/operand-deployment-lifecycle-manager/v4/controllers/testutil" ) // +kubebuilder:docs-gen:collapse=Imports diff --git a/controllers/operandconfig/operandconfig_suite_test.go b/controllers/operandconfig/operandconfig_suite_test.go index 1a6913c3..73605ab2 100644 --- a/controllers/operandconfig/operandconfig_suite_test.go +++ b/controllers/operandconfig/operandconfig_suite_test.go @@ -38,10 +38,10 @@ import ( nssv1 "github.com/IBM/ibm-namespace-scope-operator/api/v1" - apiv1alpha1 "github.com/IBM/operand-deployment-lifecycle-manager/api/v1alpha1" - "github.com/IBM/operand-deployment-lifecycle-manager/controllers/operandregistry" - "github.com/IBM/operand-deployment-lifecycle-manager/controllers/operandrequest" - deploy "github.com/IBM/operand-deployment-lifecycle-manager/controllers/operator" + apiv1alpha1 "github.com/IBM/operand-deployment-lifecycle-manager/v4/api/v1alpha1" + "github.com/IBM/operand-deployment-lifecycle-manager/v4/controllers/operandregistry" + "github.com/IBM/operand-deployment-lifecycle-manager/v4/controllers/operandrequest" + deploy "github.com/IBM/operand-deployment-lifecycle-manager/v4/controllers/operator" // +kubebuilder:scaffold:imports ) diff --git a/controllers/operandregistry/operandregistry_controller.go b/controllers/operandregistry/operandregistry_controller.go index e8040988..6f572c52 100644 --- a/controllers/operandregistry/operandregistry_controller.go +++ b/controllers/operandregistry/operandregistry_controller.go @@ -34,8 +34,8 @@ import ( "sigs.k8s.io/controller-runtime/pkg/reconcile" "sigs.k8s.io/controller-runtime/pkg/source" - operatorv1alpha1 "github.com/IBM/operand-deployment-lifecycle-manager/api/v1alpha1" - deploy "github.com/IBM/operand-deployment-lifecycle-manager/controllers/operator" + operatorv1alpha1 "github.com/IBM/operand-deployment-lifecycle-manager/v4/api/v1alpha1" + deploy "github.com/IBM/operand-deployment-lifecycle-manager/v4/controllers/operator" ) // Reconciler reconciles a OperandRegistry object diff --git a/controllers/operandregistry/operandregistry_controller_test.go b/controllers/operandregistry/operandregistry_controller_test.go index d655b336..3a075e91 100644 --- a/controllers/operandregistry/operandregistry_controller_test.go +++ b/controllers/operandregistry/operandregistry_controller_test.go @@ -24,8 +24,8 @@ import ( olmv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1" "k8s.io/apimachinery/pkg/types" - operatorv1alpha1 "github.com/IBM/operand-deployment-lifecycle-manager/api/v1alpha1" - "github.com/IBM/operand-deployment-lifecycle-manager/controllers/testutil" + operatorv1alpha1 "github.com/IBM/operand-deployment-lifecycle-manager/v4/api/v1alpha1" + "github.com/IBM/operand-deployment-lifecycle-manager/v4/controllers/testutil" ) // +kubebuilder:docs-gen:collapse=Imports diff --git a/controllers/operandregistry/operandregistry_suite_test.go b/controllers/operandregistry/operandregistry_suite_test.go index 04582485..61a80623 100644 --- a/controllers/operandregistry/operandregistry_suite_test.go +++ b/controllers/operandregistry/operandregistry_suite_test.go @@ -37,10 +37,10 @@ import ( "sigs.k8s.io/controller-runtime/pkg/log/zap" nssv1 "github.com/IBM/ibm-namespace-scope-operator/api/v1" - apiv1alpha1 "github.com/IBM/operand-deployment-lifecycle-manager/api/v1alpha1" - "github.com/IBM/operand-deployment-lifecycle-manager/controllers/operandconfig" - "github.com/IBM/operand-deployment-lifecycle-manager/controllers/operandrequest" - deploy "github.com/IBM/operand-deployment-lifecycle-manager/controllers/operator" + apiv1alpha1 "github.com/IBM/operand-deployment-lifecycle-manager/v4/api/v1alpha1" + "github.com/IBM/operand-deployment-lifecycle-manager/v4/controllers/operandconfig" + "github.com/IBM/operand-deployment-lifecycle-manager/v4/controllers/operandrequest" + deploy "github.com/IBM/operand-deployment-lifecycle-manager/v4/controllers/operator" // +kubebuilder:scaffold:imports ) diff --git a/controllers/operandrequest/operandrequest_controller.go b/controllers/operandrequest/operandrequest_controller.go index 9a4be9fc..b9b2c69c 100644 --- a/controllers/operandrequest/operandrequest_controller.go +++ b/controllers/operandrequest/operandrequest_controller.go @@ -44,9 +44,9 @@ import ( "sigs.k8s.io/controller-runtime/pkg/predicate" "sigs.k8s.io/controller-runtime/pkg/source" - operatorv1alpha1 "github.com/IBM/operand-deployment-lifecycle-manager/api/v1alpha1" - "github.com/IBM/operand-deployment-lifecycle-manager/controllers/constant" - deploy "github.com/IBM/operand-deployment-lifecycle-manager/controllers/operator" + operatorv1alpha1 "github.com/IBM/operand-deployment-lifecycle-manager/v4/api/v1alpha1" + "github.com/IBM/operand-deployment-lifecycle-manager/v4/controllers/constant" + deploy "github.com/IBM/operand-deployment-lifecycle-manager/v4/controllers/operator" ) // Reconciler reconciles a OperandRequest object diff --git a/controllers/operandrequest/operandrequest_controller_test.go b/controllers/operandrequest/operandrequest_controller_test.go index a9af6751..5b36c35a 100644 --- a/controllers/operandrequest/operandrequest_controller_test.go +++ b/controllers/operandrequest/operandrequest_controller_test.go @@ -30,8 +30,8 @@ import ( "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/types" - operatorv1alpha1 "github.com/IBM/operand-deployment-lifecycle-manager/api/v1alpha1" - "github.com/IBM/operand-deployment-lifecycle-manager/controllers/testutil" + operatorv1alpha1 "github.com/IBM/operand-deployment-lifecycle-manager/v4/api/v1alpha1" + "github.com/IBM/operand-deployment-lifecycle-manager/v4/controllers/testutil" ) // +kubebuilder:docs-gen:collapse=Imports diff --git a/controllers/operandrequest/operandrequest_suite_test.go b/controllers/operandrequest/operandrequest_suite_test.go index 33353453..db44144c 100644 --- a/controllers/operandrequest/operandrequest_suite_test.go +++ b/controllers/operandrequest/operandrequest_suite_test.go @@ -37,8 +37,8 @@ import ( "sigs.k8s.io/controller-runtime/pkg/log/zap" nssv1 "github.com/IBM/ibm-namespace-scope-operator/api/v1" - apiv1alpha1 "github.com/IBM/operand-deployment-lifecycle-manager/api/v1alpha1" - deploy "github.com/IBM/operand-deployment-lifecycle-manager/controllers/operator" + apiv1alpha1 "github.com/IBM/operand-deployment-lifecycle-manager/v4/api/v1alpha1" + deploy "github.com/IBM/operand-deployment-lifecycle-manager/v4/controllers/operator" // +kubebuilder:scaffold:imports ) diff --git a/controllers/operandrequest/reconcile_operand.go b/controllers/operandrequest/reconcile_operand.go index bdc94868..7249f2b8 100644 --- a/controllers/operandrequest/reconcile_operand.go +++ b/controllers/operandrequest/reconcile_operand.go @@ -46,9 +46,9 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" - operatorv1alpha1 "github.com/IBM/operand-deployment-lifecycle-manager/api/v1alpha1" - constant "github.com/IBM/operand-deployment-lifecycle-manager/controllers/constant" - util "github.com/IBM/operand-deployment-lifecycle-manager/controllers/util" + operatorv1alpha1 "github.com/IBM/operand-deployment-lifecycle-manager/v4/api/v1alpha1" + constant "github.com/IBM/operand-deployment-lifecycle-manager/v4/controllers/constant" + util "github.com/IBM/operand-deployment-lifecycle-manager/v4/controllers/util" ) func (r *Reconciler) reconcileOperand(ctx context.Context, requestInstance *operatorv1alpha1.OperandRequest) *util.MultiErr { diff --git a/controllers/operandrequest/reconcile_operand_test.go b/controllers/operandrequest/reconcile_operand_test.go index 408408c6..69bf5ac6 100644 --- a/controllers/operandrequest/reconcile_operand_test.go +++ b/controllers/operandrequest/reconcile_operand_test.go @@ -29,8 +29,8 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client/fake" - operatorv1alpha1 "github.com/IBM/operand-deployment-lifecycle-manager/api/v1alpha1" - deploy "github.com/IBM/operand-deployment-lifecycle-manager/controllers/operator" + operatorv1alpha1 "github.com/IBM/operand-deployment-lifecycle-manager/v4/api/v1alpha1" + deploy "github.com/IBM/operand-deployment-lifecycle-manager/v4/controllers/operator" ) type MockReader struct { diff --git a/controllers/operandrequest/reconcile_operator.go b/controllers/operandrequest/reconcile_operator.go index 281654c8..722ea8b8 100644 --- a/controllers/operandrequest/reconcile_operator.go +++ b/controllers/operandrequest/reconcile_operator.go @@ -41,9 +41,9 @@ import ( "k8s.io/klog" "sigs.k8s.io/controller-runtime/pkg/client" - operatorv1alpha1 "github.com/IBM/operand-deployment-lifecycle-manager/api/v1alpha1" - "github.com/IBM/operand-deployment-lifecycle-manager/controllers/constant" - "github.com/IBM/operand-deployment-lifecycle-manager/controllers/util" + operatorv1alpha1 "github.com/IBM/operand-deployment-lifecycle-manager/v4/api/v1alpha1" + "github.com/IBM/operand-deployment-lifecycle-manager/v4/controllers/constant" + "github.com/IBM/operand-deployment-lifecycle-manager/v4/controllers/util" ) func (r *Reconciler) reconcileOperator(ctx context.Context, requestInstance *operatorv1alpha1.OperandRequest) error { diff --git a/controllers/operandrequest/reconcile_operator_test.go b/controllers/operandrequest/reconcile_operator_test.go index d4399d05..baf63408 100644 --- a/controllers/operandrequest/reconcile_operator_test.go +++ b/controllers/operandrequest/reconcile_operator_test.go @@ -25,7 +25,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" - operatorv1alpha1 "github.com/IBM/operand-deployment-lifecycle-manager/api/v1alpha1" + operatorv1alpha1 "github.com/IBM/operand-deployment-lifecycle-manager/v4/api/v1alpha1" ) func TestGenerateClusterObjects(t *testing.T) { diff --git a/controllers/operator/manager.go b/controllers/operator/manager.go index f12fe7bb..fd2bde11 100644 --- a/controllers/operator/manager.go +++ b/controllers/operator/manager.go @@ -37,9 +37,9 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/manager" - apiv1alpha1 "github.com/IBM/operand-deployment-lifecycle-manager/api/v1alpha1" - constant "github.com/IBM/operand-deployment-lifecycle-manager/controllers/constant" - "github.com/IBM/operand-deployment-lifecycle-manager/controllers/util" + apiv1alpha1 "github.com/IBM/operand-deployment-lifecycle-manager/v4/api/v1alpha1" + constant "github.com/IBM/operand-deployment-lifecycle-manager/v4/controllers/constant" + "github.com/IBM/operand-deployment-lifecycle-manager/v4/controllers/util" ) // ODLMOperator is the struct for ODLM controllers diff --git a/controllers/operatorchecker/operatorchecker_controller.go b/controllers/operatorchecker/operatorchecker_controller.go index 58ea7370..694bccc8 100644 --- a/controllers/operatorchecker/operatorchecker_controller.go +++ b/controllers/operatorchecker/operatorchecker_controller.go @@ -26,8 +26,8 @@ import ( ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" - "github.com/IBM/operand-deployment-lifecycle-manager/controllers/constant" - deploy "github.com/IBM/operand-deployment-lifecycle-manager/controllers/operator" + "github.com/IBM/operand-deployment-lifecycle-manager/v4/controllers/constant" + deploy "github.com/IBM/operand-deployment-lifecycle-manager/v4/controllers/operator" ) // Reconciler reconciles a OperatorChecker object diff --git a/controllers/operatorconfig/operatorconfig_controller.go b/controllers/operatorconfig/operatorconfig_controller.go index cd30e196..3ee98ef7 100644 --- a/controllers/operatorconfig/operatorconfig_controller.go +++ b/controllers/operatorconfig/operatorconfig_controller.go @@ -33,9 +33,9 @@ import ( "sigs.k8s.io/controller-runtime/pkg/reconcile" "sigs.k8s.io/controller-runtime/pkg/source" - operatorv1alpha1 "github.com/IBM/operand-deployment-lifecycle-manager/api/v1alpha1" - "github.com/IBM/operand-deployment-lifecycle-manager/controllers/constant" - deploy "github.com/IBM/operand-deployment-lifecycle-manager/controllers/operator" + operatorv1alpha1 "github.com/IBM/operand-deployment-lifecycle-manager/v4/api/v1alpha1" + "github.com/IBM/operand-deployment-lifecycle-manager/v4/controllers/constant" + deploy "github.com/IBM/operand-deployment-lifecycle-manager/v4/controllers/operator" ) // OperatorConfigReconciler reconciles a OperatorConfig object diff --git a/controllers/operatorconfig/operatorconfig_suite_test.go b/controllers/operatorconfig/operatorconfig_suite_test.go index aef3a37a..ae4e2246 100644 --- a/controllers/operatorconfig/operatorconfig_suite_test.go +++ b/controllers/operatorconfig/operatorconfig_suite_test.go @@ -30,7 +30,7 @@ import ( logf "sigs.k8s.io/controller-runtime/pkg/log" "sigs.k8s.io/controller-runtime/pkg/log/zap" - operatorv1alpha1 "github.com/IBM/operand-deployment-lifecycle-manager/api/v1alpha1" + operatorv1alpha1 "github.com/IBM/operand-deployment-lifecycle-manager/v4/api/v1alpha1" //+kubebuilder:scaffold:imports ) diff --git a/controllers/testutil/test_util.go b/controllers/testutil/test_util.go index 50b75900..9308e5f5 100644 --- a/controllers/testutil/test_util.go +++ b/controllers/testutil/test_util.go @@ -30,8 +30,8 @@ import ( nssv1 "github.com/IBM/ibm-namespace-scope-operator/api/v1" - apiv1alpha1 "github.com/IBM/operand-deployment-lifecycle-manager/api/v1alpha1" - "github.com/IBM/operand-deployment-lifecycle-manager/controllers/constant" + apiv1alpha1 "github.com/IBM/operand-deployment-lifecycle-manager/v4/api/v1alpha1" + "github.com/IBM/operand-deployment-lifecycle-manager/v4/controllers/constant" // +kubebuilder:scaffold:imports ) diff --git a/go.mod b/go.mod index d61cf275..89f38bc7 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,4 @@ -module github.com/IBM/operand-deployment-lifecycle-manager +module github.com/IBM/operand-deployment-lifecycle-manager/v4 go 1.20 diff --git a/main.go b/main.go index 7281861f..939b2e1c 100644 --- a/main.go +++ b/main.go @@ -39,18 +39,18 @@ import ( cache "github.com/IBM/controller-filtered-cache/filteredcache" nssv1 "github.com/IBM/ibm-namespace-scope-operator/api/v1" - operatorv1alpha1 "github.com/IBM/operand-deployment-lifecycle-manager/api/v1alpha1" - "github.com/IBM/operand-deployment-lifecycle-manager/controllers/constant" - "github.com/IBM/operand-deployment-lifecycle-manager/controllers/k8sutil" - "github.com/IBM/operand-deployment-lifecycle-manager/controllers/namespacescope" - "github.com/IBM/operand-deployment-lifecycle-manager/controllers/operandbindinfo" - "github.com/IBM/operand-deployment-lifecycle-manager/controllers/operandconfig" - "github.com/IBM/operand-deployment-lifecycle-manager/controllers/operandregistry" - "github.com/IBM/operand-deployment-lifecycle-manager/controllers/operandrequest" - deploy "github.com/IBM/operand-deployment-lifecycle-manager/controllers/operator" - "github.com/IBM/operand-deployment-lifecycle-manager/controllers/operatorchecker" - "github.com/IBM/operand-deployment-lifecycle-manager/controllers/operatorconfig" - "github.com/IBM/operand-deployment-lifecycle-manager/controllers/util" + operatorv1alpha1 "github.com/IBM/operand-deployment-lifecycle-manager/v4/api/v1alpha1" + "github.com/IBM/operand-deployment-lifecycle-manager/v4/controllers/constant" + "github.com/IBM/operand-deployment-lifecycle-manager/v4/controllers/k8sutil" + "github.com/IBM/operand-deployment-lifecycle-manager/v4/controllers/namespacescope" + "github.com/IBM/operand-deployment-lifecycle-manager/v4/controllers/operandbindinfo" + "github.com/IBM/operand-deployment-lifecycle-manager/v4/controllers/operandconfig" + "github.com/IBM/operand-deployment-lifecycle-manager/v4/controllers/operandregistry" + "github.com/IBM/operand-deployment-lifecycle-manager/v4/controllers/operandrequest" + deploy "github.com/IBM/operand-deployment-lifecycle-manager/v4/controllers/operator" + "github.com/IBM/operand-deployment-lifecycle-manager/v4/controllers/operatorchecker" + "github.com/IBM/operand-deployment-lifecycle-manager/v4/controllers/operatorconfig" + "github.com/IBM/operand-deployment-lifecycle-manager/v4/controllers/util" // +kubebuilder:scaffold:imports ) diff --git a/test/e2e/helpers_test.go b/test/e2e/helpers_test.go index 24f5a482..24a5d10b 100644 --- a/test/e2e/helpers_test.go +++ b/test/e2e/helpers_test.go @@ -33,7 +33,7 @@ import ( "k8s.io/apimachinery/pkg/util/wait" "sigs.k8s.io/controller-runtime/pkg/client" - "github.com/IBM/operand-deployment-lifecycle-manager/api/v1alpha1" + "github.com/IBM/operand-deployment-lifecycle-manager/v4/api/v1alpha1" ) func createTestNamespace(namespace string) { diff --git a/test/e2e/odlm_test.go b/test/e2e/odlm_test.go index dd0c74a8..ee0993c1 100644 --- a/test/e2e/odlm_test.go +++ b/test/e2e/odlm_test.go @@ -20,7 +20,7 @@ import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" - operatorv1alpha1 "github.com/IBM/operand-deployment-lifecycle-manager/api/v1alpha1" + operatorv1alpha1 "github.com/IBM/operand-deployment-lifecycle-manager/v4/api/v1alpha1" ) // +kubebuilder:docs-gen:collapse=Imports diff --git a/test/e2e/utils_test.go b/test/e2e/utils_test.go index 22f33429..7548b0f0 100644 --- a/test/e2e/utils_test.go +++ b/test/e2e/utils_test.go @@ -34,7 +34,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/log/zap" kbtestutils "sigs.k8s.io/kubebuilder/test/e2e/utils" - apiv1alpha1 "github.com/IBM/operand-deployment-lifecycle-manager/api/v1alpha1" + apiv1alpha1 "github.com/IBM/operand-deployment-lifecycle-manager/v4/api/v1alpha1" ) var ( From 646f7ea772eb7bdd6402e3acc880cb449ff59591 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 May 2024 23:57:29 +0800 Subject: [PATCH 106/179] build(deps): bump golang from 1.22.2-bullseye to 1.22.3-bullseye (#1044) Bumps golang from 1.22.2-bullseye to 1.22.3-bullseye. --- updated-dependencies: - dependency-name: golang dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 83854f41..818d324b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # Build the manager binary -FROM docker.io/golang:1.22.2-bullseye as builder +FROM docker.io/golang:1.22.3-bullseye as builder ARG GOARCH WORKDIR /workspace From ab6ffe182a7dfbf882cbe73d771eb7198b54b374 Mon Sep 17 00:00:00 2001 From: Daniel Fan Date: Thu, 23 May 2024 13:28:40 -0400 Subject: [PATCH 107/179] Bump ODLM to 4.3.2 for 4.6.3 (#1047) * Bump ODLM to 4.3.2 for 4.6.3 Signed-off-by: Daniel Fan * Rollback package setup-envtest due to issue https://github.com/kubernetes-sigs/controller-runtime/issues/2838 Signed-off-by: Daniel Fan --------- Signed-off-by: Daniel Fan --- Makefile | 2 +- ...eployment-lifecycle-manager.clusterserviceversion.yaml | 8 ++++---- common/Makefile.common.mk | 2 +- ...eployment-lifecycle-manager.clusterserviceversion.yaml | 4 ++-- version/version.go | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Makefile b/Makefile index 25ed9673..e611955c 100644 --- a/Makefile +++ b/Makefile @@ -84,7 +84,7 @@ OPERATOR_IMAGE_NAME ?= odlm # Current Operator bundle image name BUNDLE_IMAGE_NAME ?= odlm-operator-bundle # Current Operator version -OPERATOR_VERSION ?= 4.3.1 +OPERATOR_VERSION ?= 4.3.2 # Kind cluster name KIND_CLUSTER_NAME ?= "odlm" diff --git a/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml b/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml index 0eda067c..c934b4fa 100644 --- a/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml +++ b/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml @@ -132,7 +132,7 @@ metadata: createdAt: "2024-04-04T03:40:45Z" description: The Operand Deployment Lifecycle Manager provides a Kubernetes CRD-based API to manage the lifecycle of operands. nss.operator.ibm.com/managed-operators: ibm-odlm - olm.skipRange: '>=1.2.0 <4.3.1' + olm.skipRange: '>=1.2.0 <4.3.2' operators.openshift.io/infrastructure-features: '["disconnected"]' operators.operatorframework.io/builder: operator-sdk-v1.32.0 operators.operatorframework.io/project_layout: go.kubebuilder.io/v3 @@ -143,7 +143,7 @@ metadata: operatorframework.io/arch.ppc64le: supported operatorframework.io/arch.s390x: supported operatorframework.io/os.linux: supported - name: operand-deployment-lifecycle-manager.v4.3.1 + name: operand-deployment-lifecycle-manager.v4.3.2 namespace: placeholder spec: apiservicedefinitions: {} @@ -860,7 +860,7 @@ spec: minKubeVersion: 1.19.0 provider: name: IBM - version: 4.3.1 + version: 4.3.2 relatedImages: - - image: icr.io/cpopen/odlm:4.3.1 + - image: icr.io/cpopen/odlm:4.3.2 name: ODLM_IMAGE diff --git a/common/Makefile.common.mk b/common/Makefile.common.mk index b7c20102..4574e06a 100644 --- a/common/Makefile.common.mk +++ b/common/Makefile.common.mk @@ -94,7 +94,7 @@ kind: ## Download kind locally if necessary. ENVTEST = $(shell pwd)/common/bin/setup-envtest setup-envtest: ## Download envtest-setup locally if necessary. - $(call go-get-tool,$(ENVTEST),sigs.k8s.io/controller-runtime/tools/setup-envtest@latest) + $(call go-get-tool,$(ENVTEST),sigs.k8s.io/controller-runtime/tools/setup-envtest@7b4325d5a38dff0c7eb9a939d079950eafcc4f7e) FINDFILES=find . \( -path ./.git -o -path ./.github -o -path ./testcrds \) -prune -o -type f XARGS = xargs -0 ${XARGS_FLAGS} diff --git a/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml b/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml index 070a2957..3524ce90 100644 --- a/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml +++ b/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml @@ -11,7 +11,7 @@ metadata: description: The Operand Deployment Lifecycle Manager provides a Kubernetes CRD-based API to manage the lifecycle of operands. nss.operator.ibm.com/managed-operators: ibm-odlm - olm.skipRange: '>=1.2.0 <4.3.1' + olm.skipRange: '>=1.2.0 <4.3.2' operators.openshift.io/infrastructure-features: '["disconnected"]' operators.operatorframework.io/builder: operator-sdk-v1.2.0 operators.operatorframework.io/project_layout: go.kubebuilder.io/v2 @@ -482,6 +482,6 @@ spec: provider: name: IBM relatedImages: - - image: icr.io/cpopen/odlm:4.3.1 + - image: icr.io/cpopen/odlm:4.3.2 name: ODLM_IMAGE version: 0.0.0 diff --git a/version/version.go b/version/version.go index 58d53ca2..d8a15ba7 100644 --- a/version/version.go +++ b/version/version.go @@ -17,5 +17,5 @@ package version var ( - Version = "4.3.1" + Version = "4.3.2" ) From 26bedb39db036779bbb0700ca209bd906bec92f2 Mon Sep 17 00:00:00 2001 From: Travis CI User Date: Fri, 24 May 2024 22:13:08 +0000 Subject: [PATCH 108/179] Trigger build with new base image --- base_images.json | 37 +++++++++++++------------------------ 1 file changed, 13 insertions(+), 24 deletions(-) diff --git a/base_images.json b/base_images.json index 57096b34..68d23d55 100644 --- a/base_images.json +++ b/base_images.json @@ -7,7 +7,7 @@ "destStage": "edge", "destNamespace": "build-images", "destImage": "ubi8", - "tag": "8.9-1160", + "tag": "8.10-901", "updatePackages": [] }, { @@ -18,7 +18,7 @@ "destStage": "edge", "destNamespace": "build-images", "destImage": "ubi8-minimal", - "tag": "8.9-1161", + "tag": "8.10-896", "updatePackages": [] }, { @@ -29,7 +29,7 @@ "destStage": "edge", "destNamespace": "build-images", "destImage": "ubi9-micro", - "tag": "9.3-15", + "tag": "9.4-6", "updatePackages": [] }, { @@ -40,7 +40,7 @@ "destStage": "edge", "destNamespace": "build-images", "destImage": "ubi9", - "tag": "9.3-1610", + "tag": "9.4-947.1714667021", "updatePackages": [] }, { @@ -51,46 +51,35 @@ "destStage": "edge", "destNamespace": "build-images", "destImage": "ubi9-minimal", - "tag": "9.3-1612", - "updatePackages": [] - }, - { - "imageType": "external", - "sourceRepo": "quay.io", - "sourceNamespace": "operator-framework", - "sourceImage": "helm-operator", - "destStage": "edge", - "destNamespace": "build-images", - "destImage": "helm-operator", - "tag": "v1.34.0", + "tag": "9.4-949.1714662671", "updatePackages": [] }, { "imageType": "node", "sourceImage": "ubi8-minimal", - "sourceTag": "8.9-1161", + "sourceTag": "8.10-896", "destImage": "node-v18-ubi8-minimal", - "nodeVersion": "18.20.2" + "nodeVersion": "18.20.3" }, { "imageType": "node", "sourceImage": "ubi8-minimal", - "sourceTag": "8.9-1161", + "sourceTag": "8.10-896", "destImage": "node-v20-ubi8-minimal", - "nodeVersion": "20.12.2" + "nodeVersion": "20.13.1" }, { "imageType": "node", "sourceImage": "ubi9-minimal", - "sourceTag": "9.3-1612", + "sourceTag": "9.4-949.1714662671", "destImage": "node-v18-ubi9-minimal", - "nodeVersion": "18.20.2" + "nodeVersion": "18.20.3" }, { "imageType": "node", "sourceImage": "ubi9-minimal", - "sourceTag": "9.3-1612", + "sourceTag": "9.4-949.1714662671", "destImage": "node-v20-ubi9-minimal", - "nodeVersion": "20.12.2" + "nodeVersion": "20.13.1" } ] From 6db85c0fbfc176b9481888e41e25f538cd7fc821 Mon Sep 17 00:00:00 2001 From: Daniel Fan Date: Sun, 26 May 2024 23:52:44 -0400 Subject: [PATCH 109/179] Only discover catalog for an operator when it has been requested in OperandRequest (#1048) Signed-off-by: Daniel Fan --- .../operandbindinfo_controller.go | 8 +- .../operandrequest_controller.go | 21 ++++-- .../operandrequest/reconcile_operand.go | 33 +++++---- .../operandrequest/reconcile_operator.go | 9 ++- controllers/operator/manager.go | 74 ++++++++++--------- .../operatorconfig_controller.go | 6 +- controllers/util/merge.go | 4 +- 7 files changed, 91 insertions(+), 64 deletions(-) diff --git a/controllers/operandbindinfo/operandbindinfo_controller.go b/controllers/operandbindinfo/operandbindinfo_controller.go index 41e54892..10f2d964 100644 --- a/controllers/operandbindinfo/operandbindinfo_controller.go +++ b/controllers/operandbindinfo/operandbindinfo_controller.go @@ -159,11 +159,11 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctrl.Re return ctrl.Result{}, nil } // Get the operand namespace - operandOperator := registryInstance.GetOperator(bindInfoInstance.Spec.Operand) - if operandOperator == nil { - klog.Errorf("failed to find operator %s in the OperandRegistry %s", bindInfoInstance.Spec.Operand, registryInstance.Name) + operandOperator, err := r.GetOperandFromRegistry(ctx, registryInstance, bindInfoInstance.Spec.Operand) + if err != nil || operandOperator == nil { + klog.Errorf("failed to find operator %s in the OperandRegistry %s: %v", bindInfoInstance.Spec.Operand, registryInstance.Name, err) r.Recorder.Eventf(bindInfoInstance, corev1.EventTypeWarning, "NotFound", "NotFound operator %s in the OperandRegistry %s", bindInfoInstance.Spec.Operand, registryInstance.Name) - return ctrl.Result{}, nil + return ctrl.Result{}, err } operandNamespace := registryInstance.Namespace diff --git a/controllers/operandrequest/operandrequest_controller.go b/controllers/operandrequest/operandrequest_controller.go index b9b2c69c..9d1c264f 100644 --- a/controllers/operandrequest/operandrequest_controller.go +++ b/controllers/operandrequest/operandrequest_controller.go @@ -354,18 +354,27 @@ func (r *Reconciler) SetupWithManager(mgr ctrl.Manager) error { ReferencePredicates := predicate.Funcs{ CreateFunc: func(e event.CreateEvent) bool { labels := e.Object.GetLabels() - for labelKey, labelValue := range labels { - if labelKey == constant.ODLMWatchedLabel { - return labelValue == "true" + // only return true when both conditions are met at the same time: + // 1. label contain key "constant.ODLMWatchedLabel" and value is true + // 2. label does not contain key "constant.OpbiTypeLabel" with value "copy" + if labels != nil { + if labelValue, ok := labels[constant.ODLMWatchedLabel]; ok && labelValue == "true" { + if labelValue, ok := labels[constant.OpbiTypeLabel]; ok && labelValue == "copy" { + return false + } + return true } } return false }, UpdateFunc: func(e event.UpdateEvent) bool { labels := e.ObjectNew.GetLabels() - for labelKey, labelValue := range labels { - if labelKey == constant.ODLMWatchedLabel { - return labelValue == "true" + if labels != nil { + if labelValue, ok := labels[constant.ODLMWatchedLabel]; ok && labelValue == "true" { + if labelValue, ok := labels[constant.OpbiTypeLabel]; ok && labelValue == "copy" { + return false + } + return true } } return false diff --git a/controllers/operandrequest/reconcile_operand.go b/controllers/operandrequest/reconcile_operand.go index 7249f2b8..69cbae26 100644 --- a/controllers/operandrequest/reconcile_operand.go +++ b/controllers/operandrequest/reconcile_operand.go @@ -22,17 +22,16 @@ import ( "encoding/hex" "encoding/json" "fmt" - "reflect" "regexp" "strconv" "strings" "sync" - "github.com/barkimedes/go-deepcopy" olmv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1" "github.com/pkg/errors" authorizationv1 "k8s.io/api/authorization/v1" corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/equality" apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -73,8 +72,12 @@ func (r *Reconciler) reconcileOperand(ctx context.Context, requestInstance *oper for i, operand := range req.Operands { - opdRegistry := registryInstance.GetOperator(operand.Name) - if opdRegistry == nil { + opdRegistry, err := r.GetOperandFromRegistry(ctx, registryInstance, operand.Name) + if err != nil { + klog.Warningf("Failed to get the Operand %s from the OperandRegistry %s", operand.Name, registryKey.String()) + merr.Add(errors.Wrapf(err, "failed to get the Operand %s from the OperandRegistry %s", operand.Name, registryKey.String())) + continue + } else if opdRegistry == nil { klog.Warningf("Cannot find %s in the OperandRegistry instance %s in the namespace %s ", operand.Name, req.Registry, req.RegistryNamespace) requestInstance.SetMemberStatus(operand.Name, operatorv1alpha1.OperatorNotFound, operatorv1alpha1.ServiceNotFound, &r.Mutex) continue @@ -772,7 +775,7 @@ func (r *Reconciler) updateCustomResource(ctx context.Context, existingCR unstru // Merge spec from update existing CR and OperandConfig spec updatedCRSpec := util.MergeCR(updatedExistingCRRaw, crConfig) - if reflect.DeepEqual(existingCR.Object["spec"], updatedCRSpec) && !forceUpdate { + if equality.Semantic.DeepEqual(existingCR.Object["spec"], updatedCRSpec) && !forceUpdate { return true, nil } @@ -1069,13 +1072,6 @@ func (r *Reconciler) updateK8sResource(ctx context.Context, existingK8sRes unstr // Merge the existing CR and the CR from the OperandConfig updatedExistingK8sRes := util.MergeCR(existingK8sResRaw, k8sResConfig.Raw) - - // Deep copy the existing k8s resource - originalK8sRes, err := deepcopy.Anything(existingK8sRes.Object) - if err != nil { - return false, errors.Wrapf(err, "failed to deep copy k8s resource -- Kind: %s, NamespacedName: %s/%s", kind, namespace, name) - } - // Update the existing k8s resource with the merged CR existingK8sRes.Object = updatedExistingK8sRes @@ -1085,14 +1081,21 @@ func (r *Reconciler) updateK8sResource(ctx context.Context, existingK8sRes unstr return false, errors.Wrapf(err, "failed to set ownerReferences for k8s resource -- Kind: %s, NamespacedName: %s/%s", kind, namespace, name) } - if reflect.DeepEqual(originalK8sRes, existingK8sRes.Object) { + resourceVersion := existingK8sRes.GetResourceVersion() + CRgeneration := existingK8sRes.GetGeneration() + err = r.Update(ctx, &existingK8sRes, client.DryRunAll) + if err != nil { + return false, errors.Wrapf(err, "failed to update k8s resource -- Kind: %s, NamespacedName: %s/%s", kind, namespace, name) + } + + if newResourceVersion := existingK8sRes.GetResourceVersion(); resourceVersion == newResourceVersion { + // if the resourceVersion is the same, the update is not performed + klog.Infof("The k8s resource with apiversion: %s, kind: %s, %s/%s is not updated", apiversion, kind, namespace, name) return true, nil } klog.Infof("updating k8s resource with apiversion: %s, kind: %s, %s/%s", apiversion, kind, namespace, name) - CRgeneration := existingK8sRes.GetGeneration() - err = r.Update(ctx, &existingK8sRes) if err != nil { diff --git a/controllers/operandrequest/reconcile_operator.go b/controllers/operandrequest/reconcile_operator.go index 722ea8b8..5c323c86 100644 --- a/controllers/operandrequest/reconcile_operator.go +++ b/controllers/operandrequest/reconcile_operator.go @@ -137,7 +137,11 @@ func (r *Reconciler) reconcileSubscription(ctx context.Context, requestInstance // Check the requested Operand if exist in specific OperandRegistry var opt *operatorv1alpha1.Operator if registryInstance != nil { - opt = registryInstance.GetOperator(operand.Name) + var err error + opt, err = r.GetOperandFromRegistry(ctx, registryInstance, operand.Name) + if err != nil { + return err + } } if opt == nil { if registryInstance != nil { @@ -381,7 +385,8 @@ func (r *Reconciler) deleteSubscription(ctx context.Context, cr *operatorv1alpha } func (r *Reconciler) uninstallOperatorsAndOperands(ctx context.Context, operandName string, requestInstance *operatorv1alpha1.OperandRequest, registryInstance *operatorv1alpha1.OperandRegistry, configInstance *operatorv1alpha1.OperandConfig) error { - op := registryInstance.GetOperator(operandName) + // No error handling for un-installation step in case Catalog has been deleted + op, _ := r.GetOperandFromRegistry(ctx, registryInstance, operandName) if op == nil { klog.Warningf("Operand %s not found", operandName) return nil diff --git a/controllers/operator/manager.go b/controllers/operator/manager.go index fd2bde11..3bc13d69 100644 --- a/controllers/operator/manager.go +++ b/controllers/operator/manager.go @@ -60,7 +60,7 @@ func NewODLMOperator(mgr manager.Manager, name string) *ODLMOperator { Config: mgr.GetConfig(), Recorder: mgr.GetEventRecorderFor(name), Scheme: mgr.GetScheme(), - MaxConcurrentReconciles: 3, + MaxConcurrentReconciles: 5, } } @@ -70,26 +70,6 @@ func (m *ODLMOperator) GetOperandRegistry(ctx context.Context, key types.Namespa if err := m.Client.Get(ctx, key, reg); err != nil { return nil, err } - // Get excluded CatalogSource from annotation - // excluded-catalogsource: catalogsource1, catalogsource2 - var excludedCatalogSources []string - if reg.Annotations != nil && reg.Annotations["excluded-catalogsource"] != "" { - excludedCatalogSources = strings.Split(reg.Annotations["excluded-catalogsource"], ",") - } - // Get catalog used by ODLM itself by check its own subscription - opts := []client.ListOption{ - client.MatchingLabels{fmt.Sprintf("operators.coreos.com/ibm-odlm.%s", util.GetOperatorNamespace()): ""}, - client.InNamespace(util.GetOperatorNamespace()), - } - odlmCatalog := "" - odlmCatalogNs := "" - odlmSubList := &olmv1alpha1.SubscriptionList{} - if err := m.Reader.List(ctx, odlmSubList, opts...); err != nil || len(odlmSubList.Items) == 0 { - klog.Warningf("No Subscription found for ibm-odlm in the namespace %s", util.GetOperatorNamespace()) - } else { - odlmCatalog = odlmSubList.Items[0].Spec.CatalogSource - odlmCatalogNs = odlmSubList.Items[0].Spec.CatalogSourceNamespace - } for i, o := range reg.Spec.Operators { if o.Scope == "" { @@ -104,18 +84,6 @@ func (m *ODLMOperator) GetOperandRegistry(ctx context.Context, key types.Namespa if o.Namespace == "" { reg.Spec.Operators[i].Namespace = key.Namespace } - if o.SourceName == "" || o.SourceNamespace == "" { - catalogSourceName, catalogSourceNs, err := m.GetCatalogSourceFromPackage(ctx, o.PackageName, reg.Spec.Operators[i].Namespace, o.Channel, key.Namespace, odlmCatalog, odlmCatalogNs, excludedCatalogSources) - if err != nil { - return nil, err - } - - if catalogSourceName == "" || catalogSourceNs == "" { - klog.V(2).Infof("no catalogsource found for %v", o.PackageName) - } - - reg.Spec.Operators[i].SourceName, reg.Spec.Operators[i].SourceNamespace = catalogSourceName, catalogSourceNs - } } return reg, nil } @@ -431,6 +399,46 @@ func (m *ODLMOperator) GetOperatorNamespace(installMode, namespace string) strin return namespace } +// GetOperandFromRegistry gets the Operand from the OperandRegistry +func (m *ODLMOperator) GetOperandFromRegistry(ctx context.Context, reg *apiv1alpha1.OperandRegistry, operandName string) (*apiv1alpha1.Operator, error) { + opt := reg.GetOperator(operandName) + // Get excluded CatalogSource from annotation + // excluded-catalogsource: catalogsource1, catalogsource2 + var excludedCatalogSources []string + if reg.Annotations != nil && reg.Annotations["excluded-catalogsource"] != "" { + excludedCatalogSources = strings.Split(reg.Annotations["excluded-catalogsource"], ",") + } + // Get catalog used by ODLM itself by check its own subscription + opts := []client.ListOption{ + client.MatchingLabels{fmt.Sprintf("operators.coreos.com/ibm-odlm.%s", util.GetOperatorNamespace()): ""}, + client.InNamespace(util.GetOperatorNamespace()), + } + odlmCatalog := "" + odlmCatalogNs := "" + odlmSubList := &olmv1alpha1.SubscriptionList{} + if err := m.Reader.List(ctx, odlmSubList, opts...); err != nil || len(odlmSubList.Items) == 0 { + klog.Warningf("No Subscription found for ibm-odlm in the namespace %s", util.GetOperatorNamespace()) + } else { + odlmCatalog = odlmSubList.Items[0].Spec.CatalogSource + odlmCatalogNs = odlmSubList.Items[0].Spec.CatalogSourceNamespace + } + + if opt.SourceName == "" || opt.SourceNamespace == "" { + catalogSourceName, catalogSourceNs, err := m.GetCatalogSourceFromPackage(ctx, opt.PackageName, opt.Namespace, opt.Channel, reg.Namespace, odlmCatalog, odlmCatalogNs, excludedCatalogSources) + if err != nil { + return nil, err + } + + if catalogSourceName == "" || catalogSourceNs == "" { + klog.V(2).Infof("no catalogsource found for %v", opt.PackageName) + } + + opt.SourceName, opt.SourceNamespace = catalogSourceName, catalogSourceNs + } + + return opt, nil +} + func (m *ODLMOperator) CheckLabel(unstruct unstructured.Unstructured, labels map[string]string) bool { for k, v := range labels { if !m.HasLabel(unstruct, k) { diff --git a/controllers/operatorconfig/operatorconfig_controller.go b/controllers/operatorconfig/operatorconfig_controller.go index 3ee98ef7..ae71f229 100644 --- a/controllers/operatorconfig/operatorconfig_controller.go +++ b/controllers/operatorconfig/operatorconfig_controller.go @@ -72,8 +72,10 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu } for _, u := range reqBlock.Operands { operand := u - operator := registry.GetOperator(operand.Name) - if operator == nil || operator.OperatorConfig == "" { + operator, err := r.GetOperandFromRegistry(ctx, registry, operand.Name) + if err != nil { + return ctrl.Result{}, err + } else if operator == nil || operator.OperatorConfig == "" { continue } diff --git a/controllers/util/merge.go b/controllers/util/merge.go index fc3b83c3..8d0743ff 100644 --- a/controllers/util/merge.go +++ b/controllers/util/merge.go @@ -18,8 +18,8 @@ package util import ( "encoding/json" - "reflect" + "k8s.io/apimachinery/pkg/api/equality" "k8s.io/klog" ) @@ -59,7 +59,7 @@ func MergeCR(defaultCR, changedCR []byte) map[string]interface{} { } func checkKeyBeforeMerging(key string, defaultMap interface{}, changedMap interface{}, finalMap map[string]interface{}) { - if !reflect.DeepEqual(defaultMap, changedMap) { + if !equality.Semantic.DeepEqual(defaultMap, changedMap) { switch defaultMap := defaultMap.(type) { case map[string]interface{}: //Check that the changed map value doesn't contain this map at all and is nil From c65b69535dfd1dd4f88606b4bb7ef66ce160afcb Mon Sep 17 00:00:00 2001 From: Travis CI User Date: Thu, 30 May 2024 17:28:04 +0000 Subject: [PATCH 110/179] Trigger build with new base image --- base_images.json | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/base_images.json b/base_images.json index 68d23d55..360c6e92 100644 --- a/base_images.json +++ b/base_images.json @@ -7,7 +7,7 @@ "destStage": "edge", "destNamespace": "build-images", "destImage": "ubi8", - "tag": "8.10-901", + "tag": "8.10-901.1716482497", "updatePackages": [] }, { @@ -18,7 +18,7 @@ "destStage": "edge", "destNamespace": "build-images", "destImage": "ubi8-minimal", - "tag": "8.10-896", + "tag": "8.10-896.1716497715", "updatePackages": [] }, { @@ -29,7 +29,7 @@ "destStage": "edge", "destNamespace": "build-images", "destImage": "ubi9-micro", - "tag": "9.4-6", + "tag": "9.4-6.1716471860", "updatePackages": [] }, { @@ -40,7 +40,7 @@ "destStage": "edge", "destNamespace": "build-images", "destImage": "ubi9", - "tag": "9.4-947.1714667021", + "tag": "9.4-947.1716476138", "updatePackages": [] }, { @@ -51,35 +51,35 @@ "destStage": "edge", "destNamespace": "build-images", "destImage": "ubi9-minimal", - "tag": "9.4-949.1714662671", + "tag": "9.4-949.1716471857", "updatePackages": [] }, { "imageType": "node", "sourceImage": "ubi8-minimal", - "sourceTag": "8.10-896", + "sourceTag": "8.10-896.1716497715", "destImage": "node-v18-ubi8-minimal", "nodeVersion": "18.20.3" }, { "imageType": "node", "sourceImage": "ubi8-minimal", - "sourceTag": "8.10-896", + "sourceTag": "8.10-896.1716497715", "destImage": "node-v20-ubi8-minimal", - "nodeVersion": "20.13.1" + "nodeVersion": "20.14.0" }, { "imageType": "node", "sourceImage": "ubi9-minimal", - "sourceTag": "9.4-949.1714662671", + "sourceTag": "9.4-949.1716471857", "destImage": "node-v18-ubi9-minimal", "nodeVersion": "18.20.3" }, { "imageType": "node", "sourceImage": "ubi9-minimal", - "sourceTag": "9.4-949.1714662671", + "sourceTag": "9.4-949.1716471857", "destImage": "node-v20-ubi9-minimal", - "nodeVersion": "20.13.1" + "nodeVersion": "20.14.0" } ] From 287eafa27e14d7e1537c0576e6d395c2d9e25de2 Mon Sep 17 00:00:00 2001 From: YuChen Shen <59578388+YCShen1010@users.noreply.github.com> Date: Mon, 3 Jun 2024 12:43:53 -0400 Subject: [PATCH 111/179] reset the phase of each operator in opreq (#1049) Signed-off-by: YuChen --- api/v1alpha1/operandrequest_types.go | 9 +++++++++ .../operandrequest/operandrequest_controller.go | 12 ++++++++++++ controllers/operandrequest/reconcile_operand.go | 3 ++- 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/api/v1alpha1/operandrequest_types.go b/api/v1alpha1/operandrequest_types.go index d99d416d..6a1651be 100644 --- a/api/v1alpha1/operandrequest_types.go +++ b/api/v1alpha1/operandrequest_types.go @@ -429,6 +429,15 @@ func (r *OperandRequest) RemoveServiceStatus(operatorName string, mu sync.Locker } } +func (r *OperandRequest) RemoveOperandPhase(name string, mu sync.Locker) { + mu.Lock() + defer mu.Unlock() + pos, m := getMemberStatus(&r.Status, name) + if m != nil { + r.Status.Members[pos].Phase = MemberPhase{} + } +} + func (r *OperandRequest) SetServiceStatus(ctx context.Context, service ServiceStatus, updater client.StatusClient, mu sync.Locker) error { mu.Lock() defer mu.Unlock() diff --git a/controllers/operandrequest/operandrequest_controller.go b/controllers/operandrequest/operandrequest_controller.go index 9d1c264f..96c45736 100644 --- a/controllers/operandrequest/operandrequest_controller.go +++ b/controllers/operandrequest/operandrequest_controller.go @@ -156,6 +156,18 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctrl.Re return ctrl.Result{Requeue: true}, err } + // Clean the phase of each operand under spec.request.operand + for _, member := range requestInstance.Status.Members { + klog.V(2).Info("Cleaning the member status for Operand: ", member.Name) + requestInstance.RemoveOperandPhase(member.Name, &r.Mutex) + } + requestInstance.Status.Phase = operatorv1alpha1.ClusterPhaseNone + + if err := r.Client.Status().Update(ctx, requestInstance); err != nil { + klog.Errorf("failed to update the status of the OperandRequest %s: %v", req.NamespacedName.String(), err) + return ctrl.Result{}, err + } + // Reconcile Operators if err := r.reconcileOperator(ctx, requestInstance); err != nil { klog.Errorf("failed to reconcile Operators for OperandRequest %s: %v", req.NamespacedName.String(), err) diff --git a/controllers/operandrequest/reconcile_operand.go b/controllers/operandrequest/reconcile_operand.go index 69cbae26..91a76fcb 100644 --- a/controllers/operandrequest/reconcile_operand.go +++ b/controllers/operandrequest/reconcile_operand.go @@ -83,6 +83,7 @@ func (r *Reconciler) reconcileOperand(ctx context.Context, requestInstance *oper continue } + // Set no-op operator to Running status if opdRegistry.InstallMode == operatorv1alpha1.InstallModeNoop { requestInstance.SetNoSuitableRegistryCondition(registryKey.String(), opdRegistry.Name+" is in maintenance status", operatorv1alpha1.ResourceTypeOperandRegistry, corev1.ConditionTrue, &r.Mutex) requestInstance.SetMemberStatus(operand.Name, operatorv1alpha1.OperatorRunning, operatorv1alpha1.ServiceRunning, &r.Mutex) @@ -164,7 +165,7 @@ func (r *Reconciler) reconcileOperand(ctx context.Context, requestInstance *oper if len(requestList) == 0 || !util.Contains(requestList, requestInstance.Namespace+"."+requestInstance.Name+"."+operand.Name+"/request") { klog.Infof("Subscription %s in the namespace %s is NOT managed by %s/%s, Skip reconciling Operands", sub.Name, sub.Namespace, requestInstance.Namespace, requestInstance.Name) - requestInstance.SetMemberStatus(operand.Name, "", operatorv1alpha1.ServiceFailed, &r.Mutex) + requestInstance.SetMemberStatus(operand.Name, operatorv1alpha1.OperatorFailed, "", &r.Mutex) continue } From 330494d95940e3a8202623f6d7cda07337d1bd95 Mon Sep 17 00:00:00 2001 From: Daniel Fan Date: Mon, 3 Jun 2024 17:33:53 -0400 Subject: [PATCH 112/179] Skip catalog discover when operator is not found in OperandRegistry (#1050) Signed-off-by: Daniel Fan --- controllers/operator/manager.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/controllers/operator/manager.go b/controllers/operator/manager.go index 3bc13d69..a455e02c 100644 --- a/controllers/operator/manager.go +++ b/controllers/operator/manager.go @@ -402,6 +402,10 @@ func (m *ODLMOperator) GetOperatorNamespace(installMode, namespace string) strin // GetOperandFromRegistry gets the Operand from the OperandRegistry func (m *ODLMOperator) GetOperandFromRegistry(ctx context.Context, reg *apiv1alpha1.OperandRegistry, operandName string) (*apiv1alpha1.Operator, error) { opt := reg.GetOperator(operandName) + if opt == nil { + return nil, nil + } + // Get excluded CatalogSource from annotation // excluded-catalogsource: catalogsource1, catalogsource2 var excludedCatalogSources []string From 85eb084f7d8f9695691949a13733b8aebbfffed7 Mon Sep 17 00:00:00 2001 From: Daniel Fan Date: Wed, 5 Jun 2024 17:27:55 -0400 Subject: [PATCH 113/179] reconcile k8s resource in parallel and with retry logic (#1053) * reconcile k8s resource in parallel and with retry logic Signed-off-by: Daniel Fan * Separate variables for chunkSize and Retry number Signed-off-by: Daniel Fan --------- Signed-off-by: Daniel Fan --- controllers/constant/constant.go | 3 + .../operandrequest/reconcile_operand.go | 196 ++++++++++-------- controllers/operator/manager.go | 2 +- .../operatorconfig_controller.go | 21 +- main.go | 2 +- 5 files changed, 139 insertions(+), 85 deletions(-) diff --git a/controllers/constant/constant.go b/controllers/constant/constant.go index 1157fd1b..1e09eb3e 100644 --- a/controllers/constant/constant.go +++ b/controllers/constant/constant.go @@ -90,4 +90,7 @@ const ( //DefaultCSVWaitPeriod is the default period for wait CSV ready DefaultCSVWaitPeriod = 1 * time.Minute + + //DefaultCRRetryNumber is the default maximum number of retry for reconciling a custom resource + DefaultCRRetryNumber = 3 ) diff --git a/controllers/operandrequest/reconcile_operand.go b/controllers/operandrequest/reconcile_operand.go index 91a76fcb..af5276d6 100644 --- a/controllers/operandrequest/reconcile_operand.go +++ b/controllers/operandrequest/reconcile_operand.go @@ -26,6 +26,7 @@ import ( "strconv" "strings" "sync" + "time" olmv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1" "github.com/pkg/errors" @@ -219,76 +220,31 @@ func (r *Reconciler) reconcileCRwithConfig(ctx context.Context, service *operato // Create k8s resources required by service if service.Resources != nil { - for i := range service.Resources { - res := service.Resources[i] - if res.APIVersion == "" { - return fmt.Errorf("The APIVersion of k8s resource is empty for operator " + service.Name) - } - - if res.Kind == "" { - return fmt.Errorf("The Kind of k8s resource is empty for operator " + service.Name) - } - if res.Name == "" { - return fmt.Errorf("The Name of k8s resource is empty for operator " + service.Name) - } - var k8sResNs string - if res.Namespace == "" { - k8sResNs = opConfigNs - } else { - k8sResNs = res.Namespace - } - - resObject, err := util.ObjectToNewUnstructured(&res) - if err != nil { - klog.Errorf("Failed to convert %s %s/%s object to unstructured.Unstructured object", res.Kind, k8sResNs, res.Name) - return err - } - - if err := r.ParseValueReferenceInObject(ctx, "data", resObject.Object["data"], resObject.Object, "OperandConfig", opConfigName, opConfigNs); err != nil { - klog.Errorf("Failed to parse value reference in resource %s/%s: %v", k8sResNs, res.Name, err) - return err - } - // cover unstructured.Unstructured object to original OperandConfig object - if err := runtime.DefaultUnstructuredConverter.FromUnstructured(resObject.Object, &res); err != nil { - klog.Errorf("Failed to convert unstructured.Unstructured object to %s %s/%s object", res.Kind, k8sResNs, res.Name) - return err - } - - var k8sRes unstructured.Unstructured - k8sRes.SetAPIVersion(res.APIVersion) - k8sRes.SetKind(res.Kind) - k8sRes.SetName(res.Name) - k8sRes.SetNamespace(k8sResNs) - - verbs := []string{"create", "delete", "get", "update"} - if r.checkResAuth(ctx, verbs, k8sRes) { - err := r.Client.Get(ctx, types.NamespacedName{ - Name: res.Name, - Namespace: k8sResNs, - }, &k8sRes) + // Get the chunk size + var chunkSize int + if r.StepSize > 0 { + chunkSize = r.StepSize + } else { + chunkSize = 1 + } + var wg sync.WaitGroup + semaphore := make(chan struct{}, chunkSize) - if err != nil && !apierrors.IsNotFound(err) { - merr.Add(errors.Wrapf(err, "failed to get k8s resource %s/%s", k8sResNs, res.Name)) - } else if apierrors.IsNotFound(err) { - if err := r.createK8sResource(ctx, k8sRes, res.Data, res.Labels, res.Annotations, &res.OwnerReferences); err != nil { - merr.Add(err) - } - } else { - if res.Force { - // Update k8s resource - klog.V(3).Info("Found existing k8s resource: " + res.Name) - if err := r.updateK8sResource(ctx, k8sRes, res.Data, res.Labels, res.Annotations, &res.OwnerReferences); err != nil { - merr.Add(err) - } - } else { - klog.V(2).Infof("Skip the k8s resource %s/%s which is not created by ODLM", res.Kind, res.Name) - } + for i := range service.Resources { + wg.Add(1) + semaphore <- struct{}{} + go func(res operatorv1alpha1.ConfigResource) { + defer wg.Done() + defer func() { <-semaphore }() // release semaphore + err := r.reconcileK8sResourceWithRetries(ctx, res, service.Name, opConfigName, opConfigNs) + if err != nil { + merr.Add(err) } - } else { - klog.Infof("ODLM doesn't have enough permission to reconcile k8s resource -- Kind: %s, NamespacedName: %s/%s", res.Kind, k8sResNs, res.Name) - } + }(service.Resources[i]) } + wg.Wait() + if len(merr.Errors) != 0 { return merr } @@ -530,6 +486,93 @@ func newServiceStatus(operatorName string, namespace string, resources []operato return serviceSpec } +func (r *Reconciler) reconcileK8sResourceWithRetries(ctx context.Context, res operatorv1alpha1.ConfigResource, serviceName, opConfigName, opConfigNs string) error { + var err error + for i := 0; i < int(constant.DefaultCRRetryNumber); i++ { + err = r.reconcileK8sResource(ctx, res, serviceName, opConfigName, opConfigNs) + if err == nil { + return nil + } + klog.Errorf("Failed to reconcile k8s resource -- Kind: %s, NamespacedName: %s/%s with error: %v", res.Kind, res.Namespace, res.Name, err) + if i < int(constant.DefaultCRRetryNumber)-1 { + waitTime := time.Duration((1 << i) * 4 * int(time.Second)) + klog.Warningf("Retry reconcile k8s resource -- Kind: %s, NamespacedName: %s/%s after waiting %v", res.Kind, res.Namespace, res.Name, waitTime) + time.Sleep(waitTime) + } + } + return err +} + +func (r *Reconciler) reconcileK8sResource(ctx context.Context, res operatorv1alpha1.ConfigResource, serviceName, opConfigName, opConfigNs string) error { + if res.APIVersion == "" { + return fmt.Errorf("The APIVersion of k8s resource is empty for operator " + serviceName) + } + + if res.Kind == "" { + return fmt.Errorf("The Kind of k8s resource is empty for operator " + serviceName) + } + if res.Name == "" { + return fmt.Errorf("The Name of k8s resource is empty for operator " + serviceName) + } + var k8sResNs string + if res.Namespace == "" { + k8sResNs = opConfigNs + } else { + k8sResNs = res.Namespace + } + + resObject, err := util.ObjectToNewUnstructured(&res) + if err != nil { + klog.Errorf("Failed to convert %s %s/%s object to unstructured.Unstructured object", res.Kind, k8sResNs, res.Name) + return err + } + + if err := r.ParseValueReferenceInObject(ctx, "data", resObject.Object["data"], resObject.Object, "OperandConfig", opConfigName, opConfigNs); err != nil { + klog.Errorf("Failed to parse value reference in resource %s/%s: %v", k8sResNs, res.Name, err) + return err + } + // cover unstructured.Unstructured object to original OperandConfig object + if err := runtime.DefaultUnstructuredConverter.FromUnstructured(resObject.Object, &res); err != nil { + klog.Errorf("Failed to convert unstructured.Unstructured object to %s %s/%s object", res.Kind, k8sResNs, res.Name) + return err + } + + var k8sRes unstructured.Unstructured + k8sRes.SetAPIVersion(res.APIVersion) + k8sRes.SetKind(res.Kind) + k8sRes.SetName(res.Name) + k8sRes.SetNamespace(k8sResNs) + + verbs := []string{"create", "delete", "get", "update"} + if r.checkResAuth(ctx, verbs, k8sRes) { + err := r.Client.Get(ctx, types.NamespacedName{ + Name: res.Name, + Namespace: k8sResNs, + }, &k8sRes) + + if err != nil && !apierrors.IsNotFound(err) { + return errors.Wrapf(err, "failed to get k8s resource %s/%s", k8sResNs, res.Name) + } else if apierrors.IsNotFound(err) { + if err := r.createK8sResource(ctx, k8sRes, res.Data, res.Labels, res.Annotations, &res.OwnerReferences); err != nil { + return err + } + } else { + if res.Force { + // Update k8s resource + klog.V(3).Info("Found existing k8s resource: " + res.Name) + if err := r.updateK8sResource(ctx, k8sRes, res.Data, res.Labels, res.Annotations, &res.OwnerReferences); err != nil { + return err + } + } else { + klog.V(2).Infof("Skip the k8s resource %s/%s which is not created by ODLM", res.Kind, res.Name) + } + } + } else { + klog.Infof("ODLM doesn't have enough permission to reconcile k8s resource -- Kind: %s, NamespacedName: %s/%s", res.Kind, k8sResNs, res.Name) + } + return nil +} + // deleteAllCustomResource remove custom resource base on OperandConfig and CSV alm-examples func (r *Reconciler) deleteAllCustomResource(ctx context.Context, csv *olmv1alpha1.ClusterServiceVersion, requestInstance *operatorv1alpha1.OperandRequest, csc *operatorv1alpha1.OperandConfig, operandName, namespace string) error { @@ -1067,8 +1110,7 @@ func (r *Reconciler) updateK8sResource(ctx context.Context, existingK8sRes unstr // Convert existing k8s resource to string existingK8sResRaw, err := json.Marshal(existingK8sRes.Object) if err != nil { - klog.Error(err) - return false, err + return false, errors.Wrapf(err, "failed to marshal existing k8s resource -- Kind: %s, NamespacedName: %s/%s", kind, namespace, name) } // Merge the existing CR and the CR from the OperandConfig @@ -1082,21 +1124,9 @@ func (r *Reconciler) updateK8sResource(ctx context.Context, existingK8sRes unstr return false, errors.Wrapf(err, "failed to set ownerReferences for k8s resource -- Kind: %s, NamespacedName: %s/%s", kind, namespace, name) } - resourceVersion := existingK8sRes.GetResourceVersion() - CRgeneration := existingK8sRes.GetGeneration() - err = r.Update(ctx, &existingK8sRes, client.DryRunAll) - if err != nil { - return false, errors.Wrapf(err, "failed to update k8s resource -- Kind: %s, NamespacedName: %s/%s", kind, namespace, name) - } - - if newResourceVersion := existingK8sRes.GetResourceVersion(); resourceVersion == newResourceVersion { - // if the resourceVersion is the same, the update is not performed - klog.Infof("The k8s resource with apiversion: %s, kind: %s, %s/%s is not updated", apiversion, kind, namespace, name) - return true, nil - } - klog.Infof("updating k8s resource with apiversion: %s, kind: %s, %s/%s", apiversion, kind, namespace, name) + resourceVersion := existingK8sRes.GetResourceVersion() err = r.Update(ctx, &existingK8sRes) if err != nil { @@ -1120,8 +1150,10 @@ func (r *Reconciler) updateK8sResource(ctx context.Context, existingK8sRes unstr } - if UpdatedK8sRes.GetGeneration() != CRgeneration { + if UpdatedK8sRes.GetResourceVersion() != resourceVersion { klog.Infof("Finish updating the k8s Resource: -- Kind: %s, NamespacedName: %s/%s", kind, namespace, name) + } else { + klog.Infof("No updates on k8s resource with apiversion: %s, kind: %s, %s/%s", apiversion, kind, namespace, name) } } return true, nil diff --git a/controllers/operator/manager.go b/controllers/operator/manager.go index a455e02c..3a4bf4fd 100644 --- a/controllers/operator/manager.go +++ b/controllers/operator/manager.go @@ -60,7 +60,7 @@ func NewODLMOperator(mgr manager.Manager, name string) *ODLMOperator { Config: mgr.GetConfig(), Recorder: mgr.GetEventRecorderFor(name), Scheme: mgr.GetScheme(), - MaxConcurrentReconciles: 5, + MaxConcurrentReconciles: 3, } } diff --git a/controllers/operatorconfig/operatorconfig_controller.go b/controllers/operatorconfig/operatorconfig_controller.go index ae71f229..29b21974 100644 --- a/controllers/operatorconfig/operatorconfig_controller.go +++ b/controllers/operatorconfig/operatorconfig_controller.go @@ -21,6 +21,7 @@ import ( "github.com/barkimedes/go-deepcopy" olmv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1" + "k8s.io/apimachinery/pkg/api/equality" "k8s.io/apimachinery/pkg/types" "k8s.io/klog" ctrl "sigs.k8s.io/controller-runtime" @@ -169,7 +170,20 @@ func (r *Reconciler) requestsFromMapFunc(ctx context.Context) handler.MapFunc { func (r *Reconciler) SetupWithManager(mgr ctrl.Manager) error { ctx := context.Background() return ctrl.NewControllerManagedBy(mgr). - For(&operatorv1alpha1.OperandRequest{}). + For(&operatorv1alpha1.OperandRequest{}, builder.WithPredicates(predicate.Funcs{ + CreateFunc: func(e event.CreateEvent) bool { + return true + }, + DeleteFunc: func(e event.DeleteEvent) bool { + // Evaluates to false if the object has been confirmed deleted. + return !e.DeleteStateUnknown + }, + UpdateFunc: func(e event.UpdateEvent) bool { + oldObject := e.ObjectOld.(*operatorv1alpha1.OperandRequest) + newObject := e.ObjectNew.(*operatorv1alpha1.OperandRequest) + return !equality.Semantic.DeepEqual(oldObject.Spec, newObject.Spec) || !equality.Semantic.DeepEqual(oldObject.Status, newObject.Status) + }, + })). Watches(&source.Kind{Type: &operatorv1alpha1.OperatorConfig{}}, handler.EnqueueRequestsFromMapFunc(r.requestsFromMapFunc(ctx)), builder.WithPredicates(predicate.Funcs{ CreateFunc: func(e event.CreateEvent) bool { return true @@ -178,6 +192,11 @@ func (r *Reconciler) SetupWithManager(mgr ctrl.Manager) error { // Evaluates to false if the object has been confirmed deleted. return !e.DeleteStateUnknown }, + UpdateFunc: func(e event.UpdateEvent) bool { + oldObject := e.ObjectOld.(*operatorv1alpha1.OperatorConfig) + newObject := e.ObjectNew.(*operatorv1alpha1.OperatorConfig) + return !equality.Semantic.DeepEqual(oldObject.Spec, newObject.Spec) + }, })). Complete(r) } diff --git a/main.go b/main.go index 939b2e1c..45ba6bb9 100644 --- a/main.go +++ b/main.go @@ -81,7 +81,7 @@ func main() { flag.BoolVar(&enableLeaderElection, "enable-leader-election", false, "Enable leader election for controller manager. "+ "Enabling this will ensure there is only one active controller manager.") - var stepSize = flag.Int("batch-chunk-size", 1, "batch-chunk-size is used to control at most how many subscriptions will be created concurrently") + var stepSize = flag.Int("batch-chunk-size", 3, "batch-chunk-size is used to control at most how many subscriptions will be created concurrently") flag.Parse() From 13d2591049095888c6917b3d87c411de050afca5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 6 Jun 2024 11:30:55 +0800 Subject: [PATCH 114/179] build(deps): bump golang from 1.22.3-bullseye to 1.22.4-bullseye (#1051) Bumps golang from 1.22.3-bullseye to 1.22.4-bullseye. --- updated-dependencies: - dependency-name: golang dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 818d324b..c488094d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # Build the manager binary -FROM docker.io/golang:1.22.3-bullseye as builder +FROM docker.io/golang:1.22.4-bullseye as builder ARG GOARCH WORKDIR /workspace From d4a3db0f89b71d3ce0569ae5b51835f5ed2eb3cc Mon Sep 17 00:00:00 2001 From: Daniel Fan Date: Thu, 6 Jun 2024 11:10:12 -0400 Subject: [PATCH 115/179] Find CSVs by label for an operator, to ensure deleting all the CSVs for a specific subscription (#1055) * Find CSVs by label for an operator, to ensure deleting all the CSVs for a specific subscription Signed-off-by: Daniel Fan * Update test case Signed-off-by: Daniel Fan --------- Signed-off-by: Daniel Fan --- .../operandconfig_controller_test.go | 4 +- .../operandregistry_controller_test.go | 4 +- .../operandrequest_controller_test.go | 12 +++--- .../operandrequest/reconcile_operator.go | 42 +++++++++++-------- controllers/operator/manager.go | 38 +++++++++++++++++ controllers/testutil/test_util.go | 5 ++- 6 files changed, 76 insertions(+), 29 deletions(-) diff --git a/controllers/operandconfig/operandconfig_controller_test.go b/controllers/operandconfig/operandconfig_controller_test.go index 21b113f4..168d58c1 100644 --- a/controllers/operandconfig/operandconfig_controller_test.go +++ b/controllers/operandconfig/operandconfig_controller_test.go @@ -121,7 +121,7 @@ var _ = Describe("OperandConfig controller", func() { }, timeout, interval).Should(Succeed()) By("Creating and Setting status of the ClusterServiceVersions") - jaegerCSV := testutil.ClusterServiceVersion("jaeger-csv.v0.0.1", operatorNamespaceName, testutil.JaegerExample) + jaegerCSV := testutil.ClusterServiceVersion("jaeger-csv.v0.0.1", "jaeger", operatorNamespaceName, testutil.JaegerExample) Expect(k8sClient.Create(ctx, jaegerCSV)).Should(Succeed()) Eventually(func() error { k8sClient.Get(ctx, types.NamespacedName{Name: "jaeger-csv.v0.0.1", Namespace: operatorNamespaceName}, jaegerCSV) @@ -129,7 +129,7 @@ var _ = Describe("OperandConfig controller", func() { return k8sClient.Status().Update(ctx, jaegerCSV) }, timeout, interval).Should(Succeed()) - mongodbCSV := testutil.ClusterServiceVersion("mongodb-atlas-kubernetes-csv.v0.0.1", operatorNamespaceName, testutil.MongodbExample) + mongodbCSV := testutil.ClusterServiceVersion("mongodb-atlas-kubernetes-csv.v0.0.1", "mongodb-atlas-kubernetes", operatorNamespaceName, testutil.MongodbExample) Expect(k8sClient.Create(ctx, mongodbCSV)).Should(Succeed()) Eventually(func() error { k8sClient.Get(ctx, types.NamespacedName{Name: "mongodb-atlas-kubernetes-csv.v0.0.1", Namespace: operatorNamespaceName}, mongodbCSV) diff --git a/controllers/operandregistry/operandregistry_controller_test.go b/controllers/operandregistry/operandregistry_controller_test.go index 3a075e91..525f822e 100644 --- a/controllers/operandregistry/operandregistry_controller_test.go +++ b/controllers/operandregistry/operandregistry_controller_test.go @@ -120,7 +120,7 @@ var _ = Describe("OperandRegistry controller", func() { }, timeout, interval).Should(Succeed()) By("Creating and Setting status of the ClusterServiceVersions") - jaegerCSV := testutil.ClusterServiceVersion("jaeger-csv.v0.0.1", operatorNamespaceName, testutil.JaegerExample) + jaegerCSV := testutil.ClusterServiceVersion("jaeger-csv.v0.0.1", "jaeger", operatorNamespaceName, testutil.JaegerExample) Expect(k8sClient.Create(ctx, jaegerCSV)).Should(Succeed()) Eventually(func() error { k8sClient.Get(ctx, types.NamespacedName{Name: "jaeger-csv.v0.0.1", Namespace: operatorNamespaceName}, jaegerCSV) @@ -128,7 +128,7 @@ var _ = Describe("OperandRegistry controller", func() { return k8sClient.Status().Update(ctx, jaegerCSV) }, timeout, interval).Should(Succeed()) - mongodbCSV := testutil.ClusterServiceVersion("mongodb-atlas-kubernetes-csv.v0.0.1", operatorNamespaceName, testutil.MongodbExample) + mongodbCSV := testutil.ClusterServiceVersion("mongodb-atlas-kubernetes-csv.v0.0.1", "mongodb-atlas-kubernetes", operatorNamespaceName, testutil.MongodbExample) Expect(k8sClient.Create(ctx, mongodbCSV)).Should(Succeed()) Eventually(func() error { k8sClient.Get(ctx, types.NamespacedName{Name: "mongodb-atlas-kubernetes-csv.v0.0.1", Namespace: operatorNamespaceName}, mongodbCSV) diff --git a/controllers/operandrequest/operandrequest_controller_test.go b/controllers/operandrequest/operandrequest_controller_test.go index 5b36c35a..a63ad87d 100644 --- a/controllers/operandrequest/operandrequest_controller_test.go +++ b/controllers/operandrequest/operandrequest_controller_test.go @@ -140,7 +140,7 @@ var _ = Describe("OperandRequest controller", func() { }, testutil.Timeout, testutil.Interval).Should(Succeed()) By("Creating and Setting status of the ClusterServiceVersions") - jaegerCSV := testutil.ClusterServiceVersion("jaeger-csv.v0.0.1", operatorNamespaceName, testutil.JaegerExample) + jaegerCSV := testutil.ClusterServiceVersion("jaeger-csv.v0.0.1", "jaeger", operatorNamespaceName, testutil.JaegerExample) Expect(k8sClient.Create(ctx, jaegerCSV)).Should(Succeed()) Eventually(func() error { k8sClient.Get(ctx, types.NamespacedName{Name: "jaeger-csv.v0.0.1", Namespace: operatorNamespaceName}, jaegerCSV) @@ -148,7 +148,7 @@ var _ = Describe("OperandRequest controller", func() { return k8sClient.Status().Update(ctx, jaegerCSV) }, testutil.Timeout, testutil.Interval).Should(Succeed()) - mongodbCSV := testutil.ClusterServiceVersion("mongodb-atlas-kubernetes-csv.v0.0.1", operatorNamespaceName, testutil.MongodbExample) + mongodbCSV := testutil.ClusterServiceVersion("mongodb-atlas-kubernetes-csv.v0.0.1", "mongodb-atlas-kubernetes", operatorNamespaceName, testutil.MongodbExample) Expect(k8sClient.Create(ctx, mongodbCSV)).Should(Succeed()) Eventually(func() error { k8sClient.Get(ctx, types.NamespacedName{Name: "mongodb-atlas-kubernetes-csv.v0.0.1", Namespace: operatorNamespaceName}, mongodbCSV) @@ -272,7 +272,7 @@ var _ = Describe("OperandRequest controller", func() { }, testutil.Timeout, testutil.Interval).Should(Succeed()) By("Creating and Setting status of the ClusterServiceVersions") - jaegerCSV := testutil.ClusterServiceVersion("jaeger-csv.v0.0.1", operatorNamespaceName, testutil.JaegerExample) + jaegerCSV := testutil.ClusterServiceVersion("jaeger-csv.v0.0.1", "jaeger", operatorNamespaceName, testutil.JaegerExample) Expect(k8sClient.Create(ctx, jaegerCSV)).Should(Succeed()) Eventually(func() error { k8sClient.Get(ctx, types.NamespacedName{Name: "jaeger-csv.v0.0.1", Namespace: operatorNamespaceName}, jaegerCSV) @@ -280,7 +280,7 @@ var _ = Describe("OperandRequest controller", func() { return k8sClient.Status().Update(ctx, jaegerCSV) }, testutil.Timeout, testutil.Interval).Should(Succeed()) - mongodbCSV := testutil.ClusterServiceVersion("mongodb-atlas-kubernetes-csv.v0.0.1", operatorNamespaceName, testutil.MongodbExample) + mongodbCSV := testutil.ClusterServiceVersion("mongodb-atlas-kubernetes-csv.v0.0.1", "mongodb-atlas-kubernetes", operatorNamespaceName, testutil.MongodbExample) Expect(k8sClient.Create(ctx, mongodbCSV)).Should(Succeed()) Eventually(func() error { k8sClient.Get(ctx, types.NamespacedName{Name: "mongodb-atlas-kubernetes-csv.v0.0.1", Namespace: operatorNamespaceName}, mongodbCSV) @@ -433,7 +433,7 @@ var _ = Describe("OperandRequest controller", func() { }, testutil.Timeout, testutil.Interval).Should(Succeed()) By("Creating and Setting status of the ClusterServiceVersions") - jaegerCSV := testutil.ClusterServiceVersion("jaeger-csv.v0.0.1", operatorNamespaceName, testutil.JaegerExample) + jaegerCSV := testutil.ClusterServiceVersion("jaeger-csv.v0.0.1", "jaeger", operatorNamespaceName, testutil.JaegerExample) Expect(k8sClient.Create(ctx, jaegerCSV)).Should(Succeed()) Eventually(func() error { k8sClient.Get(ctx, types.NamespacedName{Name: "jaeger-csv.v0.0.1", Namespace: operatorNamespaceName}, jaegerCSV) @@ -441,7 +441,7 @@ var _ = Describe("OperandRequest controller", func() { return k8sClient.Status().Update(ctx, jaegerCSV) }, testutil.Timeout, testutil.Interval).Should(Succeed()) - mongodbCSV := testutil.ClusterServiceVersion("mongodb-atlas-kubernetes-csv.v0.0.1", operatorNamespaceName, testutil.MongodbExample) + mongodbCSV := testutil.ClusterServiceVersion("mongodb-atlas-kubernetes-csv.v0.0.1", "mongodb-atlas-kubernetes", operatorNamespaceName, testutil.MongodbExample) Expect(k8sClient.Create(ctx, mongodbCSV)).Should(Succeed()) Eventually(func() error { k8sClient.Get(ctx, types.NamespacedName{Name: "mongodb-atlas-kubernetes-csv.v0.0.1", Namespace: operatorNamespaceName}, mongodbCSV) diff --git a/controllers/operandrequest/reconcile_operator.go b/controllers/operandrequest/reconcile_operator.go index 5c323c86..adb88acf 100644 --- a/controllers/operandrequest/reconcile_operator.go +++ b/controllers/operandrequest/reconcile_operator.go @@ -351,20 +351,23 @@ func (r *Reconciler) deleteSubscription(ctx context.Context, cr *operatorv1alpha klog.V(2).Infof("Deleting Subscription %s/%s ...", sub.Namespace, sub.Name) - csv, err := r.GetClusterServiceVersion(ctx, sub) + csvList, err := r.GetClusterServiceVersionList(ctx, sub) // If can't get CSV, requeue the request if err != nil { return err } - if csv != nil { - klog.V(3).Info("Set Deleting Condition in the operandRequest") - cr.SetDeletingCondition(csv.Name, operatorv1alpha1.ResourceTypeCsv, corev1.ConditionTrue, &r.Mutex) + if csvList != nil { + klog.Infof("Found %d ClusterServiceVersions for Subscription %s/%s", len(csvList), sub.Namespace, sub.Name) + for _, csv := range csvList { + klog.V(3).Info("Set Deleting Condition in the operandRequest") + cr.SetDeletingCondition(csv.Name, operatorv1alpha1.ResourceTypeCsv, corev1.ConditionTrue, &r.Mutex) - klog.V(1).Infof("Deleting the ClusterServiceVersion, Namespace: %s, Name: %s", csv.Namespace, csv.Name) - if err := r.Delete(ctx, csv); err != nil { - cr.SetDeletingCondition(csv.Name, operatorv1alpha1.ResourceTypeCsv, corev1.ConditionFalse, &r.Mutex) - return err + klog.V(1).Infof("Deleting the ClusterServiceVersion, Namespace: %s, Name: %s", csv.Namespace, csv.Name) + if err := r.Delete(ctx, csv); err != nil { + cr.SetDeletingCondition(csv.Name, operatorv1alpha1.ResourceTypeCsv, corev1.ConditionFalse, &r.Mutex) + return err + } } } @@ -426,16 +429,17 @@ func (r *Reconciler) uninstallOperatorsAndOperands(ctx context.Context, operandN return nil } - if csv, err := r.GetClusterServiceVersion(ctx, sub); err != nil { + if csvList, err := r.GetClusterServiceVersionList(ctx, sub); err != nil { // If can't get CSV, requeue the request return err - } else if csv != nil { + } else if csvList != nil { + klog.Infof("Found %d ClusterServiceVersions for Subscription %s/%s", len(csvList), sub.Namespace, sub.Name) if uninstallOperand { - klog.V(2).Infof("Deleting all the Custom Resources for CSV, Namespace: %s, Name: %s", csv.Namespace, csv.Name) - if err := r.deleteAllCustomResource(ctx, csv, requestInstance, configInstance, operandName, configInstance.Namespace); err != nil { + klog.V(2).Infof("Deleting all the Custom Resources for CSV, Namespace: %s, Name: %s", csvList[0].Namespace, csvList[0].Name) + if err := r.deleteAllCustomResource(ctx, csvList[0], requestInstance, configInstance, operandName, configInstance.Namespace); err != nil { return err } - klog.V(2).Infof("Deleting all the k8s Resources for CSV, Namespace: %s, Name: %s", csv.Namespace, csv.Name) + klog.V(2).Infof("Deleting all the k8s Resources for CSV, Namespace: %s, Name: %s", csvList[0].Namespace, csvList[0].Name) if err := r.deleteAllK8sResource(ctx, configInstance, operandName, configInstance.Namespace); err != nil { return err } @@ -447,12 +451,14 @@ func (r *Reconciler) uninstallOperatorsAndOperands(ctx context.Context, operandN } klog.V(3).Info("Set Deleting Condition in the operandRequest") - requestInstance.SetDeletingCondition(csv.Name, operatorv1alpha1.ResourceTypeCsv, corev1.ConditionTrue, &r.Mutex) + requestInstance.SetDeletingCondition(csvList[0].Name, operatorv1alpha1.ResourceTypeCsv, corev1.ConditionTrue, &r.Mutex) - klog.V(1).Infof("Deleting the ClusterServiceVersion, Namespace: %s, Name: %s", csv.Namespace, csv.Name) - if err := r.Delete(ctx, csv); err != nil { - requestInstance.SetDeletingCondition(csv.Name, operatorv1alpha1.ResourceTypeCsv, corev1.ConditionFalse, &r.Mutex) - return errors.Wrap(err, "failed to delete the ClusterServiceVersion") + for _, csv := range csvList { + klog.V(1).Infof("Deleting the ClusterServiceVersion, Namespace: %s, Name: %s", csv.Namespace, csv.Name) + if err := r.Delete(ctx, csv); err != nil { + requestInstance.SetDeletingCondition(csv.Name, operatorv1alpha1.ResourceTypeCsv, corev1.ConditionFalse, &r.Mutex) + return errors.Wrapf(err, "failed to delete the ClusterServiceVersion %s/%s", csv.Namespace, csv.Name) + } } } } diff --git a/controllers/operator/manager.go b/controllers/operator/manager.go index 3a4bf4fd..b43c98da 100644 --- a/controllers/operator/manager.go +++ b/controllers/operator/manager.go @@ -391,6 +391,44 @@ func (m *ODLMOperator) GetClusterServiceVersion(ctx context.Context, sub *olmv1a return csv, nil } +// GetClusterServiceVersionList gets a list of ClusterServiceVersions from the subscription +func (m *ODLMOperator) GetClusterServiceVersionList(ctx context.Context, sub *olmv1alpha1.Subscription) ([]*olmv1alpha1.ClusterServiceVersion, error) { + // Check if subscription is nil + if sub == nil { + klog.Error("The subscription is nil") + return nil, fmt.Errorf("the subscription is nil") + } + + packageName := sub.Spec.Package + csvNamespace := sub.Namespace + + // Get the ClusterServiceVersion list with label operators.coreos.com/packageName.csvNamespace='' + csvList := &olmv1alpha1.ClusterServiceVersionList{} + opts := []client.ListOption{ + client.MatchingLabels{fmt.Sprintf("operators.coreos.com/%s.%s", packageName, csvNamespace): ""}, + client.InNamespace(csvNamespace), + } + + if err := m.Reader.List(ctx, csvList, opts...); err != nil { + if apierrors.IsNotFound(err) || len(csvList.Items) == 0 { + klog.V(3).Infof("No ClusterServiceVersion found with label operators.coreos.com/%s.%s", packageName, csvNamespace) + return nil, nil + } + return nil, errors.Wrapf(err, "failed to list ClusterServiceVersions with label operators.coreos.com/%s.%s", packageName, csvNamespace) + } else if len(csvList.Items) > 1 { + klog.Warningf("Multiple ClusterServiceVersions found with label operators.coreos.com/%s.%s", packageName, csvNamespace) + } + + var csvs []*olmv1alpha1.ClusterServiceVersion + for i := range csvList.Items { + klog.V(3).Infof("Get ClusterServiceVersion %s in the namespace %s", csvList.Items[i].Name, csvNamespace) + csvs = append(csvs, &csvList.Items[i]) + } + + klog.V(3).Infof("Get %v ClusterServiceVersions in the namespace %s", len(csvs), csvNamespace) + return csvs, nil +} + // GetOperatorNamespace returns the operator namespace based on the install mode func (m *ODLMOperator) GetOperatorNamespace(installMode, namespace string) string { if installMode == apiv1alpha1.InstallModeCluster { diff --git a/controllers/testutil/test_util.go b/controllers/testutil/test_util.go index 9308e5f5..4eddc18e 100644 --- a/controllers/testutil/test_util.go +++ b/controllers/testutil/test_util.go @@ -495,7 +495,7 @@ func SubscriptionStatus(name, namespace, csvVersion string) olmv1alpha1.Subscrip } } -func ClusterServiceVersion(name, namespace, example string) *olmv1alpha1.ClusterServiceVersion { +func ClusterServiceVersion(name, packageName, namespace, example string) *olmv1alpha1.ClusterServiceVersion { return &olmv1alpha1.ClusterServiceVersion{ ObjectMeta: metav1.ObjectMeta{ Name: name, @@ -503,6 +503,9 @@ func ClusterServiceVersion(name, namespace, example string) *olmv1alpha1.Cluster Annotations: map[string]string{ "alm-examples": example, }, + Labels: map[string]string{ + "operators.coreos.com/" + packageName + "." + namespace: "", + }, }, Spec: olmv1alpha1.ClusterServiceVersionSpec{ InstallStrategy: olmv1alpha1.NamedInstallStrategy{ From 484e3ee3ec13570dded30ecc4c715e388d65b902 Mon Sep 17 00:00:00 2001 From: Daniel Fan Date: Thu, 6 Jun 2024 11:20:11 -0400 Subject: [PATCH 116/179] Raise error when there is no catalog found for a operator (#1054) Signed-off-by: Daniel Fan --- controllers/operandrequest/reconcile_operator.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/controllers/operandrequest/reconcile_operator.go b/controllers/operandrequest/reconcile_operator.go index adb88acf..c9597748 100644 --- a/controllers/operandrequest/reconcile_operator.go +++ b/controllers/operandrequest/reconcile_operator.go @@ -229,6 +229,9 @@ func (r *Reconciler) reconcileSubscription(ctx context.Context, requestInstance if semver.IsValid(sub.Spec.Channel) && semver.IsValid(opt.Channel) && semver.Compare(sub.Spec.Channel, opt.Channel) < 0 { sub.Annotations[requestInstance.Namespace+"."+requestInstance.Name+"."+operand.Name+"/request"] = sub.Spec.Channel } + } else if opt.SourceNamespace == "" || opt.SourceName == "" { + klog.Errorf("Failed to find catalogsource for operator %s with channel %s", opt.Name, opt.Channel) + requestInstance.SetMemberStatus(operand.Name, operatorv1alpha1.OperatorFailed, "", mu) } else { requestInstance.SetNotFoundOperatorFromRegistryCondition(operand.Name, operatorv1alpha1.ResourceTypeSub, corev1.ConditionFalse, mu) From 4bb675f09209a0a4973f37bdfe098d26ad0f33c6 Mon Sep 17 00:00:00 2001 From: Daniel Fan Date: Fri, 7 Jun 2024 19:01:15 -0400 Subject: [PATCH 117/179] Refactor members and services status update (#1056) * Refactor members and services status update Signed-off-by: Daniel Fan * Update typo in log message Signed-off-by: Daniel Fan * Re-construct if condition for better code readability Signed-off-by: Daniel Fan --------- Signed-off-by: Daniel Fan --- api/v1alpha1/operandrequest_types.go | 60 ++-------------- controllers/constant/constant.go | 3 + .../operandrequest_controller.go | 20 ++---- .../operandrequest/reconcile_operand.go | 68 +++++++++++++++---- 4 files changed, 69 insertions(+), 82 deletions(-) diff --git a/api/v1alpha1/operandrequest_types.go b/api/v1alpha1/operandrequest_types.go index 6a1651be..717e49ac 100644 --- a/api/v1alpha1/operandrequest_types.go +++ b/api/v1alpha1/operandrequest_types.go @@ -631,12 +631,16 @@ func (r *OperandRequest) GetRegistryKey(req Request) types.NamespacedName { } // InitRequestStatus OperandConfig status. -func (r *OperandRequest) InitRequestStatus() bool { +func (r *OperandRequest) InitRequestStatus(mu sync.Locker) bool { isInitialized := true if r.Status.Phase == "" { isInitialized = false - r.Status.Phase = ClusterPhaseNone } + for _, member := range r.Status.Members { + klog.V(2).Info("Cleaning the member status for Operand: ", member.Name) + r.RemoveOperandPhase(member.Name, mu) + } + r.Status.Phase = ClusterPhaseNone return isInitialized } @@ -679,58 +683,6 @@ func (r *OperandRequest) UpdateLabels() bool { return isUpdated } -func (r *OperandRequest) CheckServiceStatus() bool { - requeue := false - monitoredServices := []string{"ibm-iam-operator", "ibm-idp-config-ui-operator", "ibm-mongodb-operator", "ibm-im-operator"} - servicesRequested := false - for _, serviceName := range monitoredServices { - if foundOperand(r.Spec.Requests, serviceName) { - servicesRequested = true - break - } - } - if servicesRequested { - if len(r.Status.Services) == 0 { - klog.Info("Waiting for status.services to be instantiated ...") - requeue = true - return requeue - } - var IMOrIAM string - exists := false - if foundOperand(r.Spec.Requests, "ibm-iam-operator") { - IMOrIAM = "ibm-iam-operator" - exists = true - } else if foundOperand(r.Spec.Requests, "ibm-im-operator") { - IMOrIAM = "ibm-im-operator" - exists = true - } - - if exists { - var imIndex int - found := false - for i, s := range r.Status.Services { - if IMOrIAM == s.OperatorName { //eventually this should be changed to the variable but the operator name is still listed as iam in practice even when im is requested - found = true - imIndex = i - break - } - } - if found { - if r.Status.Services[imIndex].Status != "Ready" { - klog.Info("Waiting for IM service to be Ready ...") - requeue = true - return requeue - } - } else { - klog.Info("Waiting for IM service status ...") - requeue = true - return requeue - } - } - } - return requeue -} - // GetAllRegistryReconcileRequest gets all the Registry ReconcileRequest. func (r *OperandRequest) GetAllRegistryReconcileRequest() []reconcile.Request { rrs := []reconcile.Request{} diff --git a/controllers/constant/constant.go b/controllers/constant/constant.go index 1e09eb3e..d9bdaa8e 100644 --- a/controllers/constant/constant.go +++ b/controllers/constant/constant.go @@ -93,4 +93,7 @@ const ( //DefaultCRRetryNumber is the default maximum number of retry for reconciling a custom resource DefaultCRRetryNumber = 3 + + //StatusMonitoredServices is the annotation key for monitored services + StatusMonitoredServices = "status-monitored-services" ) diff --git a/controllers/operandrequest/operandrequest_controller.go b/controllers/operandrequest/operandrequest_controller.go index 96c45736..b00fee48 100644 --- a/controllers/operandrequest/operandrequest_controller.go +++ b/controllers/operandrequest/operandrequest_controller.go @@ -144,7 +144,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctrl.Re } // Initialize the status for OperandRequest instance - if !requestInstance.InitRequestStatus() { + if !requestInstance.InitRequestStatus(&r.Mutex) { return ctrl.Result{Requeue: true}, nil } @@ -156,18 +156,6 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctrl.Re return ctrl.Result{Requeue: true}, err } - // Clean the phase of each operand under spec.request.operand - for _, member := range requestInstance.Status.Members { - klog.V(2).Info("Cleaning the member status for Operand: ", member.Name) - requestInstance.RemoveOperandPhase(member.Name, &r.Mutex) - } - requestInstance.Status.Phase = operatorv1alpha1.ClusterPhaseNone - - if err := r.Client.Status().Update(ctx, requestInstance); err != nil { - klog.Errorf("failed to update the status of the OperandRequest %s: %v", req.NamespacedName.String(), err) - return ctrl.Result{}, err - } - // Reconcile Operators if err := r.reconcileOperator(ctx, requestInstance); err != nil { klog.Errorf("failed to reconcile Operators for OperandRequest %s: %v", req.NamespacedName.String(), err) @@ -186,8 +174,8 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctrl.Re return ctrl.Result{RequeueAfter: constant.DefaultRequeueDuration}, nil } - //check if status.services is present (if a relevant service was requested), requeue again is im/iam is not ready yet - if requestInstance.CheckServiceStatus() { + //check if status.services is present (if a relevant service was requested), requeue again if service is not ready yet + if isReady, err := r.ServiceStatusIsReady(ctx, requestInstance); !isReady || err != nil { return ctrl.Result{RequeueAfter: constant.DefaultRequeueDuration}, nil } @@ -416,7 +404,7 @@ func (r *Reconciler) SetupWithManager(mgr ctrl.Manager) error { UpdateFunc: func(e event.UpdateEvent) bool { oldObject := e.ObjectOld.(*operatorv1alpha1.OperandRegistry) newObject := e.ObjectNew.(*operatorv1alpha1.OperandRegistry) - return !reflect.DeepEqual(oldObject.Spec, newObject.Spec) + return !reflect.DeepEqual(oldObject.Spec, newObject.Spec) || !reflect.DeepEqual(oldObject.GetAnnotations(), newObject.GetAnnotations()) }, DeleteFunc: func(e event.DeleteEvent) bool { // Evaluates to false if the object has been confirmed deleted. diff --git a/controllers/operandrequest/reconcile_operand.go b/controllers/operandrequest/reconcile_operand.go index af5276d6..3966b00c 100644 --- a/controllers/operandrequest/reconcile_operand.go +++ b/controllers/operandrequest/reconcile_operand.go @@ -326,17 +326,16 @@ func (r *Reconciler) reconcileCRwithConfig(ctx context.Context, service *operato merr.Add(err) continue } - statusSpec, err := r.getOperandStatus(crFromALM) + statusFromCR, err := r.getOperandStatus(crFromALM) if err != nil { return err } serviceKind := crFromALM.GetKind() - if serviceKind != "OperandRequest" && statusSpec.ObjectName != "" { + if serviceKind != "OperandRequest" && statusFromCR.ObjectName != "" { var resources []operatorv1alpha1.OperandStatus - resources = append(resources, statusSpec) - serviceSpec := newServiceStatus(operandName, operatorNamespace, resources) - seterr := requestInstance.SetServiceStatus(ctx, serviceSpec, r.Client, mu) - if seterr != nil { + resources = append(resources, statusFromCR) + serviceStatus := newServiceStatus(operandName, operatorNamespace, resources) + if seterr := requestInstance.SetServiceStatus(ctx, serviceStatus, r.Client, mu); seterr != nil { return seterr } } @@ -410,15 +409,15 @@ func (r *Reconciler) reconcileCRwithRequest(ctx context.Context, requestInstance if err := r.updateCustomResource(ctx, crFromRequest, requestKey.Namespace, operand.Kind, operand.Spec.Raw, map[string]interface{}{}, requestInstance); err != nil { return err } - statusSpec, err := r.getOperandStatus(crFromRequest) + statusFromCR, err := r.getOperandStatus(crFromRequest) if err != nil { return err } - if operand.Kind != "OperandRequest" && statusSpec.ObjectName != "" { + if operand.Kind != "OperandRequest" && statusFromCR.ObjectName != "" { var resources []operatorv1alpha1.OperandStatus - resources = append(resources, statusSpec) - serviceSpec := newServiceStatus(operand.Name, operatorNamespace, resources) - seterr := requestInstance.SetServiceStatus(ctx, serviceSpec, r.Client, mu) + resources = append(resources, statusFromCR) + serviceStatus := newServiceStatus(operand.Name, operatorNamespace, resources) + seterr := requestInstance.SetServiceStatus(ctx, serviceStatus, r.Client, mu) if seterr != nil { return seterr } @@ -481,7 +480,6 @@ func newServiceStatus(operatorName string, namespace string, resources []operato } } serviceSpec.Status = status //TODO logic to determine readiness - // serviceSpec.LastUpdateTime = time.Now().Format(time.RFC3339) serviceSpec.Resources = resources return serviceSpec } @@ -1358,3 +1356,49 @@ func (r *Reconciler) setOwnerReferences(ctx context.Context, controlledRes *unst } return nil } + +func (r *Reconciler) ServiceStatusIsReady(ctx context.Context, requestInstance *operatorv1alpha1.OperandRequest) (bool, error) { + requestedServicesSet := make(map[string]struct{}) + for _, req := range requestInstance.Spec.Requests { + registryKey := requestInstance.GetRegistryKey(req) + registryInstance, err := r.GetOperandRegistry(ctx, registryKey) + if err != nil { + klog.Errorf("Failed to get OperandRegistry %s, %v", registryKey, err) + return false, err + } + if registryInstance.Annotations != nil && registryInstance.Annotations[constant.StatusMonitoredServices] != "" { + monitoredServices := strings.Split(registryInstance.Annotations[constant.StatusMonitoredServices], ",") + for _, operand := range req.Operands { + if util.Contains(monitoredServices, operand.Name) { + requestedServicesSet[operand.Name] = struct{}{} + } + } + } + } + + if len(requestedServicesSet) == 0 { + klog.V(2).Infof("No services to be monitored for OperandRequest %s/%s", requestInstance.Namespace, requestInstance.Name) + return true, nil + } + + if len(requestInstance.Status.Services) == 0 { + klog.Infof("Waiting for status.services to be instantiated for OperandRequest %s/%s ...", requestInstance.Namespace, requestInstance.Name) + return false, nil + } + if len(requestedServicesSet) != len(requestInstance.Status.Services) { + klog.Infof("Waiting for status of all requested services to be instantiated for OperandRequest %s/%s ...", requestInstance.Namespace, requestInstance.Name) + return false, nil + } + + serviceStatus := true + // wait for the status of the requested services to be ready + for _, s := range requestInstance.Status.Services { + if _, ok := requestedServicesSet[s.OperatorName]; ok { + if s.Status != "Ready" { + klog.Infof("Waiting for status of service %s to be Ready for OperandRequest %s/%s ...", s.OperatorName, requestInstance.Namespace, requestInstance.Name) + serviceStatus = false + } + } + } + return serviceStatus, nil +} From 929e795fab3d7a4432c513f8ca89197e0d4d883a Mon Sep 17 00:00:00 2001 From: Daniel Fan Date: Thu, 20 Jun 2024 14:20:24 -0400 Subject: [PATCH 118/179] Bump version to 4.3.3 for SC2 4.6.4 (#1058) Signed-off-by: Daniel Fan --- Makefile | 2 +- ...eployment-lifecycle-manager.clusterserviceversion.yaml | 8 ++++---- ...eployment-lifecycle-manager.clusterserviceversion.yaml | 4 ++-- version/version.go | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Makefile b/Makefile index e611955c..2bd7f4cd 100644 --- a/Makefile +++ b/Makefile @@ -84,7 +84,7 @@ OPERATOR_IMAGE_NAME ?= odlm # Current Operator bundle image name BUNDLE_IMAGE_NAME ?= odlm-operator-bundle # Current Operator version -OPERATOR_VERSION ?= 4.3.2 +OPERATOR_VERSION ?= 4.3.3 # Kind cluster name KIND_CLUSTER_NAME ?= "odlm" diff --git a/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml b/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml index c934b4fa..2d222cb9 100644 --- a/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml +++ b/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml @@ -132,7 +132,7 @@ metadata: createdAt: "2024-04-04T03:40:45Z" description: The Operand Deployment Lifecycle Manager provides a Kubernetes CRD-based API to manage the lifecycle of operands. nss.operator.ibm.com/managed-operators: ibm-odlm - olm.skipRange: '>=1.2.0 <4.3.2' + olm.skipRange: '>=1.2.0 <4.3.3' operators.openshift.io/infrastructure-features: '["disconnected"]' operators.operatorframework.io/builder: operator-sdk-v1.32.0 operators.operatorframework.io/project_layout: go.kubebuilder.io/v3 @@ -143,7 +143,7 @@ metadata: operatorframework.io/arch.ppc64le: supported operatorframework.io/arch.s390x: supported operatorframework.io/os.linux: supported - name: operand-deployment-lifecycle-manager.v4.3.2 + name: operand-deployment-lifecycle-manager.v4.3.3 namespace: placeholder spec: apiservicedefinitions: {} @@ -860,7 +860,7 @@ spec: minKubeVersion: 1.19.0 provider: name: IBM - version: 4.3.2 + version: 4.3.3 relatedImages: - - image: icr.io/cpopen/odlm:4.3.2 + - image: icr.io/cpopen/odlm:4.3.3 name: ODLM_IMAGE diff --git a/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml b/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml index 3524ce90..4e2a3435 100644 --- a/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml +++ b/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml @@ -11,7 +11,7 @@ metadata: description: The Operand Deployment Lifecycle Manager provides a Kubernetes CRD-based API to manage the lifecycle of operands. nss.operator.ibm.com/managed-operators: ibm-odlm - olm.skipRange: '>=1.2.0 <4.3.2' + olm.skipRange: '>=1.2.0 <4.3.3' operators.openshift.io/infrastructure-features: '["disconnected"]' operators.operatorframework.io/builder: operator-sdk-v1.2.0 operators.operatorframework.io/project_layout: go.kubebuilder.io/v2 @@ -482,6 +482,6 @@ spec: provider: name: IBM relatedImages: - - image: icr.io/cpopen/odlm:4.3.2 + - image: icr.io/cpopen/odlm:4.3.3 name: ODLM_IMAGE version: 0.0.0 diff --git a/version/version.go b/version/version.go index d8a15ba7..5da13293 100644 --- a/version/version.go +++ b/version/version.go @@ -17,5 +17,5 @@ package version var ( - Version = "4.3.2" + Version = "4.3.3" ) From d84fbf1bf3ce8c1ce046ad70f0e8023036b79b08 Mon Sep 17 00:00:00 2001 From: Travis CI User Date: Wed, 26 Jun 2024 15:58:17 +0000 Subject: [PATCH 119/179] Trigger build with new base image --- base_images.json | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/base_images.json b/base_images.json index 360c6e92..0956ca62 100644 --- a/base_images.json +++ b/base_images.json @@ -7,7 +7,7 @@ "destStage": "edge", "destNamespace": "build-images", "destImage": "ubi8", - "tag": "8.10-901.1716482497", + "tag": "8.10-901.1717584420", "updatePackages": [] }, { @@ -18,7 +18,7 @@ "destStage": "edge", "destNamespace": "build-images", "destImage": "ubi8-minimal", - "tag": "8.10-896.1716497715", + "tag": "8.10-896.1717584414", "updatePackages": [] }, { @@ -29,7 +29,7 @@ "destStage": "edge", "destNamespace": "build-images", "destImage": "ubi9-micro", - "tag": "9.4-6.1716471860", + "tag": "9.4-9", "updatePackages": [] }, { @@ -40,7 +40,7 @@ "destStage": "edge", "destNamespace": "build-images", "destImage": "ubi9", - "tag": "9.4-947.1716476138", + "tag": "9.4-1123", "updatePackages": [] }, { @@ -51,35 +51,35 @@ "destStage": "edge", "destNamespace": "build-images", "destImage": "ubi9-minimal", - "tag": "9.4-949.1716471857", + "tag": "9.4-1134", "updatePackages": [] }, { "imageType": "node", "sourceImage": "ubi8-minimal", - "sourceTag": "8.10-896.1716497715", + "sourceTag": "8.10-896.1717584414", "destImage": "node-v18-ubi8-minimal", "nodeVersion": "18.20.3" }, { "imageType": "node", "sourceImage": "ubi8-minimal", - "sourceTag": "8.10-896.1716497715", + "sourceTag": "8.10-896.1717584414", "destImage": "node-v20-ubi8-minimal", - "nodeVersion": "20.14.0" + "nodeVersion": "20.15.0" }, { "imageType": "node", "sourceImage": "ubi9-minimal", - "sourceTag": "9.4-949.1716471857", + "sourceTag": "9.4-1134", "destImage": "node-v18-ubi9-minimal", "nodeVersion": "18.20.3" }, { "imageType": "node", "sourceImage": "ubi9-minimal", - "sourceTag": "9.4-949.1716471857", + "sourceTag": "9.4-1134", "destImage": "node-v20-ubi9-minimal", - "nodeVersion": "20.14.0" + "nodeVersion": "20.15.0" } ] From afdc424ed15f2580dce2b4c4f20cb4a93963322e Mon Sep 17 00:00:00 2001 From: Allen Li <46284272+qpdpQ@users.noreply.github.com> Date: Mon, 22 Jul 2024 13:48:19 -0400 Subject: [PATCH 120/179] Bump version to 4.3.4 for SC2 4.6.5 (#1064) Signed-off-by: Allen Li --- Makefile | 2 +- ...eployment-lifecycle-manager.clusterserviceversion.yaml | 8 ++++---- ...eployment-lifecycle-manager.clusterserviceversion.yaml | 4 ++-- version/version.go | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Makefile b/Makefile index 2bd7f4cd..0edb08f4 100644 --- a/Makefile +++ b/Makefile @@ -84,7 +84,7 @@ OPERATOR_IMAGE_NAME ?= odlm # Current Operator bundle image name BUNDLE_IMAGE_NAME ?= odlm-operator-bundle # Current Operator version -OPERATOR_VERSION ?= 4.3.3 +OPERATOR_VERSION ?= 4.3.4 # Kind cluster name KIND_CLUSTER_NAME ?= "odlm" diff --git a/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml b/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml index 2d222cb9..15b22d91 100644 --- a/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml +++ b/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml @@ -132,7 +132,7 @@ metadata: createdAt: "2024-04-04T03:40:45Z" description: The Operand Deployment Lifecycle Manager provides a Kubernetes CRD-based API to manage the lifecycle of operands. nss.operator.ibm.com/managed-operators: ibm-odlm - olm.skipRange: '>=1.2.0 <4.3.3' + olm.skipRange: '>=1.2.0 <4.3.4' operators.openshift.io/infrastructure-features: '["disconnected"]' operators.operatorframework.io/builder: operator-sdk-v1.32.0 operators.operatorframework.io/project_layout: go.kubebuilder.io/v3 @@ -143,7 +143,7 @@ metadata: operatorframework.io/arch.ppc64le: supported operatorframework.io/arch.s390x: supported operatorframework.io/os.linux: supported - name: operand-deployment-lifecycle-manager.v4.3.3 + name: operand-deployment-lifecycle-manager.v4.3.4 namespace: placeholder spec: apiservicedefinitions: {} @@ -860,7 +860,7 @@ spec: minKubeVersion: 1.19.0 provider: name: IBM - version: 4.3.3 + version: 4.3.4 relatedImages: - - image: icr.io/cpopen/odlm:4.3.3 + - image: icr.io/cpopen/odlm:4.3.4 name: ODLM_IMAGE diff --git a/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml b/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml index 4e2a3435..5aa1e269 100644 --- a/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml +++ b/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml @@ -11,7 +11,7 @@ metadata: description: The Operand Deployment Lifecycle Manager provides a Kubernetes CRD-based API to manage the lifecycle of operands. nss.operator.ibm.com/managed-operators: ibm-odlm - olm.skipRange: '>=1.2.0 <4.3.3' + olm.skipRange: '>=1.2.0 <4.3.4' operators.openshift.io/infrastructure-features: '["disconnected"]' operators.operatorframework.io/builder: operator-sdk-v1.2.0 operators.operatorframework.io/project_layout: go.kubebuilder.io/v2 @@ -482,6 +482,6 @@ spec: provider: name: IBM relatedImages: - - image: icr.io/cpopen/odlm:4.3.3 + - image: icr.io/cpopen/odlm:4.3.4 name: ODLM_IMAGE version: 0.0.0 diff --git a/version/version.go b/version/version.go index 5da13293..a11d17c6 100644 --- a/version/version.go +++ b/version/version.go @@ -17,5 +17,5 @@ package version var ( - Version = "4.3.3" + Version = "4.3.4" ) From 223a3cf41d223e26d9c168a1bacb305827890ae3 Mon Sep 17 00:00:00 2001 From: Travis CI User Date: Tue, 23 Jul 2024 22:44:40 +0000 Subject: [PATCH 121/179] Trigger build with new base image --- base_images.json | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/base_images.json b/base_images.json index 0956ca62..bd8d9e44 100644 --- a/base_images.json +++ b/base_images.json @@ -7,7 +7,7 @@ "destStage": "edge", "destNamespace": "build-images", "destImage": "ubi8", - "tag": "8.10-901.1717584420", + "tag": "8.10-1020", "updatePackages": [] }, { @@ -18,7 +18,7 @@ "destStage": "edge", "destNamespace": "build-images", "destImage": "ubi8-minimal", - "tag": "8.10-896.1717584414", + "tag": "8.10-1018", "updatePackages": [] }, { @@ -40,7 +40,7 @@ "destStage": "edge", "destNamespace": "build-images", "destImage": "ubi9", - "tag": "9.4-1123", + "tag": "9.4-1123.1719560047", "updatePackages": [] }, { @@ -57,29 +57,29 @@ { "imageType": "node", "sourceImage": "ubi8-minimal", - "sourceTag": "8.10-896.1717584414", + "sourceTag": "8.10-1018", "destImage": "node-v18-ubi8-minimal", - "nodeVersion": "18.20.3" + "nodeVersion": "18.20.4" }, { "imageType": "node", "sourceImage": "ubi8-minimal", - "sourceTag": "8.10-896.1717584414", + "sourceTag": "8.10-1018", "destImage": "node-v20-ubi8-minimal", - "nodeVersion": "20.15.0" + "nodeVersion": "20.15.1" }, { "imageType": "node", "sourceImage": "ubi9-minimal", "sourceTag": "9.4-1134", "destImage": "node-v18-ubi9-minimal", - "nodeVersion": "18.20.3" + "nodeVersion": "18.20.4" }, { "imageType": "node", "sourceImage": "ubi9-minimal", "sourceTag": "9.4-1134", "destImage": "node-v20-ubi9-minimal", - "nodeVersion": "20.15.0" + "nodeVersion": "20.15.1" } ] From 144cdd413f6e04feb0160c11ceea5c80a5ca3c5d Mon Sep 17 00:00:00 2001 From: Travis CI User Date: Wed, 24 Jul 2024 18:14:08 +0000 Subject: [PATCH 122/179] Trigger build with new base image --- base_images.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/base_images.json b/base_images.json index bd8d9e44..854b9e2c 100644 --- a/base_images.json +++ b/base_images.json @@ -29,7 +29,7 @@ "destStage": "edge", "destNamespace": "build-images", "destImage": "ubi9-micro", - "tag": "9.4-9", + "tag": "9.4-13", "updatePackages": [] }, { @@ -40,7 +40,7 @@ "destStage": "edge", "destNamespace": "build-images", "destImage": "ubi9", - "tag": "9.4-1123.1719560047", + "tag": "9.4-1181", "updatePackages": [] }, { @@ -51,7 +51,7 @@ "destStage": "edge", "destNamespace": "build-images", "destImage": "ubi9-minimal", - "tag": "9.4-1134", + "tag": "9.4-1194", "updatePackages": [] }, { @@ -71,14 +71,14 @@ { "imageType": "node", "sourceImage": "ubi9-minimal", - "sourceTag": "9.4-1134", + "sourceTag": "9.4-1194", "destImage": "node-v18-ubi9-minimal", "nodeVersion": "18.20.4" }, { "imageType": "node", "sourceImage": "ubi9-minimal", - "sourceTag": "9.4-1134", + "sourceTag": "9.4-1194", "destImage": "node-v20-ubi9-minimal", "nodeVersion": "20.15.1" } From c1ffca72a7b0298102132327425cda6a7cb0dff1 Mon Sep 17 00:00:00 2001 From: Travis CI User Date: Mon, 29 Jul 2024 17:17:15 +0000 Subject: [PATCH 123/179] Trigger build with new base image --- base_images.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/base_images.json b/base_images.json index 854b9e2c..5682e793 100644 --- a/base_images.json +++ b/base_images.json @@ -66,7 +66,7 @@ "sourceImage": "ubi8-minimal", "sourceTag": "8.10-1018", "destImage": "node-v20-ubi8-minimal", - "nodeVersion": "20.15.1" + "nodeVersion": "20.16.0" }, { "imageType": "node", @@ -80,6 +80,6 @@ "sourceImage": "ubi9-minimal", "sourceTag": "9.4-1194", "destImage": "node-v20-ubi9-minimal", - "nodeVersion": "20.15.1" + "nodeVersion": "20.16.0" } ] From 5b41ff8086bffeb3d6c8e01dc888ceb9611a5047 Mon Sep 17 00:00:00 2001 From: Ben Luzarraga <31223504+bluzarraga@users.noreply.github.com> Date: Tue, 30 Jul 2024 08:43:41 -0500 Subject: [PATCH 124/179] trigger build --- go.mod | 1 + 1 file changed, 1 insertion(+) diff --git a/go.mod b/go.mod index 89f38bc7..d6ed398b 100644 --- a/go.mod +++ b/go.mod @@ -112,3 +112,4 @@ require ( // fix vulnerability: CVE-2021-3121 in github.com/gogo/protobuf v1.2.1 replace github.com/gogo/protobuf => github.com/gogo/protobuf v1.3.2 + From 32ea607c0c7741847106f8497518adee1884c3ba Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Aug 2024 04:28:25 +0800 Subject: [PATCH 125/179] build(deps): bump golang from 1.22.4-bullseye to 1.22.5-bullseye (#1063) Bumps golang from 1.22.4-bullseye to 1.22.5-bullseye. --- updated-dependencies: - dependency-name: golang dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index c488094d..69cdc20c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # Build the manager binary -FROM docker.io/golang:1.22.4-bullseye as builder +FROM docker.io/golang:1.22.5-bullseye as builder ARG GOARCH WORKDIR /workspace From 17707a96042a767344c5c783b9772fd6b9f84c07 Mon Sep 17 00:00:00 2001 From: Daniel Fan Date: Wed, 31 Jul 2024 23:03:25 -0400 Subject: [PATCH 126/179] Clean redundant CSV in service ns during the migration (#1065) Signed-off-by: Daniel Fan --- .../operandrequest/reconcile_operand.go | 6 ++++ controllers/operator/manager.go | 31 +++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/controllers/operandrequest/reconcile_operand.go b/controllers/operandrequest/reconcile_operand.go index 3966b00c..36805205 100644 --- a/controllers/operandrequest/reconcile_operand.go +++ b/controllers/operandrequest/reconcile_operand.go @@ -154,6 +154,12 @@ func (r *Reconciler) reconcileOperand(ctx context.Context, requestInstance *oper continue } + if err := r.DeleteRedundantCSV(ctx, csv.Name, csv.Namespace, registryKey.Namespace, opdRegistry.PackageName); err != nil { + merr.Add(errors.Wrapf(err, "failed to delete the redundant ClusterServiceVersion %s in the namespace %s", csv.Name, csv.Namespace)) + requestInstance.SetMemberStatus(operand.Name, operatorv1alpha1.OperatorFailed, "", &r.Mutex) + continue + } + // find the OperandRequest which has the same operator's channel version as existing subscription. // ODLM will only reconcile Operand based on OperandConfig for this OperandRequest var requestList []string diff --git a/controllers/operator/manager.go b/controllers/operator/manager.go index b43c98da..810987ec 100644 --- a/controllers/operator/manager.go +++ b/controllers/operator/manager.go @@ -429,6 +429,37 @@ func (m *ODLMOperator) GetClusterServiceVersionList(ctx context.Context, sub *ol return csvs, nil } +func (m *ODLMOperator) DeleteRedundantCSV(ctx context.Context, csvName, operatorNs, serviceNs, packageName string) error { + // Get the csv by its name and namespace + csv := &olmv1alpha1.ClusterServiceVersion{} + csvKey := types.NamespacedName{ + Name: csvName, + Namespace: serviceNs, + } + if err := m.Reader.Get(ctx, csvKey, csv); err != nil { + if apierrors.IsNotFound(err) { + klog.V(2).Infof("ClusterServiceVersion %s is not found", csvName) + return nil + } + return errors.Wrapf(err, "failed to get ClusterServiceVersion %s/%s", serviceNs, csvName) + } + + if csv.GetLabels() == nil { + klog.V(2).Infof("ClusterServiceVersion %s in the namespace %s has no label", csvName, serviceNs) + return nil + } + // Delete the CSV if the csv does not contain label operators.coreos.com/packageName.operatorNs='' AND does not contains label olm.copiedFrom: operatorNs + if _, ok := csv.GetLabels()[fmt.Sprintf("operators.coreos.com/%s.%s", packageName, operatorNs)]; !ok { + if csv.GetLabels()["olm.copiedFrom"] != operatorNs { + klog.Infof("Delete the redundant ClusterServiceVersion %s in the namespace %s", csvName, serviceNs) + if err := m.Client.Delete(ctx, csv); err != nil { + return errors.Wrapf(err, "failed to delete ClusterServiceVersion %s/%s", serviceNs, csvName) + } + } + } + return nil +} + // GetOperatorNamespace returns the operator namespace based on the install mode func (m *ODLMOperator) GetOperatorNamespace(installMode, namespace string) string { if installMode == apiv1alpha1.InstallModeCluster { From d54ec80277d8db0ec5ddde0dd32a0c32078fe1f2 Mon Sep 17 00:00:00 2001 From: Daniel Fan Date: Thu, 1 Aug 2024 17:31:26 -0400 Subject: [PATCH 127/179] Find semantic versioning from channel (#1066) Signed-off-by: Daniel Fan --- .../operandrequest/reconcile_operator.go | 22 +---- controllers/util/util.go | 44 +++++++++ controllers/util/util_test.go | 99 +++++++++++++++++++ 3 files changed, 148 insertions(+), 17 deletions(-) diff --git a/controllers/operandrequest/reconcile_operator.go b/controllers/operandrequest/reconcile_operator.go index c9597748..bbd0d5d5 100644 --- a/controllers/operandrequest/reconcile_operator.go +++ b/controllers/operandrequest/reconcile_operator.go @@ -21,7 +21,6 @@ import ( "encoding/json" "fmt" "regexp" - "sort" "strings" "sync" "time" @@ -226,7 +225,9 @@ func (r *Reconciler) reconcileSubscription(ctx context.Context, requestInstance // check if sub.Spec.Channel and opt.Channel are valid semantic version // set annotation channel back to previous one if sub.Spec.Channel is lower than opt.Channel - if semver.IsValid(sub.Spec.Channel) && semver.IsValid(opt.Channel) && semver.Compare(sub.Spec.Channel, opt.Channel) < 0 { + subChanel := util.FindSemantic(sub.Spec.Channel) + optChannel := util.FindSemantic(opt.Channel) + if semver.IsValid(subChanel) && semver.IsValid(optChannel) && semver.Compare(subChanel, optChannel) < 0 { sub.Annotations[requestInstance.Namespace+"."+requestInstance.Name+"."+operand.Name+"/request"] = sub.Spec.Channel } } else if opt.SourceNamespace == "" || opt.SourceName == "" { @@ -235,21 +236,8 @@ func (r *Reconciler) reconcileSubscription(ctx context.Context, requestInstance } else { requestInstance.SetNotFoundOperatorFromRegistryCondition(operand.Name, operatorv1alpha1.ResourceTypeSub, corev1.ConditionFalse, mu) - // check request annotation in subscription, get all available channels - var semverlList []string - reg, _ := regexp.Compile(`^(.*)\.(.*)\.(.*)\/request`) - for anno, channel := range sub.Annotations { - if reg.MatchString(anno) && semver.IsValid(channel) { - semverlList = append(semverlList, channel) - } - } - if len(semverlList) == 0 { - // channel is not valid semantic version - sub.Spec.Channel = opt.Channel - } else if !util.Contains(semverlList, sub.Spec.Channel) { - // upgrade channel to minimal version existing in annotation - sort.Sort(semver.ByVersion(semverlList)) - sub.Spec.Channel = semverlList[0] + if minChannel := util.FindMinSemver(sub.Annotations, sub.Spec.Channel); minChannel != "" { + sub.Spec.Channel = minChannel } // update the spec iff channel in sub matches channel in opreg diff --git a/controllers/util/util.go b/controllers/util/util.go index fbb1b435..6beea00c 100644 --- a/controllers/util/util.go +++ b/controllers/util/util.go @@ -20,6 +20,7 @@ import ( "bytes" "fmt" "os" + "regexp" "sort" "strconv" "strings" @@ -27,6 +28,7 @@ import ( "time" ocproute "github.com/openshift/api/route/v1" + "golang.org/x/mod/semver" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/equality" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" @@ -334,3 +336,45 @@ func SanitizeObjectString(jsonPath string, data interface{}) (string, error) { } return sanitized, nil } + +// FindSemantic checks if a given string contains a substring which is a valid semantic version, and returns that substring +func FindSemantic(input string) string { + // Define the regular expression pattern for flexible semantic versions + semverPattern := `\bv?(\d+)(\.\d+)?(\.\d+)?\b` + + // Compile the regular expression + re := regexp.MustCompile(semverPattern) + + // Find the first match in the input string + match := re.FindString(input) + + // if no match is found, return default minimal version + if match == "" { + return "v0.0.0" + } + + return match +} + +// FindMinSemver returns the minimal semantic version from annotations +func FindMinSemver(annotations map[string]string, curChannel string) string { + // check request annotation in subscription, get all available channels + var semverlList []string + var semVerChannelMappings = make(map[string]string) + reg, _ := regexp.Compile(`^(.*)\.(.*)\.(.*)\/request`) + for anno, channel := range annotations { + prunedChannel := FindSemantic(channel) + if reg.MatchString(anno) && semver.IsValid(prunedChannel) { + semverlList = append(semverlList, prunedChannel) + semVerChannelMappings[prunedChannel] = channel + } + } + if len(semverlList) == 0 { + return "" + } else if !Contains(semverlList, FindSemantic(curChannel)) { + // upgrade channel to minimal version existing in annotation + sort.Sort(semver.ByVersion(semverlList)) + return semVerChannelMappings[semverlList[0]] + } + return curChannel +} diff --git a/controllers/util/util_test.go b/controllers/util/util_test.go index a76c3d76..7f04a2d0 100644 --- a/controllers/util/util_test.go +++ b/controllers/util/util_test.go @@ -111,3 +111,102 @@ var _ = Describe("Differs", func() { Expect(Differs(list, s)).Should(BeFalse()) }) }) + +var _ = Describe("FindSemantic", func() { + It("Should return the semantic vX version substring", func() { + input := "stable-v1" + expected := "v1" + Expect(FindSemantic(input)).Should(Equal(expected)) + }) + + It("Should return the semantic vX.Y version substring", func() { + input := "fast-v1.2" + expected := "v1.2" + Expect(FindSemantic(input)).Should(Equal(expected)) + }) + + It("Should return the original semantic vX.Y version substring", func() { + input := "v1.2" + expected := "v1.2" + Expect(FindSemantic(input)).Should(Equal(expected)) + }) + + It("Should return the semantic vX.Y.Z version substring", func() { + input := "stable-v1.2.3" + expected := "v1.2.3" + Expect(FindSemantic(input)).Should(Equal(expected)) + }) + + It("Should return an empty string if no semantic version is found", func() { + input := "This is a test string without a semantic version" + expected := "v0.0.0" + Expect(FindSemantic(input)).Should(Equal(expected)) + }) + + It("Should return the first semantic version substring", func() { + input := "This is a test v1.2.3 string with v0.1.0 multiple semantic versions" + expected := "v1.2.3" + Expect(FindSemantic(input)).Should(Equal(expected)) + }) +}) + +var _ = Describe("FindMinSemver", func() { + It("Should return the minimal semantic version from annotations", func() { + annotations := map[string]string{ + "namespace-a.common-service.operator-a/request": "stable", + "namespace-b.common-service.operator-b/request": "stable-v1.0", + "namespace-c.common-service.operator-c/request": "stable-v1.1.0", + "namespace-d.common-service.operator-d/request": "stable-v1.2.0", + } + curChannel := "stable-v1.3.0" + expected := "stable" + Expect(FindMinSemver(annotations, curChannel)).Should(Equal(expected)) + }) + + It("Should return the minimal semantic version from annotations", func() { + annotations := map[string]string{ + "namespace-b.common-service.operator-b/request": "v4.0", + "namespace-c.common-service.operator-c/request": "v4.1", + "namespace-d.common-service.operator-d/request": "v4.2", + } + curChannel := "v3" + expected := "v4.0" + Expect(FindMinSemver(annotations, curChannel)).Should(Equal(expected)) + }) + + It("Should return the current channel if it exists in annotations", func() { + annotations := map[string]string{ + "namespace-a.common-service.operator-a/request": "stable", + "namespace-b.common-service.operator-b/request": "stable-v1.0", + "namespace-c.common-service.operator-c/request": "stable-v1.1.0", + "namespace-d.common-service.operator-d/request": "stable-v1.2", + } + curChannel := "stable-v1.1.0" + expected := "stable-v1.1.0" + Expect(FindMinSemver(annotations, curChannel)).Should(Equal(expected)) + }) + + It("Should return the current channel if it exists in annotations", func() { + annotations := map[string]string{ + "namespace-a.common-service.operator-a/request": "stable", + "namespace-b.common-service.operator-b/request": "v1.0", + "namespace-c.common-service.operator-c/request": "v2.0", + "namespace-d.common-service.operator-d/request": "v2.0", + } + curChannel := "stable" + expected := "stable" + Expect(FindMinSemver(annotations, curChannel)).Should(Equal(expected)) + }) + + It("Should return an empty string if no valid semantic versions are found", func() { + annotations := map[string]string{ + "namespace-a.common-service.operator-a/config": "stable", + "namespace-b.common-service.operator-b/config": "stable-v1.0", + "namespace-c.common-service.operator-c/config": "stable-v1.1.0", + "namespace-d.common-service.operator-d/config": "stable-v1.2", + } + curChannel := "stable-v2.0.0" + expected := "" + Expect(FindMinSemver(annotations, curChannel)).Should(Equal(expected)) + }) +}) From 2bb0bd169d969ebf8f2dbbe6b859e8fab81d4b3c Mon Sep 17 00:00:00 2001 From: Allen Li <46284272+qpdpQ@users.noreply.github.com> Date: Tue, 13 Aug 2024 16:57:26 -0400 Subject: [PATCH 128/179] add securityContext .seccompProfile field (#1071) Signed-off-by: Allen Li --- ...rand-deployment-lifecycle-manager.clusterserviceversion.yaml | 2 ++ config/e2e/manager/manager.yaml | 2 ++ config/manager/manager.yaml | 2 ++ 3 files changed, 6 insertions(+) diff --git a/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml b/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml index 15b22d91..ba5fc07e 100644 --- a/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml +++ b/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml @@ -664,6 +664,8 @@ spec: ephemeral-storage: 256Mi memory: 200Mi securityContext: + seccompProfile: + type: RuntimeDefault allowPrivilegeEscalation: false capabilities: drop: diff --git a/config/e2e/manager/manager.yaml b/config/e2e/manager/manager.yaml index 3cf3c6eb..25c5270d 100644 --- a/config/e2e/manager/manager.yaml +++ b/config/e2e/manager/manager.yaml @@ -57,6 +57,8 @@ spec: cpu: 200m memory: 200Mi securityContext: + seccompProfile: + type: RuntimeDefault allowPrivilegeEscalation: false capabilities: drop: diff --git a/config/manager/manager.yaml b/config/manager/manager.yaml index 2262f521..7f1caa7d 100644 --- a/config/manager/manager.yaml +++ b/config/manager/manager.yaml @@ -87,6 +87,8 @@ spec: memory: 200Mi ephemeral-storage: 256Mi securityContext: + seccompProfile: + type: RuntimeDefault allowPrivilegeEscalation: false capabilities: drop: From 7cb1893a37c5bedafc6e7af33fd01b62c613dd53 Mon Sep 17 00:00:00 2001 From: Allen Li <46284272+qpdpQ@users.noreply.github.com> Date: Wed, 14 Aug 2024 14:18:27 -0400 Subject: [PATCH 129/179] Bump version to 4.3.5 for SC2 4.6.6 (#1074) Signed-off-by: Allen Li --- Makefile | 2 +- ...eployment-lifecycle-manager.clusterserviceversion.yaml | 8 ++++---- ...eployment-lifecycle-manager.clusterserviceversion.yaml | 4 ++-- version/version.go | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Makefile b/Makefile index 0edb08f4..819c36cb 100644 --- a/Makefile +++ b/Makefile @@ -84,7 +84,7 @@ OPERATOR_IMAGE_NAME ?= odlm # Current Operator bundle image name BUNDLE_IMAGE_NAME ?= odlm-operator-bundle # Current Operator version -OPERATOR_VERSION ?= 4.3.4 +OPERATOR_VERSION ?= 4.3.5 # Kind cluster name KIND_CLUSTER_NAME ?= "odlm" diff --git a/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml b/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml index ba5fc07e..db3acfe8 100644 --- a/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml +++ b/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml @@ -132,7 +132,7 @@ metadata: createdAt: "2024-04-04T03:40:45Z" description: The Operand Deployment Lifecycle Manager provides a Kubernetes CRD-based API to manage the lifecycle of operands. nss.operator.ibm.com/managed-operators: ibm-odlm - olm.skipRange: '>=1.2.0 <4.3.4' + olm.skipRange: '>=1.2.0 <4.3.5' operators.openshift.io/infrastructure-features: '["disconnected"]' operators.operatorframework.io/builder: operator-sdk-v1.32.0 operators.operatorframework.io/project_layout: go.kubebuilder.io/v3 @@ -143,7 +143,7 @@ metadata: operatorframework.io/arch.ppc64le: supported operatorframework.io/arch.s390x: supported operatorframework.io/os.linux: supported - name: operand-deployment-lifecycle-manager.v4.3.4 + name: operand-deployment-lifecycle-manager.v4.3.5 namespace: placeholder spec: apiservicedefinitions: {} @@ -862,7 +862,7 @@ spec: minKubeVersion: 1.19.0 provider: name: IBM - version: 4.3.4 + version: 4.3.5 relatedImages: - - image: icr.io/cpopen/odlm:4.3.4 + - image: icr.io/cpopen/odlm:4.3.5 name: ODLM_IMAGE diff --git a/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml b/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml index 5aa1e269..4c3d0a63 100644 --- a/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml +++ b/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml @@ -11,7 +11,7 @@ metadata: description: The Operand Deployment Lifecycle Manager provides a Kubernetes CRD-based API to manage the lifecycle of operands. nss.operator.ibm.com/managed-operators: ibm-odlm - olm.skipRange: '>=1.2.0 <4.3.4' + olm.skipRange: '>=1.2.0 <4.3.5' operators.openshift.io/infrastructure-features: '["disconnected"]' operators.operatorframework.io/builder: operator-sdk-v1.2.0 operators.operatorframework.io/project_layout: go.kubebuilder.io/v2 @@ -482,6 +482,6 @@ spec: provider: name: IBM relatedImages: - - image: icr.io/cpopen/odlm:4.3.4 + - image: icr.io/cpopen/odlm:4.3.5 name: ODLM_IMAGE version: 0.0.0 diff --git a/version/version.go b/version/version.go index a11d17c6..60309e1a 100644 --- a/version/version.go +++ b/version/version.go @@ -17,5 +17,5 @@ package version var ( - Version = "4.3.4" + Version = "4.3.5" ) From 41548e1ba88db5a09154c47478c9bb1ea590a2cf Mon Sep 17 00:00:00 2001 From: Travis CI User Date: Wed, 21 Aug 2024 15:48:37 +0000 Subject: [PATCH 130/179] Trigger build with new base image --- base_images.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/base_images.json b/base_images.json index 5682e793..df2fb96c 100644 --- a/base_images.json +++ b/base_images.json @@ -7,7 +7,7 @@ "destStage": "edge", "destNamespace": "build-images", "destImage": "ubi8", - "tag": "8.10-1020", + "tag": "8.10-1054", "updatePackages": [] }, { @@ -18,7 +18,7 @@ "destStage": "edge", "destNamespace": "build-images", "destImage": "ubi8-minimal", - "tag": "8.10-1018", + "tag": "8.10-1052", "updatePackages": [] }, { From 1ec4497a3604ac4e285b845e95c3cfb81fc86b97 Mon Sep 17 00:00:00 2001 From: Travis CI User Date: Thu, 22 Aug 2024 16:44:38 +0000 Subject: [PATCH 131/179] Trigger build with new base image --- base_images.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/base_images.json b/base_images.json index df2fb96c..579a5a04 100644 --- a/base_images.json +++ b/base_images.json @@ -57,16 +57,16 @@ { "imageType": "node", "sourceImage": "ubi8-minimal", - "sourceTag": "8.10-1018", + "sourceTag": "8.10-1052", "destImage": "node-v18-ubi8-minimal", "nodeVersion": "18.20.4" }, { "imageType": "node", "sourceImage": "ubi8-minimal", - "sourceTag": "8.10-1018", + "sourceTag": "8.10-1052", "destImage": "node-v20-ubi8-minimal", - "nodeVersion": "20.16.0" + "nodeVersion": "20.17.0" }, { "imageType": "node", @@ -80,6 +80,6 @@ "sourceImage": "ubi9-minimal", "sourceTag": "9.4-1194", "destImage": "node-v20-ubi9-minimal", - "nodeVersion": "20.16.0" + "nodeVersion": "20.17.0" } ] From 1ce56cab14465ff841603d277fd6e5bc72321178 Mon Sep 17 00:00:00 2001 From: Daniel Fan Date: Mon, 26 Aug 2024 15:38:49 -0400 Subject: [PATCH 132/179] update golangci version to 1.60.x (#1076) * update golangci version to 1.60.x Signed-off-by: Daniel Fan * fix lint issues Signed-off-by: Daniel Fan * Bump golang verison in Dockerfile Signed-off-by: Daniel Fan * fix lint issue Signed-off-by: Daniel Fan --------- Signed-off-by: Daniel Fan --- Dockerfile | 2 +- common/config/.golangci.yml | 42 +++++++++++++------ common/scripts/lint_go.sh | 2 +- .../operandregistry_controller.go | 2 +- .../operandrequest/reconcile_operand.go | 10 ++--- go.mod | 3 +- go.sum | 7 ++++ 7 files changed, 46 insertions(+), 22 deletions(-) diff --git a/Dockerfile b/Dockerfile index 69cdc20c..0aec23ae 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # Build the manager binary -FROM docker.io/golang:1.22.5-bullseye as builder +FROM docker.io/golang:1.23.0-bullseye as builder ARG GOARCH WORKDIR /workspace diff --git a/common/config/.golangci.yml b/common/config/.golangci.yml index 27973311..950c034b 100644 --- a/common/config/.golangci.yml +++ b/common/config/.golangci.yml @@ -1,6 +1,6 @@ service: # When updating this, also update the version stored in docker/build-tools/Dockerfile in the multicloudlab/tools repo. - golangci-lint-version: 1.51.x # use the fixed version to not introduce new linters unexpectedly + golangci-lint-version: 1.60.x # use the fixed version to not introduce new linters unexpectedly run: # timeout for analysis, e.g. 30s, 5m, default is 1m deadline: 20m @@ -10,43 +10,44 @@ run: # default value is empty list, but next dirs are always skipped independently # from this option's value: # vendor$, third_party$, testdata$, examples$, Godeps$, builtin$ - skip-dirs: - - genfiles$ - - vendor$ + # skip-dirs: + # - genfiles$ + # - vendor$ # which files to skip: they will be analyzed, but issues from them # won't be reported. Default value is empty list, but there is # no need to include all autogenerated files, we confidently recognize # autogenerated files. If it's not please let us know. - skip-files: - - ".*\\.pb\\.go" - - ".*\\.gen\\.go" + # skip-files: + # - ".*\\.pb\\.go" + # - ".*\\.gen\\.go" linters: # please, do not use `enable-all`: it's deprecated and will be removed soon. # inverted configuration with `enable-all` and `disable` is not scalable during updates of golangci-lint disable-all: true enable: - - deadcode + # - deadcode - errcheck # - gocyclo - gofmt - goimports - - golint + # - golint + - revive - gosec - gosimple - govet - ineffassign - - interfacer + # - interfacer - lll - misspell - staticcheck - - structcheck + # - structcheck - typecheck - unconvert - unparam - unused - - varcheck + # - varcheck # don't enable: # - gocritic # - bodyclose @@ -185,6 +186,15 @@ linters-settings: # - unnamedResult # - wrapperFunc + revive: + rules: + - name: dot-imports + arguments: + - allowedPackages: + - "github.com/onsi/ginkgo" + - "github.com/onsi/ginkgo/v2" + - "github.com/onsi/gomega" + issues: # List of regexps of issue texts to exclude, empty list by default. # But independently from this option we use default exclude patterns, @@ -199,6 +209,14 @@ issues: linters: - errcheck - maligned + + exclude-dirs: + - genfiles$ + - vendor$ + + exclude-files: + - ".*\\.pb\\.go" + - ".*\\.gen\\.go" # Independently from option `exclude` we use default exclude patterns, # it can be disabled by this option. To list all diff --git a/common/scripts/lint_go.sh b/common/scripts/lint_go.sh index 84a70810..3fd5d346 100755 --- a/common/scripts/lint_go.sh +++ b/common/scripts/lint_go.sh @@ -15,4 +15,4 @@ # limitations under the License. # -GOGC=25 golangci-lint run -c ./common/config/.golangci.yml +GOGC=25 golangci-lint run -c ./common/config/.golangci.yml --timeout=180s diff --git a/controllers/operandregistry/operandregistry_controller.go b/controllers/operandregistry/operandregistry_controller.go index 6f572c52..28dc895b 100644 --- a/controllers/operandregistry/operandregistry_controller.go +++ b/controllers/operandregistry/operandregistry_controller.go @@ -78,7 +78,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctrl.Re } // Summarize instance status - if instance.Status.OperatorsStatus == nil || len(instance.Status.OperatorsStatus) == 0 { + if len(instance.Status.OperatorsStatus) == 0 { instance.UpdateRegistryPhase(operatorv1alpha1.RegistryReady) } else { instance.UpdateRegistryPhase(operatorv1alpha1.RegistryRunning) diff --git a/controllers/operandrequest/reconcile_operand.go b/controllers/operandrequest/reconcile_operand.go index 36805205..a23c7076 100644 --- a/controllers/operandrequest/reconcile_operand.go +++ b/controllers/operandrequest/reconcile_operand.go @@ -371,11 +371,11 @@ func (r *Reconciler) reconcileCRwithRequest(ctx context.Context, requestInstance var crFromRequest unstructured.Unstructured if operand.APIVersion == "" { - return fmt.Errorf("The APIVersion of operand is empty for operator " + operand.Name) + return fmt.Errorf("the APIVersion of operand is empty for operator %s", operand.Name) } if operand.Kind == "" { - return fmt.Errorf("The Kind of operand is empty for operator " + operand.Name) + return fmt.Errorf("the Kind of operand is empty for operator %s", operand.Name) } var name string @@ -509,14 +509,14 @@ func (r *Reconciler) reconcileK8sResourceWithRetries(ctx context.Context, res op func (r *Reconciler) reconcileK8sResource(ctx context.Context, res operatorv1alpha1.ConfigResource, serviceName, opConfigName, opConfigNs string) error { if res.APIVersion == "" { - return fmt.Errorf("The APIVersion of k8s resource is empty for operator " + serviceName) + return fmt.Errorf("the APIVersion of k8s resource is empty for operator %s", serviceName) } if res.Kind == "" { - return fmt.Errorf("The Kind of k8s resource is empty for operator " + serviceName) + return fmt.Errorf("the Kind of k8s resource is empty for operator %s", serviceName) } if res.Name == "" { - return fmt.Errorf("The Name of k8s resource is empty for operator " + serviceName) + return fmt.Errorf("the Name of k8s resource is empty for operator %s", serviceName) } var k8sResNs string if res.Namespace == "" { diff --git a/go.mod b/go.mod index d6ed398b..8548e7a6 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/IBM/operand-deployment-lifecycle-manager/v4 -go 1.20 +go 1.23 require ( github.com/IBM/controller-filtered-cache v0.3.5 @@ -112,4 +112,3 @@ require ( // fix vulnerability: CVE-2021-3121 in github.com/gogo/protobuf v1.2.1 replace github.com/gogo/protobuf => github.com/gogo/protobuf v1.3.2 - diff --git a/go.sum b/go.sum index c17e0561..88adc21f 100644 --- a/go.sum +++ b/go.sum @@ -309,6 +309,7 @@ github.com/flowstack/go-jsonschema v0.1.1/go.mod h1:yL7fNggx1o8rm9RlgXv7hTBWxdBM github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= +github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI= @@ -624,6 +625,7 @@ github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFB github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= @@ -859,6 +861,7 @@ github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6So github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k= +github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= @@ -902,6 +905,7 @@ github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJ github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo= github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g= github.com/spf13/cobra v1.5.0 h1:X+jTBEBqF0bHN+9cSMgmfuvv2VHJ9ezmFNf9Y/XstYU= +github.com/spf13/cobra v1.5.0/go.mod h1:dWXEIy2H428czQCjInthrTRUg7yKbok+2Qi/yBIJoUM= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= @@ -1007,6 +1011,7 @@ go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= +go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= go.opentelemetry.io/contrib v0.20.0/go.mod h1:G/EtFaa6qaN7+LxqfIAT3GiZa7Wv5DTBUzl5H4LY0Kc= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.20.0/go.mod h1:oVGt1LRbBOBq1A5BQLlUg9UaU/54aiHw8cgjV3aWZ/E= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.20.0/go.mod h1:2AboqHi0CiIZU0qwhtUfCYD1GeUzvvIXWNkhDt7ZMG4= @@ -1027,6 +1032,7 @@ go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/goleak v1.1.12 h1:gZAh5/EyT/HQwlpkCy6wTpqfH9H8Lz8zbm3dZh+OyzA= +go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= @@ -1197,6 +1203,7 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/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.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= +golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= From afe2a5ec148ee6f7bb65e1d7adb4e90b0ee0ec2b Mon Sep 17 00:00:00 2001 From: YuChen Shen <59578388+YCShen1010@users.noreply.github.com> Date: Mon, 26 Aug 2024 15:57:48 -0400 Subject: [PATCH 133/179] remove ltsr branch from dependabot.yml (#1075) --- .github/dependabot.yml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index f7e93cc2..d551e40b 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -5,8 +5,3 @@ updates: schedule: interval: daily target-branch: "master" - - package-ecosystem: docker - directory: "/" - schedule: - interval: daily - target-branch: "release-ltsr" From 67f51c839fe07f9b1ef393244f57a42b75dead63 Mon Sep 17 00:00:00 2001 From: Henry Li Date: Mon, 26 Aug 2024 16:09:46 -0400 Subject: [PATCH 134/179] updated base image to ubi9 (#1077) Signed-off-by: Henry Li --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 0aec23ae..a4775ec0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -21,7 +21,7 @@ RUN CGO_ENABLED=0 GOOS=linux GO111MODULE=on go build -a -o manager main.go # Use distroless as minimal base image to package the manager binary # Refer to https://github.com/GoogleContainerTools/distroless for more details # FROM gcr.io/distroless/static:nonroot -FROM docker-na-public.artifactory.swg-devops.com/hyc-cloud-private-edge-docker-local/build-images/ubi8-minimal:latest +FROM docker-na-public.artifactory.swg-devops.com/hyc-cloud-private-edge-docker-local/build-images/ubi9-minimal:latest ARG VCS_REF ARG VCS_URL From 58b5ab1feaec10bb0366ecd5213baf5fde685e1f Mon Sep 17 00:00:00 2001 From: Henry Li Date: Thu, 29 Aug 2024 21:06:49 -0400 Subject: [PATCH 135/179] added feature to handle user managed operators (BYO) (#1078) * fixed make bundle-manifests to check for yq first Signed-off-by: Henry Li * updated controller-gen to v0.14.0 Signed-off-by: Henry Li * added UserManaged field to OperandRegistry - for BYO scenario Signed-off-by: Henry Li * updated operator/operand reconcile for userManaged - so that controllers do not try to create/update/manage Subscription for an operator which is userManaged - so that controllers do not spit out errors as it did previously - so that controllers update OperandRequest with Running status - operands in OperandConfig should still be created - currently missing proper cleanup when OperandRequest is deleted Signed-off-by: Henry Li * updated user managed logic to properly cleanup Signed-off-by: Henry Li * increase lint timeout to 300s Signed-off-by: Henry Li * fixed test regression by adding opreq-control label Signed-off-by: Henry Li * updated to handle BYO operator in different ns - when the user managed operator is out of the watch scope of ODLM - i.e. ODLM cannot see the Subscription Signed-off-by: Henry Li * updated DeleteRedundantCSV to ignore any CSVs where olm.copiedFrom label exists Signed-off-by: Henry Li --------- Signed-off-by: Henry Li --- Makefile | 2 +- api/v1alpha1/operandregistry_types.go | 2 + api/v1alpha1/zz_generated.deepcopy.go | 1 - ...fecycle-manager.clusterserviceversion.yaml | 6 +- .../operator.ibm.com_operandregistries.yaml | 4 + common/Makefile.common.mk | 2 +- common/scripts/lint_go.sh | 2 +- .../operator.ibm.com_operandregistries.yaml | 4 + .../operandrequest_controller.go | 25 ++-- .../operandrequest/reconcile_operand.go | 120 ++++++++++-------- .../operandrequest/reconcile_operator.go | 95 ++++++++++++-- .../operandrequest/reconcile_operator_test.go | 7 + controllers/operator/manager.go | 43 ++++++- 13 files changed, 233 insertions(+), 80 deletions(-) diff --git a/Makefile b/Makefile index 819c36cb..e02cccf8 100644 --- a/Makefile +++ b/Makefile @@ -200,7 +200,7 @@ manifests: controller-gen ## Generate manifests e.g. CRD, RBAC etc. generate: controller-gen ## Generate code e.g. API etc. $(CONTROLLER_GEN) object:headerFile="hack/boilerplate.go.txt" paths="./..." -bundle-manifests: +bundle-manifests: yq $(KUSTOMIZE) build config/manifests | $(OPERATOR_SDK) generate bundle \ -q --overwrite --version $(OPERATOR_VERSION) $(BUNDLE_METADATA_OPTS) $(OPERATOR_SDK) bundle validate ./bundle diff --git a/api/v1alpha1/operandregistry_types.go b/api/v1alpha1/operandregistry_types.go index 94955f3b..becab46e 100644 --- a/api/v1alpha1/operandregistry_types.go +++ b/api/v1alpha1/operandregistry_types.go @@ -76,6 +76,8 @@ type Operator struct { // OperatorConfig is the name of the OperatorConfig // +optional OperatorConfig string `json:"operatorConfig,omitempty"` + // UserManaged is a flag to indicate whether operator is managed by user + UserManaged bool `json:"userManaged,omitempty"` } // +kubebuilder:validation:Enum=public;private diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 26f36494..d8720dec 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -1,5 +1,4 @@ //go:build !ignore_autogenerated -// +build !ignore_autogenerated // // Copyright 2022 IBM Corporation diff --git a/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml b/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml index db3acfe8..0aaee96d 100644 --- a/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml +++ b/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml @@ -129,7 +129,7 @@ metadata: categories: Developer Tools, Monitoring, Logging & Tracing, Security certified: "false" containerImage: icr.io/cpopen/odlm:latest - createdAt: "2024-04-04T03:40:45Z" + createdAt: "2024-08-27T18:18:40Z" description: The Operand Deployment Lifecycle Manager provides a Kubernetes CRD-based API to manage the lifecycle of operands. nss.operator.ibm.com/managed-operators: ibm-odlm olm.skipRange: '>=1.2.0 <4.3.5' @@ -664,8 +664,6 @@ spec: ephemeral-storage: 256Mi memory: 200Mi securityContext: - seccompProfile: - type: RuntimeDefault allowPrivilegeEscalation: false capabilities: drop: @@ -673,6 +671,8 @@ spec: privileged: false readOnlyRootFilesystem: true runAsNonRoot: true + seccompProfile: + type: RuntimeDefault serviceAccount: operand-deployment-lifecycle-manager serviceAccountName: operand-deployment-lifecycle-manager terminationGracePeriodSeconds: 10 diff --git a/bundle/manifests/operator.ibm.com_operandregistries.yaml b/bundle/manifests/operator.ibm.com_operandregistries.yaml index a8f57f4e..8618ce06 100644 --- a/bundle/manifests/operator.ibm.com_operandregistries.yaml +++ b/bundle/manifests/operator.ibm.com_operandregistries.yaml @@ -2055,6 +2055,10 @@ spec: items: type: string type: array + userManaged: + description: UserManaged is a flag to indicate whether operator + is managed by user + type: boolean required: - channel - name diff --git a/common/Makefile.common.mk b/common/Makefile.common.mk index 4574e06a..fcc2796f 100644 --- a/common/Makefile.common.mk +++ b/common/Makefile.common.mk @@ -86,7 +86,7 @@ fetch-test-crds: CONTROLLER_GEN ?= $(shell pwd)/common/bin/controller-gen controller-gen: ## Download controller-gen locally if necessary. - $(call go-get-tool,$(CONTROLLER_GEN),sigs.k8s.io/controller-tools/cmd/controller-gen@v0.6.1) + $(call go-get-tool,$(CONTROLLER_GEN),sigs.k8s.io/controller-tools/cmd/controller-gen@v0.14.0) KIND ?= $(shell pwd)/common/bin/kind kind: ## Download kind locally if necessary. diff --git a/common/scripts/lint_go.sh b/common/scripts/lint_go.sh index 3fd5d346..e3163d8f 100755 --- a/common/scripts/lint_go.sh +++ b/common/scripts/lint_go.sh @@ -15,4 +15,4 @@ # limitations under the License. # -GOGC=25 golangci-lint run -c ./common/config/.golangci.yml --timeout=180s +GOGC=25 golangci-lint run -c ./common/config/.golangci.yml --timeout=300s diff --git a/config/crd/bases/operator.ibm.com_operandregistries.yaml b/config/crd/bases/operator.ibm.com_operandregistries.yaml index b452d559..54197b1b 100644 --- a/config/crd/bases/operator.ibm.com_operandregistries.yaml +++ b/config/crd/bases/operator.ibm.com_operandregistries.yaml @@ -2051,6 +2051,10 @@ spec: items: type: string type: array + userManaged: + description: UserManaged is a flag to indicate whether operator + is managed by user + type: boolean required: - channel - name diff --git a/controllers/operandrequest/operandrequest_controller.go b/controllers/operandrequest/operandrequest_controller.go index b00fee48..0f82ae56 100644 --- a/controllers/operandrequest/operandrequest_controller.go +++ b/controllers/operandrequest/operandrequest_controller.go @@ -238,18 +238,19 @@ func (r *Reconciler) checkFinalizer(ctx context.Context, requestInstance *operat for _, m := range requestInstance.Status.Members { remainingOperands.Add(m.Name) } - existingSub := &olmv1alpha1.SubscriptionList{} - - opts := []client.ListOption{ - client.MatchingLabels(map[string]string{constant.OpreqLabel: "true"}), - } - - if err := r.Client.List(ctx, existingSub, opts...); err != nil { - return err - } - if len(existingSub.Items) == 0 { - return nil - } + // TODO: update to check OperandRequest status to see if member is user managed or not + // existingSub := &olmv1alpha1.SubscriptionList{} + + // opts := []client.ListOption{ + // client.MatchingLabels(map[string]string{constant.OpreqLabel: "true"}), + // } + + // if err := r.Client.List(ctx, existingSub, opts...); err != nil { + // return err + // } + // if len(existingSub.Items) == 0 { + // return nil + // } // Delete all the subscriptions that created by current request if err := r.absentOperatorsAndOperands(ctx, requestInstance, &remainingOperands); err != nil { return err diff --git a/controllers/operandrequest/reconcile_operand.go b/controllers/operandrequest/reconcile_operand.go index a23c7076..45e09967 100644 --- a/controllers/operandrequest/reconcile_operand.go +++ b/controllers/operandrequest/reconcile_operand.go @@ -99,53 +99,67 @@ func (r *Reconciler) reconcileOperand(ctx context.Context, requestInstance *oper namespace := r.GetOperatorNamespace(opdRegistry.InstallMode, opdRegistry.Namespace) sub, err := r.GetSubscription(ctx, operatorName, namespace, registryInstance.Namespace, opdRegistry.PackageName) - - if sub == nil && err == nil { - klog.Warningf("There is no Subscription %s or %s in the namespace %s and %s", operatorName, opdRegistry.PackageName, namespace, registryInstance.Namespace) - continue - - } else if err != nil { + if err != nil { merr.Add(errors.Wrapf(err, "failed to get the Subscription %s in the namespace %s and %s", operatorName, namespace, registryInstance.Namespace)) return merr } - if _, ok := sub.Labels[constant.OpreqLabel]; !ok { - // Subscription existing and not managed by OperandRequest controller - klog.Warningf("Subscription %s in the namespace %s isn't created by ODLM", sub.Name, sub.Namespace) - } + if !opdRegistry.UserManaged { + if sub == nil { + klog.Warningf("There is no Subscription %s or %s in the namespace %s and %s", operatorName, opdRegistry.PackageName, namespace, registryInstance.Namespace) + continue + } - // It the installplan is not created yet, ODLM will try later - if sub.Status.Install == nil || sub.Status.InstallPlanRef.Name == "" { - klog.Warningf("The Installplan for Subscription %s is not ready. Will check it again", sub.Name) - requestInstance.SetMemberStatus(operand.Name, operatorv1alpha1.OperatorInstalling, "", &r.Mutex) - continue - } + if _, ok := sub.Labels[constant.OpreqLabel]; !ok { + // Subscription existing and not managed by OperandRequest controller + klog.Warningf("Subscription %s in the namespace %s isn't created by ODLM", sub.Name, sub.Namespace) + } - // If the installplan is deleted after is completed, ODLM won't block the CR update. - ipName := sub.Status.InstallPlanRef.Name - ipNamespace := sub.Namespace - ip := &olmv1alpha1.InstallPlan{} - ipKey := types.NamespacedName{ - Name: ipName, - Namespace: ipNamespace, - } - if err := r.Client.Get(ctx, ipKey, ip); err != nil { - if !apierrors.IsNotFound(err) { - merr.Add(errors.Wrapf(err, "failed to get Installplan")) + // It the installplan is not created yet, ODLM will try later + if sub.Status.Install == nil || sub.Status.InstallPlanRef.Name == "" { + klog.Warningf("The Installplan for Subscription %s is not ready. Will check it again", sub.Name) + requestInstance.SetMemberStatus(operand.Name, operatorv1alpha1.OperatorInstalling, "", &r.Mutex) + continue } - } else if ip.Status.Phase == olmv1alpha1.InstallPlanPhaseFailed { - klog.Errorf("installplan %s/%s is failed", ipNamespace, ipName) - requestInstance.SetMemberStatus(operand.Name, operatorv1alpha1.OperatorFailed, "", &r.Mutex) - continue + + // If the installplan is deleted after is completed, ODLM won't block the CR update. + ipName := sub.Status.InstallPlanRef.Name + ipNamespace := sub.Namespace + ip := &olmv1alpha1.InstallPlan{} + ipKey := types.NamespacedName{ + Name: ipName, + Namespace: ipNamespace, + } + if err := r.Client.Get(ctx, ipKey, ip); err != nil { + if !apierrors.IsNotFound(err) { + merr.Add(errors.Wrapf(err, "failed to get Installplan")) + } + } else if ip.Status.Phase == olmv1alpha1.InstallPlanPhaseFailed { + klog.Errorf("installplan %s/%s is failed", ipNamespace, ipName) + requestInstance.SetMemberStatus(operand.Name, operatorv1alpha1.OperatorFailed, "", &r.Mutex) + continue + } + } - csv, err := r.GetClusterServiceVersion(ctx, sub) + var csv *olmv1alpha1.ClusterServiceVersion - // If can't get CSV, requeue the request - if err != nil { - merr.Add(err) - requestInstance.SetMemberStatus(operand.Name, operatorv1alpha1.OperatorFailed, "", &r.Mutex) - continue + if opdRegistry.UserManaged { + csvList, err := r.GetClusterServiceVersionListFromPackage(ctx, opdRegistry.PackageName, opdRegistry.Namespace) + if err != nil { + merr.Add(err) + requestInstance.SetMemberStatus(operand.Name, operatorv1alpha1.OperatorFailed, "", &r.Mutex) + continue + } + csv = csvList[0] + } else { + csv, err = r.GetClusterServiceVersion(ctx, sub) + // If can't get CSV, requeue the request + if err != nil { + merr.Add(err) + requestInstance.SetMemberStatus(operand.Name, operatorv1alpha1.OperatorFailed, "", &r.Mutex) + continue + } } if csv == nil { @@ -160,20 +174,22 @@ func (r *Reconciler) reconcileOperand(ctx context.Context, requestInstance *oper continue } - // find the OperandRequest which has the same operator's channel version as existing subscription. - // ODLM will only reconcile Operand based on OperandConfig for this OperandRequest - var requestList []string - reg, _ := regexp.Compile(`^(.*)\.(.*)\.(.*)\/request`) - for anno, version := range sub.Annotations { - if reg.MatchString(anno) && version == sub.Spec.Channel { - requestList = append(requestList, anno) + if !opdRegistry.UserManaged { + // find the OperandRequest which has the same operator's channel version as existing subscription. + // ODLM will only reconcile Operand based on OperandConfig for this OperandRequest + var requestList []string + reg, _ := regexp.Compile(`^(.*)\.(.*)\.(.*)\/request`) + for anno, version := range sub.Annotations { + if reg.MatchString(anno) && version == sub.Spec.Channel { + requestList = append(requestList, anno) + } } - } - if len(requestList) == 0 || !util.Contains(requestList, requestInstance.Namespace+"."+requestInstance.Name+"."+operand.Name+"/request") { - klog.Infof("Subscription %s in the namespace %s is NOT managed by %s/%s, Skip reconciling Operands", sub.Name, sub.Namespace, requestInstance.Namespace, requestInstance.Name) - requestInstance.SetMemberStatus(operand.Name, operatorv1alpha1.OperatorFailed, "", &r.Mutex) - continue + if len(requestList) == 0 || !util.Contains(requestList, requestInstance.Namespace+"."+requestInstance.Name+"."+operand.Name+"/request") { + klog.Infof("Subscription %s in the namespace %s is NOT managed by %s/%s, Skip reconciling Operands", sub.Name, sub.Namespace, requestInstance.Namespace, requestInstance.Name) + requestInstance.SetMemberStatus(operand.Name, operatorv1alpha1.OperatorFailed, "", &r.Mutex) + continue + } } klog.V(3).Info("Generating customresource base on ClusterServiceVersion: ", csv.GetName()) @@ -185,11 +201,11 @@ func (r *Reconciler) reconcileOperand(ctx context.Context, requestInstance *oper if err == nil { // Check the requested Service Config if exist in specific OperandConfig opdConfig := configInstance.GetService(operand.Name) - if opdConfig == nil { + if opdConfig == nil && !opdRegistry.UserManaged { klog.V(2).Infof("There is no service: %s from the OperandConfig instance: %s/%s, Skip reconciling Operands", operand.Name, registryKey.Namespace, req.Registry) continue } - err = r.reconcileCRwithConfig(ctx, opdConfig, configInstance.Name, configInstance.Namespace, csv, requestInstance, operand.Name, sub.Namespace, &r.Mutex) + err = r.reconcileCRwithConfig(ctx, opdConfig, configInstance.Name, configInstance.Namespace, csv, requestInstance, operand.Name, csv.Namespace, &r.Mutex) if err != nil { merr.Add(err) requestInstance.SetMemberStatus(operand.Name, "", operatorv1alpha1.ServiceFailed, &r.Mutex) @@ -203,7 +219,7 @@ func (r *Reconciler) reconcileOperand(ctx context.Context, requestInstance *oper } } else { - err = r.reconcileCRwithRequest(ctx, requestInstance, operand, types.NamespacedName{Name: requestInstance.Name, Namespace: requestInstance.Namespace}, i, sub.Namespace, &r.Mutex) + err = r.reconcileCRwithRequest(ctx, requestInstance, operand, types.NamespacedName{Name: requestInstance.Name, Namespace: requestInstance.Namespace}, i, csv.Namespace, &r.Mutex) if err != nil { merr.Add(err) requestInstance.SetMemberStatus(operand.Name, "", operatorv1alpha1.ServiceFailed, &r.Mutex) diff --git a/controllers/operandrequest/reconcile_operator.go b/controllers/operandrequest/reconcile_operator.go index bbd0d5d5..e714274a 100644 --- a/controllers/operandrequest/reconcile_operator.go +++ b/controllers/operandrequest/reconcile_operator.go @@ -160,6 +160,19 @@ func (r *Reconciler) reconcileSubscription(ctx context.Context, requestInstance namespace := r.GetOperatorNamespace(opt.InstallMode, opt.Namespace) sub, err := r.GetSubscription(ctx, opt.Name, namespace, registryInstance.Namespace, opt.PackageName) + if opt.UserManaged { + klog.Infof("Skip installing operator %s because it is managed by user", opt.PackageName) + csvList, err := r.GetClusterServiceVersionListFromPackage(ctx, opt.PackageName, namespace) + if err != nil { + return errors.Wrapf(err, "failed to get CSV from package %s/%s", namespace, opt.PackageName) + } + if len(csvList) == 0 { + return errors.New("operator " + opt.Name + " is user managed, but no CSV exists, waiting...") + } + requestInstance.SetMemberStatus(opt.Name, operatorv1alpha1.OperatorUpdating, "", mu) + return nil + } + if sub == nil && err == nil { if opt.InstallMode == operatorv1alpha1.InstallModeNoop { requestInstance.SetNoSuitableRegistryCondition(registryKey.String(), opt.Name+" is in maintenance status", operatorv1alpha1.ResourceTypeOperandRegistry, corev1.ConditionTrue, &r.Mutex) @@ -403,9 +416,10 @@ func (r *Reconciler) uninstallOperatorsAndOperands(ctx context.Context, operandN } if _, ok := sub.Labels[constant.OpreqLabel]; !ok { - // Subscription existing and not managed by OperandRequest controller - klog.V(2).Infof("Subscription %s in the namespace %s isn't created by ODLM", sub.Name, sub.Namespace) - return nil + if !op.UserManaged { + klog.V(2).Infof("Subscription %s in the namespace %s isn't created by ODLM and isn't user managed", sub.Name, sub.Namespace) + return nil + } } uninstallOperator, uninstallOperand := checkSubAnnotationsForUninstall(requestInstance.ObjectMeta.Name, requestInstance.ObjectMeta.Namespace, op.Name, sub) @@ -480,6 +494,54 @@ func (r *Reconciler) uninstallOperatorsAndOperands(ctx context.Context, operandN return nil } +func (r *Reconciler) uninstallOperands(ctx context.Context, operandName string, requestInstance *operatorv1alpha1.OperandRequest, registryInstance *operatorv1alpha1.OperandRegistry, configInstance *operatorv1alpha1.OperandConfig) error { + // No error handling for un-installation step in case Catalog has been deleted + op, _ := r.GetOperandFromRegistry(ctx, registryInstance, operandName) + if op == nil { + klog.Warningf("Operand %s not found", operandName) + return nil + } + + namespace := r.GetOperatorNamespace(op.InstallMode, op.Namespace) + uninstallOperand := false + operatorStatus, ok := registryInstance.Status.OperatorsStatus[op.Name] + if !ok { + return nil + } + if operatorStatus.ReconcileRequests == nil { + return nil + } + if len(operatorStatus.ReconcileRequests) > 1 { + return nil + } + if operatorStatus.ReconcileRequests[0].Name == requestInstance.Name { + uninstallOperand = true + } + + // get list reconcileRequests + // ignore the name which triggered reconcile + // if list is empty then uninstallOperand = true + + if csvList, err := r.GetClusterServiceVersionListFromPackage(ctx, op.PackageName, namespace); err != nil { + // If can't get CSV, requeue the request + return err + } else if csvList != nil { + klog.Infof("Found %d ClusterServiceVersions for package %s/%s", len(csvList), op.Name, namespace) + if uninstallOperand { + klog.V(2).Infof("Deleting all the Custom Resources for CSV, Namespace: %s, Name: %s", csvList[0].Namespace, csvList[0].Name) + if err := r.deleteAllCustomResource(ctx, csvList[0], requestInstance, configInstance, operandName, configInstance.Namespace); err != nil { + return err + } + klog.V(2).Infof("Deleting all the k8s Resources for CSV, Namespace: %s, Name: %s", csvList[0].Namespace, csvList[0].Name) + if err := r.deleteAllK8sResource(ctx, configInstance, operandName, configInstance.Namespace); err != nil { + return err + } + } + } + + return nil +} + func (r *Reconciler) absentOperatorsAndOperands(ctx context.Context, requestInstance *operatorv1alpha1.OperandRequest, remainingOperands *gset.Set) error { needDeletedOperands := r.getNeedDeletedOperands(requestInstance) @@ -510,11 +572,24 @@ func (r *Reconciler) absentOperatorsAndOperands(ctx context.Context, requestInst wg.Add(1) go func() { defer wg.Done() - if err := r.uninstallOperatorsAndOperands(ctx, fmt.Sprintf("%v", o), requestInstance, registryInstance, configInstance); err != nil { - r.Mutex.Lock() - defer r.Mutex.Unlock() - merr.Add(err) - return // return here to avoid removing the operand from remainingOperands + op, _ := r.GetOperandFromRegistry(ctx, registryInstance, fmt.Sprintf("%v", o)) + if op == nil { + klog.Warningf("Operand %s not found", fmt.Sprintf("%v", o)) + } + if op != nil && !op.UserManaged { + if err := r.uninstallOperatorsAndOperands(ctx, fmt.Sprintf("%v", o), requestInstance, registryInstance, configInstance); err != nil { + r.Mutex.Lock() + defer r.Mutex.Unlock() + merr.Add(err) + return // return here to avoid removing the operand from remainingOperands + } + } else { + if err := r.uninstallOperands(ctx, fmt.Sprintf("%v", o), requestInstance, registryInstance, configInstance); err != nil { + r.Mutex.Lock() + defer r.Mutex.Unlock() + merr.Add(err) + return // return here to avoid removing the operand from remainingOperands + } } requestInstance.RemoveServiceStatus(fmt.Sprintf("%v", o), &r.Mutex) (*remainingOperands).Remove(o) @@ -694,6 +769,10 @@ func checkSubAnnotationsForUninstall(reqName, reqNs, opName string, sub *olmv1al uninstallOperator = false } + if _, ok := sub.Labels[constant.OpreqLabel]; !ok { + uninstallOperator = false + } + // If the removed/uninstalled /request annotation's value is NOT the same as all other /request annotation's values. // or the operator namespace in one of remaining annotation is the same as the operator name in removed/uninstalled /request // the operand should NOT be uninstalled. diff --git a/controllers/operandrequest/reconcile_operator_test.go b/controllers/operandrequest/reconcile_operator_test.go index baf63408..c141c48f 100644 --- a/controllers/operandrequest/reconcile_operator_test.go +++ b/controllers/operandrequest/reconcile_operator_test.go @@ -26,6 +26,7 @@ import ( "k8s.io/apimachinery/pkg/types" operatorv1alpha1 "github.com/IBM/operand-deployment-lifecycle-manager/v4/api/v1alpha1" + "github.com/IBM/operand-deployment-lifecycle-manager/v4/controllers/constant" ) func TestGenerateClusterObjects(t *testing.T) { @@ -125,6 +126,9 @@ func TestCheckSubAnnotationsForUninstall(t *testing.T) { reqNsA + "." + reqNameA + "." + opNameA + "/request": opChannelA, reqNsA + "." + reqNameA + "." + opNameA + "/operatorNamespace": reqNsA, }, + Labels: map[string]string{ + constant.OpreqLabel: "true", + }, }, } @@ -147,6 +151,9 @@ func TestCheckSubAnnotationsForUninstall(t *testing.T) { reqNsB + "." + reqNameB + "." + opNameB + "/request": opChannelB, reqNsB + "." + reqNameB + "." + opNameB + "/operatorNamespace": reqNsB, }, + Labels: map[string]string{ + constant.OpreqLabel: "true", + }, }, } diff --git a/controllers/operator/manager.go b/controllers/operator/manager.go index 810987ec..ff54761d 100644 --- a/controllers/operator/manager.go +++ b/controllers/operator/manager.go @@ -429,6 +429,47 @@ func (m *ODLMOperator) GetClusterServiceVersionList(ctx context.Context, sub *ol return csvs, nil } +// GetClusterServiceVersionList gets a list of ClusterServiceVersions from the subscription +func (m *ODLMOperator) GetClusterServiceVersionListFromPackage(ctx context.Context, name, namespace string) ([]*olmv1alpha1.ClusterServiceVersion, error) { + packageName := name + csvNamespace := namespace + + csvList := &olmv1alpha1.ClusterServiceVersionList{} + + opts := []client.ListOption{ + client.InNamespace(csvNamespace), + } + + if err := m.Reader.List(ctx, csvList, opts...); err != nil { + if apierrors.IsNotFound(err) || len(csvList.Items) == 0 { + klog.V(3).Infof("No ClusterServiceVersion found") + return nil, nil + } + return nil, errors.Wrapf(err, "failed to list ClusterServiceVersions") + } + + var csvs []*olmv1alpha1.ClusterServiceVersion + // filter csvList to find one(s) that contain packageName + for _, v := range csvList.Items { + csv := v + if csv.Annotations == nil { + continue + } + if _, ok := csv.Annotations["operatorframework.io/properties"]; !ok { + continue + } + annotation := fmt.Sprintf("\"packageName\":\"%s\"", packageName) + if !strings.Contains(csv.Annotations["operatorframework.io/properties"], annotation) { + continue + } + klog.V(3).Infof("Get ClusterServiceVersion %s in the namespace %s", csv.Name, csvNamespace) + csvs = append(csvs, &csv) + } + + klog.V(3).Infof("Get %v ClusterServiceVersions in the namespace %s", len(csvs), csvNamespace) + return csvs, nil +} + func (m *ODLMOperator) DeleteRedundantCSV(ctx context.Context, csvName, operatorNs, serviceNs, packageName string) error { // Get the csv by its name and namespace csv := &olmv1alpha1.ClusterServiceVersion{} @@ -450,7 +491,7 @@ func (m *ODLMOperator) DeleteRedundantCSV(ctx context.Context, csvName, operator } // Delete the CSV if the csv does not contain label operators.coreos.com/packageName.operatorNs='' AND does not contains label olm.copiedFrom: operatorNs if _, ok := csv.GetLabels()[fmt.Sprintf("operators.coreos.com/%s.%s", packageName, operatorNs)]; !ok { - if csv.GetLabels()["olm.copiedFrom"] != operatorNs { + if _, ok := csv.Labels["olm.copiedFrom"]; !ok { klog.Infof("Delete the redundant ClusterServiceVersion %s in the namespace %s", csvName, serviceNs) if err := m.Client.Delete(ctx, csv); err != nil { return errors.Wrapf(err, "failed to delete ClusterServiceVersion %s/%s", serviceNs, csvName) From 7f5d804e33abb5ac9bb9786f9f43213602eef076 Mon Sep 17 00:00:00 2001 From: Daniel Fan Date: Fri, 30 Aug 2024 00:42:45 -0400 Subject: [PATCH 136/179] implement channel fallback in catalog discovery (#1079) * implement channel fallback in catalog discovery Signed-off-by: Daniel Fan * fix lint issue Signed-off-by: Daniel Fan * add packagemanifest into scheme Signed-off-by: Daniel Fan --------- Signed-off-by: Daniel Fan --- api/v1alpha1/operandregistry_types.go | 3 + .../operator.ibm.com_operandregistries.yaml | 6 + .../operator.ibm.com_operandregistries.yaml | 6 + .../operandbindinfo_suite_test.go | 3 + .../operandconfig/operandconfig_suite_test.go | 3 + .../operandregistry_suite_test.go | 3 + .../operandrequest_suite_test.go | 3 + .../operandrequest/reconcile_operand.go | 14 +- .../operandrequest/reconcile_operator.go | 25 +- .../operandrequest/reconcile_operator_test.go | 197 +++++---- controllers/operator/manager.go | 132 ++++-- controllers/operator/manager_test.go | 417 ++++++++++++++++++ .../operatorconfig_suite_test.go | 3 + controllers/util/util.go | 43 +- controllers/util/util_test.go | 60 ++- 15 files changed, 767 insertions(+), 151 deletions(-) create mode 100644 controllers/operator/manager_test.go diff --git a/api/v1alpha1/operandregistry_types.go b/api/v1alpha1/operandregistry_types.go index becab46e..1b939d0a 100644 --- a/api/v1alpha1/operandregistry_types.go +++ b/api/v1alpha1/operandregistry_types.go @@ -58,6 +58,9 @@ type Operator struct { PackageName string `json:"packageName"` // Name of the channel to track. Channel string `json:"channel"` + // List of channels to fallback when the main channel is not available. + // +optional + FallbackChannels []string `json:"fallbackChannels,omitempty"` // Description of a common service. // +optional Description string `json:"description,omitempty"` diff --git a/bundle/manifests/operator.ibm.com_operandregistries.yaml b/bundle/manifests/operator.ibm.com_operandregistries.yaml index 8618ce06..be2020d6 100644 --- a/bundle/manifests/operator.ibm.com_operandregistries.yaml +++ b/bundle/manifests/operator.ibm.com_operandregistries.yaml @@ -70,6 +70,12 @@ spec: description: description: Description of a common service. type: string + fallbackChannels: + description: List of channels to fallback when the main channel + is not available. + items: + type: string + type: array installMode: description: |- The install mode of an operator, either namespace or cluster. diff --git a/config/crd/bases/operator.ibm.com_operandregistries.yaml b/config/crd/bases/operator.ibm.com_operandregistries.yaml index 54197b1b..f6013aed 100644 --- a/config/crd/bases/operator.ibm.com_operandregistries.yaml +++ b/config/crd/bases/operator.ibm.com_operandregistries.yaml @@ -66,6 +66,12 @@ spec: description: description: Description of a common service. type: string + fallbackChannels: + description: List of channels to fallback when the main channel + is not available. + items: + type: string + type: array installMode: description: |- The install mode of an operator, either namespace or cluster. diff --git a/controllers/operandbindinfo/operandbindinfo_suite_test.go b/controllers/operandbindinfo/operandbindinfo_suite_test.go index 25937857..be7a1ea6 100644 --- a/controllers/operandbindinfo/operandbindinfo_suite_test.go +++ b/controllers/operandbindinfo/operandbindinfo_suite_test.go @@ -28,6 +28,7 @@ import ( "github.com/onsi/gomega/gexec" olmv1 "github.com/operator-framework/api/pkg/operators/v1" olmv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1" + operatorsv1 "github.com/operator-framework/operator-lifecycle-manager/pkg/package-server/apis/operators/v1" clientgoscheme "k8s.io/client-go/kubernetes/scheme" "k8s.io/client-go/rest" ctrl "sigs.k8s.io/controller-runtime" @@ -92,6 +93,8 @@ var _ = BeforeSuite(func(done Done) { Expect(err).NotTo(HaveOccurred()) err = jaegerv1.AddToScheme(clientgoscheme.Scheme) Expect(err).NotTo(HaveOccurred()) + err = operatorsv1.AddToScheme(clientgoscheme.Scheme) + Expect(err).NotTo(HaveOccurred()) k8sClient, err = client.New(cfg, client.Options{Scheme: clientgoscheme.Scheme}) Expect(err).ToNot(HaveOccurred()) diff --git a/controllers/operandconfig/operandconfig_suite_test.go b/controllers/operandconfig/operandconfig_suite_test.go index 73605ab2..db18eff8 100644 --- a/controllers/operandconfig/operandconfig_suite_test.go +++ b/controllers/operandconfig/operandconfig_suite_test.go @@ -28,6 +28,7 @@ import ( "github.com/onsi/gomega/gexec" olmv1 "github.com/operator-framework/api/pkg/operators/v1" olmv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1" + operatorsv1 "github.com/operator-framework/operator-lifecycle-manager/pkg/package-server/apis/operators/v1" clientgoscheme "k8s.io/client-go/kubernetes/scheme" "k8s.io/client-go/rest" ctrl "sigs.k8s.io/controller-runtime" @@ -93,6 +94,8 @@ var _ = BeforeSuite(func(done Done) { Expect(err).NotTo(HaveOccurred()) err = jaegerv1.AddToScheme(clientgoscheme.Scheme) Expect(err).NotTo(HaveOccurred()) + err = operatorsv1.AddToScheme(clientgoscheme.Scheme) + Expect(err).NotTo(HaveOccurred()) k8sClient, err = client.New(cfg, client.Options{Scheme: clientgoscheme.Scheme}) Expect(err).ToNot(HaveOccurred()) diff --git a/controllers/operandregistry/operandregistry_suite_test.go b/controllers/operandregistry/operandregistry_suite_test.go index 61a80623..041b2e6b 100644 --- a/controllers/operandregistry/operandregistry_suite_test.go +++ b/controllers/operandregistry/operandregistry_suite_test.go @@ -28,6 +28,7 @@ import ( "github.com/onsi/gomega/gexec" olmv1 "github.com/operator-framework/api/pkg/operators/v1" olmv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1" + operatorsv1 "github.com/operator-framework/operator-lifecycle-manager/pkg/package-server/apis/operators/v1" clientgoscheme "k8s.io/client-go/kubernetes/scheme" "k8s.io/client-go/rest" ctrl "sigs.k8s.io/controller-runtime" @@ -92,6 +93,8 @@ var _ = BeforeSuite(func(done Done) { Expect(err).NotTo(HaveOccurred()) err = jaegerv1.AddToScheme(clientgoscheme.Scheme) Expect(err).NotTo(HaveOccurred()) + err = operatorsv1.AddToScheme(clientgoscheme.Scheme) + Expect(err).NotTo(HaveOccurred()) k8sClient, err = client.New(cfg, client.Options{Scheme: clientgoscheme.Scheme}) Expect(err).ToNot(HaveOccurred()) diff --git a/controllers/operandrequest/operandrequest_suite_test.go b/controllers/operandrequest/operandrequest_suite_test.go index db44144c..e7a864b6 100644 --- a/controllers/operandrequest/operandrequest_suite_test.go +++ b/controllers/operandrequest/operandrequest_suite_test.go @@ -28,6 +28,7 @@ import ( "github.com/onsi/gomega/gexec" olmv1 "github.com/operator-framework/api/pkg/operators/v1" olmv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1" + operatorsv1 "github.com/operator-framework/operator-lifecycle-manager/pkg/package-server/apis/operators/v1" clientgoscheme "k8s.io/client-go/kubernetes/scheme" "k8s.io/client-go/rest" ctrl "sigs.k8s.io/controller-runtime" @@ -86,6 +87,8 @@ var _ = BeforeSuite(func(done Done) { Expect(err).NotTo(HaveOccurred()) err = jaegerv1.AddToScheme(clientgoscheme.Scheme) Expect(err).NotTo(HaveOccurred()) + err = operatorsv1.AddToScheme(clientgoscheme.Scheme) + Expect(err).NotTo(HaveOccurred()) k8sClient, err = client.New(cfg, client.Options{Scheme: clientgoscheme.Scheme}) Expect(err).ToNot(HaveOccurred()) diff --git a/controllers/operandrequest/reconcile_operand.go b/controllers/operandrequest/reconcile_operand.go index 45e09967..693711bf 100644 --- a/controllers/operandrequest/reconcile_operand.go +++ b/controllers/operandrequest/reconcile_operand.go @@ -22,7 +22,6 @@ import ( "encoding/hex" "encoding/json" "fmt" - "regexp" "strconv" "strings" "sync" @@ -175,17 +174,10 @@ func (r *Reconciler) reconcileOperand(ctx context.Context, requestInstance *oper } if !opdRegistry.UserManaged { - // find the OperandRequest which has the same operator's channel version as existing subscription. + // find the OperandRequest which has the same operator's channel or fallback channels as existing subscription. // ODLM will only reconcile Operand based on OperandConfig for this OperandRequest - var requestList []string - reg, _ := regexp.Compile(`^(.*)\.(.*)\.(.*)\/request`) - for anno, version := range sub.Annotations { - if reg.MatchString(anno) && version == sub.Spec.Channel { - requestList = append(requestList, anno) - } - } - - if len(requestList) == 0 || !util.Contains(requestList, requestInstance.Namespace+"."+requestInstance.Name+"."+operand.Name+"/request") { + channels := []string{opdRegistry.Channel} + if channels = append(channels, opdRegistry.FallbackChannels...); !util.Contains(channels, sub.Spec.Channel) { klog.Infof("Subscription %s in the namespace %s is NOT managed by %s/%s, Skip reconciling Operands", sub.Name, sub.Namespace, requestInstance.Namespace, requestInstance.Name) requestInstance.SetMemberStatus(operand.Name, operatorv1alpha1.OperatorFailed, "", &r.Mutex) continue diff --git a/controllers/operandrequest/reconcile_operator.go b/controllers/operandrequest/reconcile_operator.go index e714274a..459edf8c 100644 --- a/controllers/operandrequest/reconcile_operator.go +++ b/controllers/operandrequest/reconcile_operator.go @@ -238,6 +238,7 @@ func (r *Reconciler) reconcileSubscription(ctx context.Context, requestInstance // check if sub.Spec.Channel and opt.Channel are valid semantic version // set annotation channel back to previous one if sub.Spec.Channel is lower than opt.Channel + // To avoid upgrade from one maintenance version to another maintenance version like from v3 to v3.23 subChanel := util.FindSemantic(sub.Spec.Channel) optChannel := util.FindSemantic(opt.Channel) if semver.IsValid(subChanel) && semver.IsValid(optChannel) && semver.Compare(subChanel, optChannel) < 0 { @@ -249,11 +250,11 @@ func (r *Reconciler) reconcileSubscription(ctx context.Context, requestInstance } else { requestInstance.SetNotFoundOperatorFromRegistryCondition(operand.Name, operatorv1alpha1.ResourceTypeSub, corev1.ConditionFalse, mu) - if minChannel := util.FindMinSemver(sub.Annotations, sub.Spec.Channel); minChannel != "" { + if minChannel := util.FindMinSemverFromAnnotations(sub.Annotations, sub.Spec.Channel); minChannel != "" { sub.Spec.Channel = minChannel } - // update the spec iff channel in sub matches channel in opreg + // update the spec iff channel in sub matches channel if sub.Spec.Channel == opt.Channel { isMatchedChannel = true sub.Spec.CatalogSource = opt.SourceName @@ -422,7 +423,7 @@ func (r *Reconciler) uninstallOperatorsAndOperands(ctx context.Context, operandN } } - uninstallOperator, uninstallOperand := checkSubAnnotationsForUninstall(requestInstance.ObjectMeta.Name, requestInstance.ObjectMeta.Namespace, op.Name, sub) + uninstallOperator, uninstallOperand := checkSubAnnotationsForUninstall(requestInstance.ObjectMeta.Name, requestInstance.ObjectMeta.Namespace, op.Name, op.InstallMode, sub) if !uninstallOperand && !uninstallOperator { if err = r.updateSubscription(ctx, requestInstance, sub); err != nil { requestInstance.SetMemberStatus(op.Name, operatorv1alpha1.OperatorFailed, "", &r.Mutex) @@ -731,21 +732,15 @@ func CheckSingletonServices(operator string) bool { // It returns two boolean values: uninstallOperator and uninstallOperand. // If uninstallOperator is true, it means the operator should be uninstalled. // If uninstallOperand is true, it means the operand should be uninstalled. -func checkSubAnnotationsForUninstall(reqName, reqNs, opName string, sub *olmv1alpha1.Subscription) (bool, bool) { +func checkSubAnnotationsForUninstall(reqName, reqNs, opName, installMode string, sub *olmv1alpha1.Subscription) (bool, bool) { uninstallOperator := true uninstallOperand := true - var curChannel string - if sub.GetAnnotations() != nil { - curChannel = sub.Annotations[reqNs+"."+reqName+"."+opName+"/request"] - } - delete(sub.Annotations, reqNs+"."+reqName+"."+opName+"/request") delete(sub.Annotations, reqNs+"."+reqName+"."+opName+"/operatorNamespace") var opreqNsSlice []string var operatorNameSlice []string - var channelSlice []string namespaceReg, _ := regexp.Compile(`^(.*)\.(.*)\.(.*)\/operatorNamespace`) channelReg, _ := regexp.Compile(`^(.*)\.(.*)\.(.*)\/request`) @@ -755,7 +750,6 @@ func checkSubAnnotationsForUninstall(reqName, reqNs, opName string, sub *olmv1al } if channelReg.MatchString(key) { - channelSlice = append(channelSlice, value) // Extract the operator name from the key keyParts := strings.Split(key, "/") annoPrefix := strings.Split(keyParts[0], ".") @@ -773,10 +767,11 @@ func checkSubAnnotationsForUninstall(reqName, reqNs, opName string, sub *olmv1al uninstallOperator = false } - // If the removed/uninstalled /request annotation's value is NOT the same as all other /request annotation's values. - // or the operator namespace in one of remaining annotation is the same as the operator name in removed/uninstalled /request - // the operand should NOT be uninstalled. - if util.Differs(channelSlice, curChannel) || util.Contains(operatorNameSlice, opName) { + // When one of following conditions are met, the operand will NOT be uninstalled: + // 1. operator is not uninstalled AND intallMode is no-op. + // 2. operator is uninstalled AND at least one other /operatorNamespace annotation exists. + // 2. remaining /request annotation's values contain the same operator name + if (!uninstallOperator && installMode == operatorv1alpha1.InstallModeNoop) || (uninstallOperator && len(opreqNsSlice) != 0) || util.Contains(operatorNameSlice, opName) { uninstallOperand = false } diff --git a/controllers/operandrequest/reconcile_operator_test.go b/controllers/operandrequest/reconcile_operator_test.go index c141c48f..35ef023e 100644 --- a/controllers/operandrequest/reconcile_operator_test.go +++ b/controllers/operandrequest/reconcile_operator_test.go @@ -88,43 +88,43 @@ func TestGenerateClusterObjects(t *testing.T) { } func TestCheckSubAnnotationsForUninstall(t *testing.T) { + reqNameA := "common-service" - reqNsA := "ibm-common-services" - opNameA := "ibm-iam" - opChannelA := "v3" + reqNsOld := "ibm-common-services" + opNameV3 := "ibm-iam" + opChannelV3 := "v3" reqNameB := "other-request" - reqNsB := "other-namespace" - opNameB := "ibm-im" - opChannelB := "v4.0" + reqNsNew := "other-namespace" + opNameV4 := "ibm-im" + opChannelV4 := "v4.0" - reqNameC := "common-service" - reqNsC := "ibm-common-services" + reqNameC := "common-service-postgresql" opNameC := "common-service-postgresql" - opChannelC := "stable-v1" + opChannelC := "stable-v1.22" - reqNameD := "common-service" - reqNsD := "ibm-common-services" + reqNameD := "edb-keycloak" opNameD := "edb-keycloak" - opChannelD := "stable-v1" + opChannelD := "stable" // The annotation key has prefix: ../* // When following conditions are met, the operator should be uninstalled: // If all remaining /operatorNamespace annotations' values are not the same as subscription's namespace, the operator should be uninstalled. - // When following conditions are met, the operand should be uninstalled: - // 1. The removed/uninstalled /request annotation's value is the same as all other /request annotation's values. - // 2. Operator name in removed/uninstalled /request is different from all other /request annotation's values. + // When one of following conditions are met, the operand will NOT be uninstalled: + // 1. operator is not uninstalled AND intallMode is no-op. + // 2. operator is uninstalled AND at least one other /operatorNamespace annotation exists. + // 2. remaining /request annotation's values contain the same operator name - // Test case 1: uninstallOperator is true, uninstallOperand is true - // The operator and operand should be uninstalled because only the remaining OperandRequest B is internal-opreq: true. + // Test case 1: uninstallOperator is true, uninstallOperand is true for uninstalling operator with v3 no-op installMode + // The operator and operand should be uninstalled because no remaining annotation is left. sub := &olmv1alpha1.Subscription{ ObjectMeta: metav1.ObjectMeta{ - Namespace: reqNsA, + Namespace: reqNsOld, Annotations: map[string]string{ - reqNsA + "." + reqNameA + "." + opNameA + "/request": opChannelA, - reqNsA + "." + reqNameA + "." + opNameA + "/operatorNamespace": reqNsA, + reqNsOld + "." + reqNameA + "." + opNameV3 + "/request": opChannelV3, + reqNsOld + "." + reqNameA + "." + opNameV3 + "/operatorNamespace": reqNsOld, }, Labels: map[string]string{ constant.OpreqLabel: "true", @@ -132,24 +132,22 @@ func TestCheckSubAnnotationsForUninstall(t *testing.T) { }, } - uninstallOperator, uninstallOperand := checkSubAnnotationsForUninstall(reqNameA, reqNsA, opNameA, sub) + uninstallOperator, uninstallOperand := checkSubAnnotationsForUninstall(reqNameA, reqNsOld, opNameV3, operatorv1alpha1.InstallModeNoop, sub) assert.True(t, uninstallOperator) assert.True(t, uninstallOperand) - assert.NotContains(t, sub.Annotations, reqNsA+"."+reqNameA+"."+opNameA+"/request") - assert.NotContains(t, sub.Annotations, reqNsA+"."+reqNameA+"."+opNameA+"/operatorNamespace") + assert.NotContains(t, sub.Annotations, reqNsOld+"."+reqNameA+"."+opNameV3+"/request") + assert.NotContains(t, sub.Annotations, reqNsOld+"."+reqNameA+"."+opNameV3+"/operatorNamespace") - // Test case 2: uninstallOperator is true, uninstallOperand is false - // The operator should be uninstalled because only the remaining Subscription B requesting operator is not in the same namespace as the Subscription. + // Test case 2: uninstallOperator is true, uninstallOperand is true for uninstalling operator with general installMode + // The operator and operand should be uninstalled because no remaining annotation is left. sub = &olmv1alpha1.Subscription{ ObjectMeta: metav1.ObjectMeta{ - Namespace: reqNsA, + Namespace: reqNsOld, Annotations: map[string]string{ - reqNsA + "." + reqNameA + "." + opNameA + "/request": opChannelA, - reqNsA + "." + reqNameA + "." + opNameA + "/operatorNamespace": reqNsA, - reqNsB + "." + reqNameB + "." + opNameB + "/request": opChannelB, - reqNsB + "." + reqNameB + "." + opNameB + "/operatorNamespace": reqNsB, + reqNsOld + "." + reqNameA + "." + opNameV4 + "/request": opChannelV4, + reqNsOld + "." + reqNameA + "." + opNameV4 + "/operatorNamespace": reqNsOld, }, Labels: map[string]string{ constant.OpreqLabel: "true", @@ -157,91 +155,136 @@ func TestCheckSubAnnotationsForUninstall(t *testing.T) { }, } - uninstallOperator, uninstallOperand = checkSubAnnotationsForUninstall(reqNameA, reqNsA, opNameA, sub) + uninstallOperator, uninstallOperand = checkSubAnnotationsForUninstall(reqNameA, reqNsOld, opNameV4, operatorv1alpha1.InstallModeNamespace, sub) + + assert.True(t, uninstallOperator) + assert.True(t, uninstallOperand) + + assert.NotContains(t, sub.Annotations, reqNsOld+"."+reqNameA+"."+opNameV4+"/request") + assert.NotContains(t, sub.Annotations, reqNsOld+"."+reqNameA+"."+opNameV4+"/operatorNamespace") + + // Test case 3: uninstallOperator is true, uninstallOperand is false for all namespace migration + // where operator is uninstalled and will be reinstalled in new namespace and operand is not for old operator with v3 no-op installMode + sub = &olmv1alpha1.Subscription{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: reqNsOld, + Annotations: map[string]string{ + reqNsOld + "." + reqNameA + "." + opNameV3 + "/request": opChannelV3, + reqNsOld + "." + reqNameA + "." + opNameV3 + "/operatorNamespace": reqNsOld, + reqNsNew + "." + reqNameB + "." + opNameV4 + "/request": opChannelV4, + reqNsNew + "." + reqNameB + "." + opNameV4 + "/operatorNamespace": reqNsNew, + }, + }, + } + + uninstallOperator, uninstallOperand = checkSubAnnotationsForUninstall(reqNameA, reqNsOld, opNameV3, operatorv1alpha1.InstallModeNoop, sub) assert.True(t, uninstallOperator) assert.False(t, uninstallOperand) - assert.NotContains(t, sub.Annotations, reqNsA+"."+reqNameA+"."+opNameA+"/request") - assert.NotContains(t, sub.Annotations, reqNsA+"."+reqNameA+"."+opNameA+"/operatorNamespace") - assert.Contains(t, sub.Annotations, reqNsB+"."+reqNameB+"."+opNameB+"/request") - assert.Contains(t, sub.Annotations, reqNsB+"."+reqNameB+"."+opNameB+"/operatorNamespace") + assert.NotContains(t, sub.Annotations, reqNsOld+"."+reqNameA+"."+opNameV3+"/request") + assert.NotContains(t, sub.Annotations, reqNsOld+"."+reqNameA+"."+opNameV3+"/operatorNamespace") + assert.Contains(t, sub.Annotations, reqNsNew+"."+reqNameB+"."+opNameV4+"/request") + assert.Contains(t, sub.Annotations, reqNsNew+"."+reqNameB+"."+opNameV4+"/operatorNamespace") - // Test case 3: uninstallOperator is false, uninstallOperand is true - // The operator should not be uninstalled because the remaining Subscription B requesting operator is in the same namespace as the Subscription. - // The operand should be uninstalled because - // 1. the operator name in removed/uninstalled Subscription A is different from all other Subscription annotation's values, - // 2. but the removed/uninstalled /request annotation's value is the same as all other /request annotation's values. + // Test case 4: uninstallOperator is true, uninstallOperand is false for all namespace migration + // where operator is uninstalled and will be reinstalled in new namespace and operand is not for operator with general installMode sub = &olmv1alpha1.Subscription{ ObjectMeta: metav1.ObjectMeta{ - Namespace: reqNsC, + Namespace: reqNsOld, Annotations: map[string]string{ - reqNsC + "." + reqNameC + "." + opNameC + "/request": opChannelC, - reqNsC + "." + reqNameC + "." + opNameC + "/operatorNamespace": reqNsC, - reqNsD + "." + reqNameD + "." + opNameD + "/request": opChannelD, - reqNsD + "." + reqNameD + "." + opNameD + "/operatorNamespace": reqNsD, + reqNsOld + "." + reqNameA + "." + opNameV3 + "/request": opChannelV3, + reqNsOld + "." + reqNameA + "." + opNameV3 + "/operatorNamespace": reqNsOld, + reqNsNew + "." + reqNameB + "." + opNameV4 + "/request": opChannelV4, + reqNsNew + "." + reqNameB + "." + opNameV4 + "/operatorNamespace": reqNsNew, }, }, } - uninstallOperator, uninstallOperand = checkSubAnnotationsForUninstall(reqNameC, reqNsC, opNameC, sub) + uninstallOperator, uninstallOperand = checkSubAnnotationsForUninstall(reqNameA, reqNsOld, opNameV3, operatorv1alpha1.InstallModeNamespace, sub) + + assert.True(t, uninstallOperator) + assert.False(t, uninstallOperand) + + assert.NotContains(t, sub.Annotations, reqNsOld+"."+reqNameA+"."+opNameV3+"/request") + assert.NotContains(t, sub.Annotations, reqNsOld+"."+reqNameA+"."+opNameV3+"/operatorNamespace") + assert.Contains(t, sub.Annotations, reqNsNew+"."+reqNameB+"."+opNameV4+"/request") + assert.Contains(t, sub.Annotations, reqNsNew+"."+reqNameB+"."+opNameV4+"/operatorNamespace") + + // Test case 5: uninstallOperator is false, uninstallOperand is true for removing operand only for specific operandrequest + // The operator should not be uninstalled because the remaining request is requesting operator is in the same namespace as the Subscription. + // The operand should be uninstalled because this operand is NOT noop InstallMode And no other OperandRequest is requesting the same operand. + // For example, no OperandRequest is requesting common-service-postgresql. + sub = &olmv1alpha1.Subscription{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: reqNsOld, + Annotations: map[string]string{ + reqNsOld + "." + reqNameC + "." + opNameC + "/request": opChannelC, + reqNsOld + "." + reqNameC + "." + opNameC + "/operatorNamespace": reqNsOld, + reqNsOld + "." + reqNameD + "." + opNameD + "/request": opChannelD, + reqNsOld + "." + reqNameD + "." + opNameD + "/operatorNamespace": reqNsOld, + }, + }, + } + + uninstallOperator, uninstallOperand = checkSubAnnotationsForUninstall(reqNameC, reqNsOld, opNameC, operatorv1alpha1.InstallModeNamespace, sub) assert.False(t, uninstallOperator) assert.True(t, uninstallOperand) - assert.NotContains(t, sub.Annotations, reqNsC+"."+reqNameC+"."+opNameC+"/request") - assert.NotContains(t, sub.Annotations, reqNsC+"."+reqNameC+"."+opNameC+"/operatorNamespace") - assert.Contains(t, sub.Annotations, reqNsD+"."+reqNameD+"."+opNameD+"/request") - assert.Contains(t, sub.Annotations, reqNsD+"."+reqNameD+"."+opNameD+"/operatorNamespace") + assert.NotContains(t, sub.Annotations, reqNsOld+"."+reqNameC+"."+opNameC+"/request") + assert.NotContains(t, sub.Annotations, reqNsOld+"."+reqNameC+"."+opNameC+"/operatorNamespace") + assert.Contains(t, sub.Annotations, reqNsOld+"."+reqNameD+"."+opNameD+"/request") + assert.Contains(t, sub.Annotations, reqNsOld+"."+reqNameD+"."+opNameD+"/operatorNamespace") - // Test case 4: uninstallOperator is false, uninstallOperand is false - // The operator and operand should not be uninstalled because at least one different OperandRequest requesting same operator - // But the annotation of removed OperandRequest should be removed. + // Test case 6: uninstallOperator is false, uninstallOperand is false for removing one no-op operand only for upgrade scenario + // The operator should not be uninstalled because the remaining request is requesting operator is in the same namespace as the Subscription. + // The operand should NOT be uninstalled because this operand is noop InstallMode And other OperandRequest is requesting the newer version operand. + // For example, IAM -> IM in-place upgrade scenario. sub = &olmv1alpha1.Subscription{ ObjectMeta: metav1.ObjectMeta{ - Namespace: reqNsA, + Namespace: reqNsOld, Annotations: map[string]string{ - reqNsA + "." + reqNameA + "." + opNameA + "/request": opChannelA, - reqNsA + "." + reqNameA + "." + opNameA + "/operatorNamespace": reqNsA, - // The remaining OperandRequest B is requesting the same operator - reqNsB + "." + reqNameB + "." + opNameA + "/request": opChannelA, - reqNsB + "." + reqNameB + "." + opNameA + "/operatorNamespace": reqNsA, + reqNsOld + "." + reqNameA + "." + opNameV3 + "/request": opChannelV3, + reqNsOld + "." + reqNameA + "." + opNameV3 + "/operatorNamespace": reqNsOld, + reqNsOld + "." + reqNameB + "." + opNameV4 + "/request": opChannelV4, + reqNsOld + "." + reqNameB + "." + opNameV4 + "/operatorNamespace": reqNsOld, }, }, } - uninstallOperator, uninstallOperand = checkSubAnnotationsForUninstall(reqNameA, reqNsA, opNameA, sub) + uninstallOperator, uninstallOperand = checkSubAnnotationsForUninstall(reqNameA, reqNsOld, opNameV3, operatorv1alpha1.InstallModeNoop, sub) assert.False(t, uninstallOperator) assert.False(t, uninstallOperand) - assert.NotContains(t, sub.Annotations, reqNsA+"."+reqNameA+"."+opNameA+"/request") - assert.NotContains(t, sub.Annotations, reqNsA+"."+reqNameA+"."+opNameA+"/operatorNamespace") - assert.Contains(t, sub.Annotations, reqNsB+"."+reqNameB+"."+opNameA+"/request") - assert.Contains(t, sub.Annotations, reqNsB+"."+reqNameB+"."+opNameA+"/operatorNamespace") + assert.NotContains(t, sub.Annotations, reqNsOld+"."+reqNameA+"."+opNameV3+"/request") + assert.NotContains(t, sub.Annotations, reqNsOld+"."+reqNameA+"."+opNameV3+"/operatorNamespace") + assert.Contains(t, sub.Annotations, reqNsOld+"."+reqNameB+"."+opNameV4+"/request") + assert.Contains(t, sub.Annotations, reqNsOld+"."+reqNameB+"."+opNameV4+"/operatorNamespace") - // Test case 5: uninstallOperator is false, uninstallOperand is false - // The operator and operand should not be uninstalled because at OperandRequest request a different operator name and different channel, but the same operator namespace - // But the annotation of removed OperandRequest should be removed. + // Test case 7: uninstallOperator is false, uninstallOperand is false + // The operator and operand should not be uninstalled because at least one different OperandRequest requesting same operator + // For example, two OperandRequests are requesting IM. sub = &olmv1alpha1.Subscription{ ObjectMeta: metav1.ObjectMeta{ - Namespace: reqNsA, + Namespace: reqNsNew, Annotations: map[string]string{ - reqNsA + "." + reqNameA + "." + opNameA + "/request": opChannelA, - reqNsA + "." + reqNameA + "." + opNameA + "/operatorNamespace": reqNsA, - reqNsB + "." + reqNameB + "." + opNameB + "/request": opChannelB, - reqNsB + "." + reqNameB + "." + opNameB + "/operatorNamespace": reqNsA, + reqNsNew + "." + reqNameA + "." + opNameV4 + "/request": opChannelV4, + reqNsNew + "." + reqNameA + "." + opNameV4 + "/operatorNamespace": reqNsNew, + reqNsNew + "." + reqNameB + "." + opNameV4 + "/request": opChannelV4, + reqNsNew + "." + reqNameB + "." + opNameV4 + "/operatorNamespace": reqNsNew, }, }, } - uninstallOperator, uninstallOperand = checkSubAnnotationsForUninstall(reqNameA, reqNsA, opNameA, sub) + uninstallOperator, uninstallOperand = checkSubAnnotationsForUninstall(reqNameA, reqNsNew, opNameV4, operatorv1alpha1.InstallModeNoop, sub) assert.False(t, uninstallOperator) assert.False(t, uninstallOperand) - assert.NotContains(t, sub.Annotations, reqNsA+"."+reqNameA+"."+opNameA+"/request") - assert.NotContains(t, sub.Annotations, reqNsA+"."+reqNameA+"."+opNameA+"/operatorNamespace") - assert.Contains(t, sub.Annotations, reqNsB+"."+reqNameB+"."+opNameB+"/request") - assert.Contains(t, sub.Annotations, reqNsB+"."+reqNameB+"."+opNameB+"/operatorNamespace") + assert.NotContains(t, sub.Annotations, reqNsNew+"."+reqNameA+"."+opNameV4+"/request") + assert.NotContains(t, sub.Annotations, reqNsNew+"."+reqNameA+"."+opNameV4+"/operatorNamespace") + assert.Contains(t, sub.Annotations, reqNsNew+"."+reqNameB+"."+opNameV4+"/request") + assert.Contains(t, sub.Annotations, reqNsNew+"."+reqNameB+"."+opNameV4+"/operatorNamespace") } diff --git a/controllers/operator/manager.go b/controllers/operator/manager.go index ff54761d..7c0cab6b 100644 --- a/controllers/operator/manager.go +++ b/controllers/operator/manager.go @@ -26,6 +26,7 @@ import ( olmv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1" operatorsv1 "github.com/operator-framework/operator-lifecycle-manager/pkg/package-server/apis/operators/v1" "github.com/pkg/errors" + "golang.org/x/mod/semver" corev1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" @@ -137,31 +138,38 @@ func (s sortableCatalogSource) Less(i, j int) bool { return s[i].Namespace < s[j].Namespace } -func (m *ODLMOperator) GetCatalogSourceFromPackage(ctx context.Context, packageName, namespace, channel, registryNs, odlmCatalog, odlmCatalogNs string, excludedCatalogSources []string) (catalogSourceName string, catalogSourceNs string, err error) { +func (m *ODLMOperator) GetCatalogSourceAndChannelFromPackage(ctx context.Context, opregCatalog, opregCatalogNs, packageName, namespace, channel string, fallbackChannels []string, + registryNs, odlmCatalog, odlmCatalogNs string, excludedCatalogSources []string) (catalogSourceName string, catalogSourceNs string, availableChannel string, err error) { + packageManifestList := &operatorsv1.PackageManifestList{} opts := []client.ListOption{ client.MatchingFields{"metadata.name": packageName}, client.InNamespace(namespace), } if err := m.Reader.List(ctx, packageManifestList, opts...); err != nil { - return "", "", err + return "", "", "", err } number := len(packageManifestList.Items) switch number { case 0: klog.V(2).Infof("Not found PackageManifest %s in the namespace %s has channel %s", packageName, namespace, channel) - return "", "", nil - case 1: - if excludedCatalogSources != nil && util.Contains(excludedCatalogSources, packageManifestList.Items[0].Status.CatalogSource) { - klog.V(2).Infof("Not found available CatalogSource for PackageManifest %s in the namespace %s, CatalogSource %s is excluded from OperandRegistry annotations", packageName, namespace, packageManifestList.Items[0].Status.CatalogSource) - return "", "", nil - } - return packageManifestList.Items[0].Status.CatalogSource, packageManifestList.Items[0].Status.CatalogSourceNamespace, nil + return "", "", "", nil default: - var catalogSourceCandidate []CatalogSource + // Check if the CatalogSource and CatalogSource namespace are specified in OperandRegistry + if opregCatalog != "" && opregCatalogNs != "" { + curChannel := getFirstAvailableSemverChannelFromCatalog(packageManifestList, fallbackChannels, channel, opregCatalog, opregCatalogNs) + if curChannel == "" { + klog.Errorf("Not found PackageManifest %s in the namespace %s has channel %s or fallback channels %s in the CatalogSource %s in the namespace %s", packageName, namespace, channel, fallbackChannels, opregCatalog, opregCatalogNs) + return "", "", "", nil + } + return opregCatalog, opregCatalogNs, curChannel, nil + } + // Get the CatalogSource and CatalogSource namespace from the PackageManifest + var primaryCatalogCandidate []CatalogSource + var fallBackChannelAndCatalogMapping = make(map[string][]CatalogSource) for _, pm := range packageManifestList.Items { - if !channelCheck(channel, pm.Status.Channels) || (excludedCatalogSources != nil && util.Contains(excludedCatalogSources, pm.Status.CatalogSource)) { + if excludedCatalogSources != nil && util.Contains(excludedCatalogSources, pm.Status.CatalogSource) { continue } catalogsource := &olmv1alpha1.CatalogSource{} @@ -169,7 +177,7 @@ func (m *ODLMOperator) GetCatalogSourceFromPackage(ctx context.Context, packageN klog.Warning(err) continue } - catalogSourceCandidate = append(catalogSourceCandidate, CatalogSource{ + currentCatalog := CatalogSource{ Name: pm.Status.CatalogSource, Namespace: pm.Status.CatalogSourceNamespace, OpNamespace: namespace, @@ -177,23 +185,42 @@ func (m *ODLMOperator) GetCatalogSourceFromPackage(ctx context.Context, packageN Priority: catalogsource.Spec.Priority, ODLMCatalog: odlmCatalog, ODLMCatalogNamespace: odlmCatalogNs, - }) + } + if channelCheck(channel, pm.Status.Channels) { + primaryCatalogCandidate = append(primaryCatalogCandidate, currentCatalog) + } + for _, fc := range fallbackChannels { + if channelCheck(fc, pm.Status.Channels) { + fallBackChannelAndCatalogMapping[fc] = append(fallBackChannelAndCatalogMapping[fc], currentCatalog) + } + } } - if len(catalogSourceCandidate) == 0 { - klog.Errorf("Not found PackageManifest %s in the namespace %s has channel %s", packageName, namespace, channel) - return "", "", nil + if len(primaryCatalogCandidate) == 0 { + klog.Warningf("Not found PackageManifest %s in the namespace %s has channel %s", packageName, namespace, channel) + if len(fallBackChannelAndCatalogMapping) == 0 { + klog.Errorf("Not found PackageManifest %s in the namespace %s has fallback channels %v", packageName, namespace, fallbackChannels) + return "", "", "", nil + } + fallbackChannel, fallbackCatalog := findCatalogFromFallbackChannels(fallbackChannels, fallBackChannelAndCatalogMapping) + if len(fallbackCatalog) == 0 { + klog.Errorf("Not found PackageManifest %s in the namespace %s has fallback channels %v", packageName, namespace, fallbackChannels) + return "", "", "", nil + } + klog.Infof("Found %v CatalogSources for PackageManifest %s in the namespace %s has fallback channel %s", len(fallbackCatalog), packageName, namespace, fallbackChannel) + primaryCatalogCandidate = fallbackCatalog + channel = fallbackChannel } - klog.V(2).Infof("Found %v CatalogSources for PackageManifest %s in the namespace %s has channel %s", len(catalogSourceCandidate), packageName, namespace, channel) + klog.V(2).Infof("Found %v CatalogSources for PackageManifest %s in the namespace %s has channel %s", len(primaryCatalogCandidate), packageName, namespace, channel) // Sort CatalogSources by priority - sort.Sort(sortableCatalogSource(catalogSourceCandidate)) - for i, c := range catalogSourceCandidate { + sort.Sort(sortableCatalogSource(primaryCatalogCandidate)) + for i, c := range primaryCatalogCandidate { klog.V(2).Infof("The %vth sorted CatalogSource is %s in namespace %s with priority: %v", i, c.Name, c.Namespace, c.Priority) } - return catalogSourceCandidate[0].Name, catalogSourceCandidate[0].Namespace, nil + return primaryCatalogCandidate[0].Name, primaryCatalogCandidate[0].Namespace, channel, nil } } -func channelCheck(channelName string, channelList []operatorsv1.PackageChannel) (found bool) { +func channelCheck(channelName string, channelList []operatorsv1.PackageChannel) bool { for _, channel := range channelList { if channelName == channel.Name { return true @@ -202,6 +229,51 @@ func channelCheck(channelName string, channelList []operatorsv1.PackageChannel) return false } +func findCatalogFromFallbackChannels(fallbackChannels []string, fallBackChannelAndCatalogMapping map[string][]CatalogSource) (string, []CatalogSource) { + var fallbackChannel string + var fallbackCatalog []CatalogSource + + // sort fallback channels by semantic version + semverlList, semVerChannelMappings := prunedSemverChannel(fallbackChannels) + + maxChannel := util.FindMaxSemver("", semverlList, semVerChannelMappings) + if catalogSources, ok := fallBackChannelAndCatalogMapping[maxChannel]; ok { + fallbackChannel = maxChannel + fallbackCatalog = append(fallbackCatalog, catalogSources...) + } + return fallbackChannel, fallbackCatalog +} + +func prunedSemverChannel(fallbackChannels []string) ([]string, map[string]string) { + var semverlList []string + var semVerChannelMappings = make(map[string]string) + for _, fc := range fallbackChannels { + semVerChannelMappings[util.FindSemantic(fc)] = fc + semverlList = append(semverlList, util.FindSemantic(fc)) + } + return semverlList, semVerChannelMappings +} + +func getFirstAvailableSemverChannelFromCatalog(packageManifestList *operatorsv1.PackageManifestList, fallbackChannels []string, channel, catalogName, catalogNs string) string { + semverlList, semVerChannelMappings := prunedSemverChannel(fallbackChannels) + sort.Sort(semver.ByVersion(semverlList)) + + for _, pm := range packageManifestList.Items { + if pm.Status.CatalogSource == catalogName && pm.Status.CatalogSourceNamespace == catalogNs { + if channelCheck(channel, pm.Status.Channels) { + return channel + } + // iterate the sorted semver list in reverse order to get the first available channel + for i := len(semverlList) - 1; i >= 0; i-- { + if channelCheck(semverlList[i], pm.Status.Channels) { + return semVerChannelMappings[semverlList[i]] + } + } + } + } + return "" +} + // ListOperandRegistry lists the OperandRegistry instance with default value func (m *ODLMOperator) ListOperandRegistry(ctx context.Context, label map[string]string) (*apiv1alpha1.OperandRegistryList, error) { registryList := &apiv1alpha1.OperandRegistryList{} @@ -537,19 +609,17 @@ func (m *ODLMOperator) GetOperandFromRegistry(ctx context.Context, reg *apiv1alp odlmCatalogNs = odlmSubList.Items[0].Spec.CatalogSourceNamespace } - if opt.SourceName == "" || opt.SourceNamespace == "" { - catalogSourceName, catalogSourceNs, err := m.GetCatalogSourceFromPackage(ctx, opt.PackageName, opt.Namespace, opt.Channel, reg.Namespace, odlmCatalog, odlmCatalogNs, excludedCatalogSources) - if err != nil { - return nil, err - } - - if catalogSourceName == "" || catalogSourceNs == "" { - klog.V(2).Infof("no catalogsource found for %v", opt.PackageName) - } + catalogSourceName, catalogSourceNs, channel, err := m.GetCatalogSourceAndChannelFromPackage(ctx, opt.SourceName, opt.SourceNamespace, opt.PackageName, opt.Namespace, opt.Channel, opt.FallbackChannels, reg.Namespace, odlmCatalog, odlmCatalogNs, excludedCatalogSources) + if err != nil { + return nil, err + } - opt.SourceName, opt.SourceNamespace = catalogSourceName, catalogSourceNs + if catalogSourceName == "" || catalogSourceNs == "" { + klog.V(2).Infof("no catalogsource found for %v", opt.PackageName) } + opt.SourceName, opt.SourceNamespace, opt.Channel = catalogSourceName, catalogSourceNs, channel + return opt, nil } diff --git a/controllers/operator/manager_test.go b/controllers/operator/manager_test.go new file mode 100644 index 00000000..4d55b5e6 --- /dev/null +++ b/controllers/operator/manager_test.go @@ -0,0 +1,417 @@ +// +// Copyright 2022 IBM Corporation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package operator + +import ( + "context" + "reflect" + "testing" + + olmv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1" + operatorsv1 "github.com/operator-framework/operator-lifecycle-manager/pkg/package-server/apis/operators/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +func TestChannelCheck(t *testing.T) { + channelName := "stable" + channelList := []operatorsv1.PackageChannel{ + { + Name: "alpha", + }, + { + Name: "beta", + }, + { + Name: "stable", + }, + } + + if !channelCheck(channelName, channelList) { + t.Errorf("Expected channelCheck to return true, but got false") + } + + channelName = "dev" + + if channelCheck(channelName, channelList) { + t.Errorf("Expected channelCheck to return false, but got true") + } +} + +func TestPrunedSemverChannel(t *testing.T) { + fallbackChannels := []string{"stable-v1", "alpha-v1.5", "v2.0.1", "stable-v2.5.0", "v4.0"} + expectedSemverList := []string{"v1", "v1.5", "v2.0.1", "v2.5.0", "v4.0"} + expectedSemVerChannelMappings := map[string]string{ + "v1": "stable-v1", + "v1.5": "alpha-v1.5", + "v2.0.1": "v2.0.1", + "v2.5.0": "stable-v2.5.0", + "v4.0": "v4.0", + } + + semverList, semVerChannelMappings := prunedSemverChannel(fallbackChannels) + + if len(semverList) != len(expectedSemverList) { + t.Errorf("Expected semver list length %d, but got %d", len(expectedSemverList), len(semverList)) + } + + for i, semver := range semverList { + if semver != expectedSemverList[i] { + t.Errorf("Expected semver %s at index %d, but got %s", expectedSemverList[i], i, semver) + } + } + + if len(semVerChannelMappings) != len(expectedSemVerChannelMappings) { + t.Errorf("Expected semver channel mappings length %d, but got %d", len(expectedSemVerChannelMappings), len(semVerChannelMappings)) + } + + for semver, channel := range semVerChannelMappings { + expectedChannel, ok := expectedSemVerChannelMappings[semver] + if !ok { + t.Errorf("Unexpected semver %s in semver channel mappings", semver) + } + if channel != expectedChannel { + t.Errorf("Expected channel %s for semver %s, but got %s", expectedChannel, semver, channel) + } + } +} + +func TestFindCatalogFromFallbackChannels(t *testing.T) { + fallbackChannels := []string{"stable-v1", "alpha-v1.5", "v2.0.1", "stable-v2.5.0", "v4.0"} + fallBackChannelAndCatalogMapping := map[string][]CatalogSource{ + "v1": {{Name: "catalog1", Namespace: "namespace1"}}, + "v1.5": {{Name: "catalog2", Namespace: "namespace2"}}, + "v2.0.1": {{Name: "catalog3", Namespace: "namespace3"}}, + "v2.5.0": {{Name: "catalog4", Namespace: "namespace4"}}, + "v4.0": {{Name: "catalog5", Namespace: "namespace5"}}, + } + + fallbackChannel, fallbackCatalog := findCatalogFromFallbackChannels(fallbackChannels, fallBackChannelAndCatalogMapping) + + expectedFallbackChannel := "v4.0" + expectedFallbackCatalog := []CatalogSource{{Name: "catalog5", Namespace: "namespace5"}} + + if fallbackChannel != expectedFallbackChannel { + t.Errorf("Expected fallback channel %s, but got %s", expectedFallbackChannel, fallbackChannel) + } + + if !reflect.DeepEqual(fallbackCatalog, expectedFallbackCatalog) { + t.Errorf("Expected fallback catalog %v, but got %v", expectedFallbackCatalog, fallbackCatalog) + } + + // Find empty catalog + fallBackChannelAndCatalogMapping = map[string][]CatalogSource{} + + fallbackChannel, fallbackCatalog = findCatalogFromFallbackChannels(fallbackChannels, fallBackChannelAndCatalogMapping) + + expectedFallbackChannel = "" + expectedFallbackCatalog = nil + + if fallbackChannel != expectedFallbackChannel { + t.Errorf("Expected fallback channel %s, but got %s", expectedFallbackChannel, fallbackChannel) + } + + if !reflect.DeepEqual(fallbackCatalog, expectedFallbackCatalog) { + t.Errorf("Expected fallback catalog %v, but got %v", expectedFallbackCatalog, fallbackCatalog) + } +} + +func TestGetFirstAvailableSemverChannelFromCatalog(t *testing.T) { + packageManifestList := &operatorsv1.PackageManifestList{ + Items: []operatorsv1.PackageManifest{ + { + Status: operatorsv1.PackageManifestStatus{ + CatalogSource: "catalog1", + CatalogSourceNamespace: "namespace1", + Channels: []operatorsv1.PackageChannel{ + { + Name: "v1.0", + }, + { + Name: "v2.0", + }, + }, + }, + }, + { + Status: operatorsv1.PackageManifestStatus{ + CatalogSource: "catalog2", + CatalogSourceNamespace: "namespace2", + Channels: []operatorsv1.PackageChannel{ + { + Name: "v1.0", + }, + { + Name: "v2.0", + }, + { + Name: "v3.0", + }, + }, + }, + }, + }, + } + + fallbackChannels := []string{} + channel := "v1.0" + + catalogName := "catalog1" + catalogNs := "namespace1" + + // Test with empty fallback channels and channel exists in the catalog + result := getFirstAvailableSemverChannelFromCatalog(packageManifestList, fallbackChannels, channel, catalogName, catalogNs) + expectedResult := "v1.0" + + if result != expectedResult { + t.Errorf("Expected result to be %s, but got %s", expectedResult, result) + } + + // Test with empty fallback channels and channel does not exist in the catalog + channel = "alpha" + result = getFirstAvailableSemverChannelFromCatalog(packageManifestList, fallbackChannels, channel, catalogName, catalogNs) + expectedResult = "" + + if result != expectedResult { + t.Errorf("Expected result to be %s, but got %s", expectedResult, result) + } + + fallbackChannels = []string{"v1.0", "v2.0"} + channel = "v3.0" + + // Test with fallback channels and channel does not exist in the catalog, but fallback channel exists + result = getFirstAvailableSemverChannelFromCatalog(packageManifestList, fallbackChannels, channel, catalogName, catalogNs) + expectedResult = "v2.0" + + if result != expectedResult { + t.Errorf("Expected result to be %s, but got %s", expectedResult, result) + } + + catalogName = "catalog2" + catalogNs = "namespace2" + channel = "v3.0" + + // Test with fallback channels, but channel exist in the catalog + result = getFirstAvailableSemverChannelFromCatalog(packageManifestList, fallbackChannels, channel, catalogName, catalogNs) + expectedResult = "v3.0" + + if result != expectedResult { + t.Errorf("Expected result to be %s, but got %s", expectedResult, result) + } + +} + +type MockReader struct { + PackageManifestList *operatorsv1.PackageManifestList + CatalogSourceList *olmv1alpha1.CatalogSourceList +} + +func (m *MockReader) Get(ctx context.Context, key client.ObjectKey, obj client.Object) error { + if catalogSource, ok := obj.(*olmv1alpha1.CatalogSource); ok { + if m.CatalogSourceList != nil { + for _, cs := range m.CatalogSourceList.Items { + if cs.Name == key.Name && cs.Namespace == key.Namespace { + *catalogSource = cs + return nil + } + } + } + return client.IgnoreNotFound(nil) + } + return nil +} + +func (m *MockReader) List(ctx context.Context, list client.ObjectList, opts ...client.ListOption) error { + if packageManifestList, ok := list.(*operatorsv1.PackageManifestList); ok { + packageManifestList.Items = m.PackageManifestList.Items + } + return nil +} + +func TestGetCatalogSourceAndChannelFromPackage(t *testing.T) { + ctx := context.TODO() + + packageManifestList := &operatorsv1.PackageManifestList{ + Items: []operatorsv1.PackageManifest{ + { + Status: operatorsv1.PackageManifestStatus{ + CatalogSource: "catalog1", + CatalogSourceNamespace: "namespace1", + Channels: []operatorsv1.PackageChannel{ + { + Name: "v3.0", + }, + { + Name: "v2.0", + }, + }, + }, + }, + { + Status: operatorsv1.PackageManifestStatus{ + CatalogSource: "catalog2", + CatalogSourceNamespace: "namespace1", + Channels: []operatorsv1.PackageChannel{ + { + Name: "v1.0", + }, + { + Name: "v2.0", + }, + }, + }, + }, + }, + } + CatalogSourceList := &olmv1alpha1.CatalogSourceList{ + Items: []olmv1alpha1.CatalogSource{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "catalog1", + Namespace: "namespace1", + }, + }, + { + ObjectMeta: metav1.ObjectMeta{ + Name: "catalog2", + Namespace: "namespace1", + }, + Spec: olmv1alpha1.CatalogSourceSpec{ + Priority: 100, + }, + }, + }, + } + + fakeReader := &MockReader{ + PackageManifestList: packageManifestList, + CatalogSourceList: CatalogSourceList, + } + + operator := &ODLMOperator{ + Reader: fakeReader, + } + + registryNs := "registry-namespace" + odlmCatalog := "odlm-catalog" + odlmCatalogNs := "odlm-namespace" + excludedCatalogSources := []string{"excluded1", "excluded2"} + + // Test with setting catalog source explicitly + opregCatalog := "catalog1" + opregCatalogNs := "namespace1" + packageName := "package1" + namespace := "namespace1" + + // Test with channel exists in the catalog + channel := "v3.0" + fallbackChannels := []string{"v2.0", "v1.0"} + + if catalogSourceName, catalogSourceNs, availableChannel, err := operator.GetCatalogSourceAndChannelFromPackage(ctx, opregCatalog, opregCatalogNs, packageName, namespace, channel, fallbackChannels, registryNs, odlmCatalog, odlmCatalogNs, excludedCatalogSources); err != nil { + t.Errorf("Unexpected error: %v", err) + } else { + assertCatalogSourceAndChannel(t, catalogSourceName, "catalog1", catalogSourceNs, "namespace1", availableChannel, "v3.0") + } + + // Test with channel does not exist in the catalog, but fallback channel exists + channel = "v4.0" + if catalogSourceName, catalogSourceNs, availableChannel, err := operator.GetCatalogSourceAndChannelFromPackage(ctx, opregCatalog, opregCatalogNs, packageName, namespace, channel, fallbackChannels, registryNs, odlmCatalog, odlmCatalogNs, excludedCatalogSources); err != nil { + t.Errorf("Unexpected error: %v", err) + } else { + assertCatalogSourceAndChannel(t, catalogSourceName, "catalog1", catalogSourceNs, "namespace1", availableChannel, "v2.0") + } + + // Test with not setting catalog source explicitly + opregCatalog = "" + opregCatalogNs = "" + + // Test with excluded catalog sources + excludedCatalogSources = []string{"catalog1", "catalog2"} + + if catalogSourceName, catalogSourceNs, availableChannel, err := operator.GetCatalogSourceAndChannelFromPackage(ctx, opregCatalog, opregCatalogNs, packageName, namespace, channel, fallbackChannels, registryNs, odlmCatalog, odlmCatalogNs, excludedCatalogSources); err != nil { + t.Errorf("Unexpected error: %v", err) + } else { + assertCatalogSourceAndChannel(t, catalogSourceName, "", catalogSourceNs, "", availableChannel, "") + } + + excludedCatalogSources = []string{} + + // Test with channel does not exist in the catalog, and fallback channel does not exist + fallbackChannels = []string{"v4.0", "v5.0"} + channel = "v6.0" + + if catalogSourceName, catalogSourceNs, availableChannel, err := operator.GetCatalogSourceAndChannelFromPackage(ctx, opregCatalog, opregCatalogNs, packageName, namespace, channel, fallbackChannels, registryNs, odlmCatalog, odlmCatalogNs, excludedCatalogSources); err != nil { + t.Errorf("Unexpected error: %v", err) + } else { + assertCatalogSourceAndChannel(t, catalogSourceName, "", catalogSourceNs, "", availableChannel, "") + } + + // Test with channel does not exist in the catalog, and fallback channel exists + fallbackChannels = []string{"v3.0", "v2.0"} + channel = "v4.0" + + if catalogSourceName, catalogSourceNs, availableChannel, err := operator.GetCatalogSourceAndChannelFromPackage(ctx, opregCatalog, opregCatalogNs, packageName, namespace, channel, fallbackChannels, registryNs, odlmCatalog, odlmCatalogNs, excludedCatalogSources); err != nil { + t.Errorf("Unexpected error: %v", err) + } else { + assertCatalogSourceAndChannel(t, catalogSourceName, "catalog1", catalogSourceNs, "namespace1", availableChannel, "v3.0") + } + + // Test with channel does not exist in the catalog, and fallback channel exists, and found the catalog with higher priority + fallbackChannels = []string{"v2.0", "v1.0"} + channel = "v4.0" + + if catalogSourceName, catalogSourceNs, availableChannel, err := operator.GetCatalogSourceAndChannelFromPackage(ctx, opregCatalog, opregCatalogNs, packageName, namespace, channel, fallbackChannels, registryNs, odlmCatalog, odlmCatalogNs, excludedCatalogSources); err != nil { + t.Errorf("Unexpected error: %v", err) + } else { + assertCatalogSourceAndChannel(t, catalogSourceName, "catalog2", catalogSourceNs, "namespace1", availableChannel, "v2.0") + } + + // Test with channel already exist in the catalog + channel = "v1.0" + + if catalogSourceName, catalogSourceNs, availableChannel, err := operator.GetCatalogSourceAndChannelFromPackage(ctx, opregCatalog, opregCatalogNs, packageName, namespace, channel, fallbackChannels, registryNs, odlmCatalog, odlmCatalogNs, excludedCatalogSources); err != nil { + t.Errorf("Unexpected error: %v", err) + } else { + assertCatalogSourceAndChannel(t, catalogSourceName, "catalog2", catalogSourceNs, "namespace1", availableChannel, "v1.0") + } + + // Test with channel already exist in the catalog, and found the catalog with higher priority + channel = "v2.0" + + if catalogSourceName, catalogSourceNs, availableChannel, err := operator.GetCatalogSourceAndChannelFromPackage(ctx, opregCatalog, opregCatalogNs, packageName, namespace, channel, fallbackChannels, registryNs, odlmCatalog, odlmCatalogNs, excludedCatalogSources); err != nil { + t.Errorf("Unexpected error: %v", err) + } else { + assertCatalogSourceAndChannel(t, catalogSourceName, "catalog2", catalogSourceNs, "namespace1", availableChannel, "v2.0") + } + +} + +func assertCatalogSourceAndChannel(t *testing.T, catalogSourceName, expectedCatalogSourceName, catalogSourceNs, expectedCatalogSourceNs, availableChannel, expectedAvailableChannel string) { + t.Helper() + + if catalogSourceName != expectedCatalogSourceName { + t.Errorf("Expected catalog source name %s, but got %s", expectedCatalogSourceName, catalogSourceName) + } + + if catalogSourceNs != expectedCatalogSourceNs { + t.Errorf("Expected catalog source namespace %s, but got %s", expectedCatalogSourceNs, catalogSourceNs) + } + + if availableChannel != expectedAvailableChannel { + t.Errorf("Expected available channel %s, but got %s", expectedAvailableChannel, availableChannel) + } +} diff --git a/controllers/operatorconfig/operatorconfig_suite_test.go b/controllers/operatorconfig/operatorconfig_suite_test.go index ae4e2246..924627bf 100644 --- a/controllers/operatorconfig/operatorconfig_suite_test.go +++ b/controllers/operatorconfig/operatorconfig_suite_test.go @@ -23,6 +23,7 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + operatorsv1 "github.com/operator-framework/operator-lifecycle-manager/pkg/package-server/apis/operators/v1" "k8s.io/client-go/kubernetes/scheme" "k8s.io/client-go/rest" "sigs.k8s.io/controller-runtime/pkg/client" @@ -64,6 +65,8 @@ var _ = BeforeSuite(func() { err = operatorv1alpha1.AddToScheme(scheme.Scheme) Expect(err).NotTo(HaveOccurred()) + err = operatorsv1.AddToScheme(scheme.Scheme) + Expect(err).NotTo(HaveOccurred()) //+kubebuilder:scaffold:scheme diff --git a/controllers/util/util.go b/controllers/util/util.go index 6beea00c..3b009176 100644 --- a/controllers/util/util.go +++ b/controllers/util/util.go @@ -356,9 +356,31 @@ func FindSemantic(input string) string { return match } -// FindMinSemver returns the minimal semantic version from annotations -func FindMinSemver(annotations map[string]string, curChannel string) string { - // check request annotation in subscription, get all available channels +// FindMinSemver returns the minimal semantic version by given channel and semver list +func FindMinSemver(curChannel string, semverlList []string, semVerChannelMappings map[string]string) string { + if len(semverlList) == 0 { + return "" + } else if !Contains(semverlList, FindSemantic(curChannel)) || curChannel == "" { // if current channel is not in the list or empty + // change channel to minimal version in the list + sort.Sort(semver.ByVersion(semverlList)) + return semVerChannelMappings[semverlList[0]] + } + return curChannel +} + +// FindMaxSemver returns the maximal semantic version by given channel and semver list +func FindMaxSemver(curChannel string, semverlList []string, semVerChannelMappings map[string]string) string { + if len(semverlList) == 0 { + return "" + } else if !Contains(semverlList, FindSemantic(curChannel)) || curChannel == "" { // if current channel is not in the list or empty + // change channel to maximal version in the list + sort.Sort(semver.ByVersion(semverlList)) + return semVerChannelMappings[semverlList[len(semverlList)-1]] + } + return curChannel +} + +func FindSemverFromAnnotations(annotations map[string]string) ([]string, map[string]string) { var semverlList []string var semVerChannelMappings = make(map[string]string) reg, _ := regexp.Compile(`^(.*)\.(.*)\.(.*)\/request`) @@ -369,12 +391,11 @@ func FindMinSemver(annotations map[string]string, curChannel string) string { semVerChannelMappings[prunedChannel] = channel } } - if len(semverlList) == 0 { - return "" - } else if !Contains(semverlList, FindSemantic(curChannel)) { - // upgrade channel to minimal version existing in annotation - sort.Sort(semver.ByVersion(semverlList)) - return semVerChannelMappings[semverlList[0]] - } - return curChannel + return semverlList, semVerChannelMappings +} + +func FindMinSemverFromAnnotations(annotations map[string]string, curChannel string) string { + // check request annotation in subscription, get all available channels + semverlList, semVerChannelMappings := FindSemverFromAnnotations(annotations) + return FindMinSemver(curChannel, semverlList, semVerChannelMappings) } diff --git a/controllers/util/util_test.go b/controllers/util/util_test.go index 7f04a2d0..311df979 100644 --- a/controllers/util/util_test.go +++ b/controllers/util/util_test.go @@ -150,7 +150,7 @@ var _ = Describe("FindSemantic", func() { }) }) -var _ = Describe("FindMinSemver", func() { +var _ = Describe("FindMinSemverFromAnnotations", func() { It("Should return the minimal semantic version from annotations", func() { annotations := map[string]string{ "namespace-a.common-service.operator-a/request": "stable", @@ -160,7 +160,7 @@ var _ = Describe("FindMinSemver", func() { } curChannel := "stable-v1.3.0" expected := "stable" - Expect(FindMinSemver(annotations, curChannel)).Should(Equal(expected)) + Expect(FindMinSemverFromAnnotations(annotations, curChannel)).Should(Equal(expected)) }) It("Should return the minimal semantic version from annotations", func() { @@ -171,7 +171,7 @@ var _ = Describe("FindMinSemver", func() { } curChannel := "v3" expected := "v4.0" - Expect(FindMinSemver(annotations, curChannel)).Should(Equal(expected)) + Expect(FindMinSemverFromAnnotations(annotations, curChannel)).Should(Equal(expected)) }) It("Should return the current channel if it exists in annotations", func() { @@ -183,7 +183,7 @@ var _ = Describe("FindMinSemver", func() { } curChannel := "stable-v1.1.0" expected := "stable-v1.1.0" - Expect(FindMinSemver(annotations, curChannel)).Should(Equal(expected)) + Expect(FindMinSemverFromAnnotations(annotations, curChannel)).Should(Equal(expected)) }) It("Should return the current channel if it exists in annotations", func() { @@ -195,7 +195,7 @@ var _ = Describe("FindMinSemver", func() { } curChannel := "stable" expected := "stable" - Expect(FindMinSemver(annotations, curChannel)).Should(Equal(expected)) + Expect(FindMinSemverFromAnnotations(annotations, curChannel)).Should(Equal(expected)) }) It("Should return an empty string if no valid semantic versions are found", func() { @@ -207,6 +207,54 @@ var _ = Describe("FindMinSemver", func() { } curChannel := "stable-v2.0.0" expected := "" - Expect(FindMinSemver(annotations, curChannel)).Should(Equal(expected)) + Expect(FindMinSemverFromAnnotations(annotations, curChannel)).Should(Equal(expected)) + }) +}) + +var _ = Describe("FindMaxSemver", func() { + It("Should return the maximal semantic version from the given channel and semver list", func() { + curChannel := "stable-v1.2.0" + semverList := []string{"v1.0.0", "v1.1.0", "v1.3.0", "v1.4.0"} + semVerChannelMappings := map[string]string{ + "v1.0.0": "stable-v1.0.0", + "v1.1.0": "stable-v1.1.0", + "v1.3.0": "stable-v1.3.0", + "v1.4.0": "stable-v1.4.0", + } + expected := "stable-v1.4.0" + Expect(FindMaxSemver(curChannel, semverList, semVerChannelMappings)).Should(Equal(expected)) + }) + + It("Should return the current channel if it exists in the semver list", func() { + curChannel := "stable-v1.2.0" + semverList := []string{"v1.0.0", "v1.1.0", "v1.2.0", "v1.3.0"} + semVerChannelMappings := map[string]string{ + "v1.0.0": "stable-v1.0.0", + "v1.1.0": "stable-v1.1.0", + "v1.2.0": "stable-v1.2.0", + "v1.3.0": "stable-v1.3.0", + } + expected := "stable-v1.2.0" + Expect(FindMaxSemver(curChannel, semverList, semVerChannelMappings)).Should(Equal(expected)) + }) + + It("Should return an empty string if the semver list is empty", func() { + curChannel := "stable-v1.2.0" + semverList := []string{} + semVerChannelMappings := map[string]string{} + expected := "" + Expect(FindMaxSemver(curChannel, semverList, semVerChannelMappings)).Should(Equal(expected)) + }) + + It("Should return an empty string if the semVerChannelMappings has no valid mappings", func() { + curChannel := "stable-v1.2.0" + semverList := []string{"v1.4.0", "v1.5.0", "v1.6.0"} + semVerChannelMappings := map[string]string{ + "v1.0.0": "stable-v1.0.0", + "v1.1.0": "stable-v1.1.0", + "v1.3.0": "stable-v1.3.0", + } + expected := "" + Expect(FindMaxSemver(curChannel, semverList, semVerChannelMappings)).Should(Equal(expected)) }) }) From 1a737972a2ae18ac766afa74fcfcbf82b2b947bd Mon Sep 17 00:00:00 2001 From: Allen Li <46284272+qpdpQ@users.noreply.github.com> Date: Mon, 16 Sep 2024 16:39:43 -0400 Subject: [PATCH 137/179] Bump version to 4.3.6 for SC2 4.6.7 (#1082) Signed-off-by: Allen Li --- Makefile | 2 +- ...eployment-lifecycle-manager.clusterserviceversion.yaml | 8 ++++---- ...eployment-lifecycle-manager.clusterserviceversion.yaml | 4 ++-- version/version.go | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Makefile b/Makefile index e02cccf8..5c2560a8 100644 --- a/Makefile +++ b/Makefile @@ -84,7 +84,7 @@ OPERATOR_IMAGE_NAME ?= odlm # Current Operator bundle image name BUNDLE_IMAGE_NAME ?= odlm-operator-bundle # Current Operator version -OPERATOR_VERSION ?= 4.3.5 +OPERATOR_VERSION ?= 4.3.6 # Kind cluster name KIND_CLUSTER_NAME ?= "odlm" diff --git a/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml b/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml index 0aaee96d..929d2e50 100644 --- a/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml +++ b/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml @@ -132,7 +132,7 @@ metadata: createdAt: "2024-08-27T18:18:40Z" description: The Operand Deployment Lifecycle Manager provides a Kubernetes CRD-based API to manage the lifecycle of operands. nss.operator.ibm.com/managed-operators: ibm-odlm - olm.skipRange: '>=1.2.0 <4.3.5' + olm.skipRange: '>=1.2.0 <4.3.6' operators.openshift.io/infrastructure-features: '["disconnected"]' operators.operatorframework.io/builder: operator-sdk-v1.32.0 operators.operatorframework.io/project_layout: go.kubebuilder.io/v3 @@ -143,7 +143,7 @@ metadata: operatorframework.io/arch.ppc64le: supported operatorframework.io/arch.s390x: supported operatorframework.io/os.linux: supported - name: operand-deployment-lifecycle-manager.v4.3.5 + name: operand-deployment-lifecycle-manager.v4.3.6 namespace: placeholder spec: apiservicedefinitions: {} @@ -862,7 +862,7 @@ spec: minKubeVersion: 1.19.0 provider: name: IBM - version: 4.3.5 + version: 4.3.6 relatedImages: - - image: icr.io/cpopen/odlm:4.3.5 + - image: icr.io/cpopen/odlm:4.3.6 name: ODLM_IMAGE diff --git a/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml b/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml index 4c3d0a63..e797eb9f 100644 --- a/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml +++ b/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml @@ -11,7 +11,7 @@ metadata: description: The Operand Deployment Lifecycle Manager provides a Kubernetes CRD-based API to manage the lifecycle of operands. nss.operator.ibm.com/managed-operators: ibm-odlm - olm.skipRange: '>=1.2.0 <4.3.5' + olm.skipRange: '>=1.2.0 <4.3.6' operators.openshift.io/infrastructure-features: '["disconnected"]' operators.operatorframework.io/builder: operator-sdk-v1.2.0 operators.operatorframework.io/project_layout: go.kubebuilder.io/v2 @@ -482,6 +482,6 @@ spec: provider: name: IBM relatedImages: - - image: icr.io/cpopen/odlm:4.3.5 + - image: icr.io/cpopen/odlm:4.3.6 name: ODLM_IMAGE version: 0.0.0 diff --git a/version/version.go b/version/version.go index 60309e1a..95dd04cb 100644 --- a/version/version.go +++ b/version/version.go @@ -17,5 +17,5 @@ package version var ( - Version = "4.3.5" + Version = "4.3.6" ) From 2c3e50f13c82f681a573acffb39355e1e881ffcd Mon Sep 17 00:00:00 2001 From: Travis CI User Date: Wed, 18 Sep 2024 13:44:07 +0000 Subject: [PATCH 138/179] Trigger build with new base image --- base_images.json | 46 +++++----------------------------------------- 1 file changed, 5 insertions(+), 41 deletions(-) diff --git a/base_images.json b/base_images.json index 579a5a04..3285d1e9 100644 --- a/base_images.json +++ b/base_images.json @@ -1,26 +1,4 @@ [ - { - "imageType": "external", - "sourceRepo": "registry.access.redhat.com", - "sourceNamespace": "ubi8", - "sourceImage": "ubi", - "destStage": "edge", - "destNamespace": "build-images", - "destImage": "ubi8", - "tag": "8.10-1054", - "updatePackages": [] - }, - { - "imageType": "external", - "sourceRepo": "registry.access.redhat.com", - "sourceNamespace": "ubi8", - "sourceImage": "ubi-minimal", - "destStage": "edge", - "destNamespace": "build-images", - "destImage": "ubi8-minimal", - "tag": "8.10-1052", - "updatePackages": [] - }, { "imageType": "external", "sourceRepo": "registry.access.redhat.com", @@ -29,7 +7,7 @@ "destStage": "edge", "destNamespace": "build-images", "destImage": "ubi9-micro", - "tag": "9.4-13", + "tag": "9.4-15", "updatePackages": [] }, { @@ -40,7 +18,7 @@ "destStage": "edge", "destNamespace": "build-images", "destImage": "ubi9", - "tag": "9.4-1181", + "tag": "9.4-1214.1725849297", "updatePackages": [] }, { @@ -51,34 +29,20 @@ "destStage": "edge", "destNamespace": "build-images", "destImage": "ubi9-minimal", - "tag": "9.4-1194", + "tag": "9.4-1227.1725849298", "updatePackages": [] }, - { - "imageType": "node", - "sourceImage": "ubi8-minimal", - "sourceTag": "8.10-1052", - "destImage": "node-v18-ubi8-minimal", - "nodeVersion": "18.20.4" - }, - { - "imageType": "node", - "sourceImage": "ubi8-minimal", - "sourceTag": "8.10-1052", - "destImage": "node-v20-ubi8-minimal", - "nodeVersion": "20.17.0" - }, { "imageType": "node", "sourceImage": "ubi9-minimal", - "sourceTag": "9.4-1194", + "sourceTag": "9.4-1227.1725849298", "destImage": "node-v18-ubi9-minimal", "nodeVersion": "18.20.4" }, { "imageType": "node", "sourceImage": "ubi9-minimal", - "sourceTag": "9.4-1194", + "sourceTag": "9.4-1227.1725849298", "destImage": "node-v20-ubi9-minimal", "nodeVersion": "20.17.0" } From f71913eb136bbff504b38cd923b1356408dc359f Mon Sep 17 00:00:00 2001 From: Daniel Fan Date: Wed, 18 Sep 2024 10:10:18 -0400 Subject: [PATCH 139/179] Add packagemanifest CRD in test ENV (#1080) * Add packagemanifest CRD in test ENV Signed-off-by: Daniel Fan * update test cases Signed-off-by: Daniel Fan --------- Signed-off-by: Daniel Fan --- common/Makefile.common.mk | 3 + .../operandrequest_controller.go | 5 +- .../operandrequest/reconcile_operator.go | 2 +- .../operandrequest/reconcile_operator_test.go | 39 +++++ controllers/operator/manager.go | 2 +- .../testutil/packagemanifests_crd.yaml | 164 ++++++++++++++++++ 6 files changed, 212 insertions(+), 3 deletions(-) create mode 100644 controllers/testutil/packagemanifests_crd.yaml diff --git a/common/Makefile.common.mk b/common/Makefile.common.mk index fcc2796f..cea96080 100644 --- a/common/Makefile.common.mk +++ b/common/Makefile.common.mk @@ -82,6 +82,9 @@ fetch-test-crds: tar -zxf v${NAMESPACESCOPE_VERSION}.tar.gz ibm-namespace-scope-operator-${NAMESPACESCOPE_VERSION}/bundle/manifests && mv ibm-namespace-scope-operator-${NAMESPACESCOPE_VERSION}/bundle/manifests/operator.ibm.com_namespacescopes.yaml ${ENVCRDS_DIR}/operator.ibm.com_namespacescopes.yaml ;\ rm -rf ibm-namespace-scope-operator-${NAMESPACESCOPE_VERSION} v${NAMESPACESCOPE_VERSION}.tar.gz ;\ } + @{ \ + cp ./controllers/testutil/packagemanifests_crd.yaml ${ENVCRDS_DIR}/packagemanifests_crd.yaml ;\ + } CONTROLLER_GEN ?= $(shell pwd)/common/bin/controller-gen diff --git a/controllers/operandrequest/operandrequest_controller.go b/controllers/operandrequest/operandrequest_controller.go index 0f82ae56..29479fc5 100644 --- a/controllers/operandrequest/operandrequest_controller.go +++ b/controllers/operandrequest/operandrequest_controller.go @@ -103,6 +103,9 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctrl.Re if err := r.Client.Status().Patch(ctx, requestInstance, client.MergeFrom(existingInstance)); err != nil && !apierrors.IsNotFound(err) { reconcileErr = utilerrors.NewAggregate([]error{reconcileErr, fmt.Errorf("error while patching OperandRequest.Status: %v", err)}) } + if reconcileErr != nil { + klog.Errorf("failed to patch status for OperandRequest %s: %v", req.NamespacedName.String(), reconcileErr) + } }() // Remove finalizer when DeletionTimestamp none zero @@ -180,7 +183,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctrl.Re } klog.V(1).Infof("Finished reconciling OperandRequest: %s", req.NamespacedName) - return ctrl.Result{RequeueAfter: constant.DefaultSyncPeriod}, nil + return ctrl.Result{RequeueAfter: constant.DefaultSyncPeriod}, reconcileErr } func (r *Reconciler) checkPermission(ctx context.Context, req ctrl.Request) bool { diff --git a/controllers/operandrequest/reconcile_operator.go b/controllers/operandrequest/reconcile_operator.go index 459edf8c..d53c3368 100644 --- a/controllers/operandrequest/reconcile_operator.go +++ b/controllers/operandrequest/reconcile_operator.go @@ -763,7 +763,7 @@ func checkSubAnnotationsForUninstall(reqName, reqNs, opName, installMode string, uninstallOperator = false } - if _, ok := sub.Labels[constant.OpreqLabel]; !ok { + if value, ok := sub.Labels[constant.OpreqLabel]; !ok || value != "true" { uninstallOperator = false } diff --git a/controllers/operandrequest/reconcile_operator_test.go b/controllers/operandrequest/reconcile_operator_test.go index 35ef023e..3232d703 100644 --- a/controllers/operandrequest/reconcile_operator_test.go +++ b/controllers/operandrequest/reconcile_operator_test.go @@ -174,6 +174,9 @@ func TestCheckSubAnnotationsForUninstall(t *testing.T) { reqNsNew + "." + reqNameB + "." + opNameV4 + "/request": opChannelV4, reqNsNew + "." + reqNameB + "." + opNameV4 + "/operatorNamespace": reqNsNew, }, + Labels: map[string]string{ + constant.OpreqLabel: "true", + }, }, } @@ -198,6 +201,9 @@ func TestCheckSubAnnotationsForUninstall(t *testing.T) { reqNsNew + "." + reqNameB + "." + opNameV4 + "/request": opChannelV4, reqNsNew + "." + reqNameB + "." + opNameV4 + "/operatorNamespace": reqNsNew, }, + Labels: map[string]string{ + constant.OpreqLabel: "true", + }, }, } @@ -224,6 +230,9 @@ func TestCheckSubAnnotationsForUninstall(t *testing.T) { reqNsOld + "." + reqNameD + "." + opNameD + "/request": opChannelD, reqNsOld + "." + reqNameD + "." + opNameD + "/operatorNamespace": reqNsOld, }, + Labels: map[string]string{ + constant.OpreqLabel: "true", + }, }, } @@ -250,6 +259,9 @@ func TestCheckSubAnnotationsForUninstall(t *testing.T) { reqNsOld + "." + reqNameB + "." + opNameV4 + "/request": opChannelV4, reqNsOld + "." + reqNameB + "." + opNameV4 + "/operatorNamespace": reqNsOld, }, + Labels: map[string]string{ + constant.OpreqLabel: "true", + }, }, } @@ -275,6 +287,9 @@ func TestCheckSubAnnotationsForUninstall(t *testing.T) { reqNsNew + "." + reqNameB + "." + opNameV4 + "/request": opChannelV4, reqNsNew + "." + reqNameB + "." + opNameV4 + "/operatorNamespace": reqNsNew, }, + Labels: map[string]string{ + constant.OpreqLabel: "true", + }, }, } @@ -287,4 +302,28 @@ func TestCheckSubAnnotationsForUninstall(t *testing.T) { assert.NotContains(t, sub.Annotations, reqNsNew+"."+reqNameA+"."+opNameV4+"/operatorNamespace") assert.Contains(t, sub.Annotations, reqNsNew+"."+reqNameB+"."+opNameV4+"/request") assert.Contains(t, sub.Annotations, reqNsNew+"."+reqNameB+"."+opNameV4+"/operatorNamespace") + + // Test case 8: uninstallOperator is false, uninstallOperand is true for operator with general installMode + // The operator should be NOT uninstalled because operator is not been managed by ODLM. + // The operand should be uninstalled because no other OperandRequest is requesting the same operand. + sub = &olmv1alpha1.Subscription{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: reqNsOld, + Annotations: map[string]string{ + reqNsOld + "." + reqNameA + "." + opNameV4 + "/request": opChannelV4, + reqNsOld + "." + reqNameA + "." + opNameV4 + "/operatorNamespace": reqNsOld, + }, + Labels: map[string]string{ + constant.OpreqLabel: "false", + }, + }, + } + + uninstallOperator, uninstallOperand = checkSubAnnotationsForUninstall(reqNameA, reqNsOld, opNameV4, operatorv1alpha1.InstallModeNamespace, sub) + + assert.False(t, uninstallOperator) + assert.True(t, uninstallOperand) + + assert.NotContains(t, sub.Annotations, reqNsOld+"."+reqNameA+"."+opNameV4+"/request") + assert.NotContains(t, sub.Annotations, reqNsOld+"."+reqNameA+"."+opNameV4+"/operatorNamespace") } diff --git a/controllers/operator/manager.go b/controllers/operator/manager.go index 7c0cab6b..6cb646fd 100644 --- a/controllers/operator/manager.go +++ b/controllers/operator/manager.go @@ -154,7 +154,7 @@ func (m *ODLMOperator) GetCatalogSourceAndChannelFromPackage(ctx context.Context switch number { case 0: klog.V(2).Infof("Not found PackageManifest %s in the namespace %s has channel %s", packageName, namespace, channel) - return "", "", "", nil + return opregCatalog, opregCatalogNs, channel, nil default: // Check if the CatalogSource and CatalogSource namespace are specified in OperandRegistry if opregCatalog != "" && opregCatalogNs != "" { diff --git a/controllers/testutil/packagemanifests_crd.yaml b/controllers/testutil/packagemanifests_crd.yaml new file mode 100644 index 00000000..4931e9b1 --- /dev/null +++ b/controllers/testutil/packagemanifests_crd.yaml @@ -0,0 +1,164 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: packagemanifests.packages.operators.coreos.com +spec: + group: packages.operators.coreos.com + versions: + - name: v1 + served: true + storage: true + schema: + openAPIV3Schema: + type: object + properties: + spec: + type: object + status: + type: object + properties: + catalogSource: + type: string + catalogSourceDisplayName: + type: string + catalogSourcePublisher: + type: string + catalogSourceNamespace: + type: string + provider: + type: object + properties: + name: + type: string + url: + type: string + packageName: + type: string + deprecation: + type: object + properties: + message: + type: string + channels: + type: array + items: + type: object + properties: + name: + type: string + currentCSV: + type: string + currentCSVDesc: + type: object + properties: + displayName: + type: string + icon: + type: array + items: + type: object + properties: + base64data: + type: string + mediatype: + type: string + version: + type: object + properties: + version: + type: string + provider: + type: object + properties: + name: + type: string + url: + type: string + annotations: + type: object + additionalProperties: + type: string + keywords: + type: array + items: + type: string + links: + type: array + items: + type: object + properties: + name: + type: string + url: + type: string + maintainers: + type: array + items: + type: object + properties: + name: + type: string + email: + type: string + maturity: + type: string + longDescription: + type: string + installModes: + type: array + items: + type: object + properties: + type: + type: string + supported: + type: boolean + customResourceDefinitions: + type: object + apiServiceDefinitions: + type: object + nativeAPIs: + type: array + items: + type: object + properties: + group: + type: string + version: + type: string + kind: + type: string + minKubeVersion: + type: string + relatedImages: + type: array + items: + type: string + deprecation: + type: object + properties: + message: + type: string + entries: + type: array + items: + type: object + properties: + name: + type: string + version: + type: string + deprecation: + type: object + properties: + message: + type: string + defaultChannel: + type: string + names: + plural: packagemanifests + singular: packagemanifest + kind: PackageManifest + shortNames: + - pm + scope: Namespaced \ No newline at end of file From dfc27df84ddbbd64f996b92f843edafcb7b42a68 Mon Sep 17 00:00:00 2001 From: Travis CI User Date: Wed, 25 Sep 2024 14:49:11 +0000 Subject: [PATCH 140/179] Trigger build with new base image --- base_images.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/base_images.json b/base_images.json index 3285d1e9..fba9a7de 100644 --- a/base_images.json +++ b/base_images.json @@ -18,7 +18,7 @@ "destStage": "edge", "destNamespace": "build-images", "destImage": "ubi9", - "tag": "9.4-1214.1725849297", + "tag": "9.4-1214.1726694543", "updatePackages": [] }, { @@ -29,20 +29,20 @@ "destStage": "edge", "destNamespace": "build-images", "destImage": "ubi9-minimal", - "tag": "9.4-1227.1725849298", + "tag": "9.4-1227.1726694542", "updatePackages": [] }, { "imageType": "node", "sourceImage": "ubi9-minimal", - "sourceTag": "9.4-1227.1725849298", + "sourceTag": "9.4-1227.1726694542", "destImage": "node-v18-ubi9-minimal", "nodeVersion": "18.20.4" }, { "imageType": "node", "sourceImage": "ubi9-minimal", - "sourceTag": "9.4-1227.1725849298", + "sourceTag": "9.4-1227.1726694542", "destImage": "node-v20-ubi9-minimal", "nodeVersion": "20.17.0" } From f6260a69dea8310dda6b862b302f49564a3e84bb Mon Sep 17 00:00:00 2001 From: YuChen Shen <59578388+YCShen1010@users.noreply.github.com> Date: Wed, 25 Sep 2024 17:10:25 -0400 Subject: [PATCH 141/179] Revert the host back to default value (#1083) * revert host back to default in route Signed-off-by: YuChen * fix go format Signed-off-by: YuChen --------- Signed-off-by: YuChen --- .../operandrequest/reconcile_operand.go | 198 ++++++++++++++---- controllers/util/util.go | 10 + 2 files changed, 164 insertions(+), 44 deletions(-) diff --git a/controllers/operandrequest/reconcile_operand.go b/controllers/operandrequest/reconcile_operand.go index 693711bf..1d173534 100644 --- a/controllers/operandrequest/reconcile_operand.go +++ b/controllers/operandrequest/reconcile_operand.go @@ -1010,10 +1010,22 @@ func (r *Reconciler) createK8sResource(ctx context.Context, k8sResTemplate unstr if k8sResConfigUnmarshalErr != nil { klog.Errorf("failed to unmarshal k8s Resource Config: %v", k8sResConfigUnmarshalErr) } - for k, v := range k8sResConfigDecoded { k8sResTemplate.Object[k] = v } + + if kind == "Route" { + if host, found := k8sResConfigDecoded["spec"].(map[string]interface{})["host"].(string); found { + hostHash := util.CalculateHash(host) + + if newAnnotations == nil { + newAnnotations = make(map[string]string) + } + newAnnotations["operator.ibm.com/odlm.route.hashedData"] = hostHash + } else { + klog.Warningf("spec.host not found in Route %s/%s", namespace, name) + } + } } r.EnsureLabel(k8sResTemplate, map[string]string{constant.OpreqLabel: "true"}) @@ -1039,59 +1051,36 @@ func (r *Reconciler) updateK8sResource(ctx context.Context, existingK8sRes unstr apiversion := existingK8sRes.GetAPIVersion() name := existingK8sRes.GetName() namespace := existingK8sRes.GetNamespace() - if kind == "Job" { - existingK8sRes := unstructured.Unstructured{ - Object: map[string]interface{}{ - "apiVersion": apiversion, - "kind": kind, - }, - } - err := r.Client.Get(ctx, types.NamespacedName{ - Name: name, - Namespace: namespace, - }, &existingK8sRes) - - if err != nil { - return errors.Wrapf(err, "failed to get k8s resource -- Kind: %s, NamespacedName: %s/%s", kind, namespace, name) - } - if !r.CheckLabel(existingK8sRes, map[string]string{constant.OpreqLabel: "true"}) && (newLabels == nil || newLabels[constant.OpreqLabel] != "true") { - return nil + if kind == "Job" { + if err := r.updateK8sJob(ctx, existingK8sRes, k8sResConfig, newLabels, newAnnotations, ownerReferences); err != nil { + return errors.Wrap(err, "failed to update Job") } + return nil + } - var existingHashedData string - var newHashedData string - if existingK8sRes.GetAnnotations() != nil { - existingHashedData = existingK8sRes.GetAnnotations()[constant.HashedData] + if kind == "Route" { + if err := r.updateK8sRoute(ctx, existingK8sRes, k8sResConfig, newLabels, newAnnotations, ownerReferences); err != nil { + return errors.Wrap(err, "failed to update Route") } if k8sResConfig != nil { - hashedData := sha256.Sum256(k8sResConfig.Raw) - newHashedData = hex.EncodeToString(hashedData[:7]) - } - - if existingHashedData != newHashedData { - // create a new template of k8s resource - var templatek8sRes unstructured.Unstructured - templatek8sRes.SetAPIVersion(apiversion) - templatek8sRes.SetKind(kind) - templatek8sRes.SetName(name) - templatek8sRes.SetNamespace(namespace) - - if newAnnotations == nil { - newAnnotations = make(map[string]string) + k8sResConfigDecoded := make(map[string]interface{}) + if k8sResConfigUnmarshalErr := json.Unmarshal(k8sResConfig.Raw, &k8sResConfigDecoded); k8sResConfigUnmarshalErr != nil { + return errors.Wrap(k8sResConfigUnmarshalErr, "failed to unmarshal k8s Resource Config") } - newAnnotations[constant.HashedData] = newHashedData - if err := r.deleteK8sResource(ctx, existingK8sRes, namespace); err != nil { - return errors.Wrap(err, "failed to update k8s resource") - } - if err := r.createK8sResource(ctx, templatek8sRes, k8sResConfig, newLabels, newAnnotations, ownerReferences); err != nil { - return errors.Wrap(err, "failed to update k8s resource") + if host, found := k8sResConfigDecoded["spec"].(map[string]interface{})["host"].(string); found { + hostHash := util.CalculateHash(host) + + if newAnnotations == nil { + newAnnotations = make(map[string]string) + } + newAnnotations["operator.ibm.com/odlm.route.hashedData"] = hostHash + } else { + klog.Warningf("spec.host not found in Route %s/%s", namespace, name) } } - - return nil } // Update the k8s res @@ -1178,6 +1167,127 @@ func (r *Reconciler) updateK8sResource(ctx context.Context, existingK8sRes unstr return nil } +func (r *Reconciler) updateK8sJob(ctx context.Context, existingK8sRes unstructured.Unstructured, k8sResConfig *runtime.RawExtension, newLabels, newAnnotations map[string]string, ownerReferences *[]operatorv1alpha1.OwnerReference) error { + + kind := existingK8sRes.GetKind() + apiversion := existingK8sRes.GetAPIVersion() + name := existingK8sRes.GetName() + namespace := existingK8sRes.GetNamespace() + + existingRes := unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": apiversion, + "kind": kind, + }, + } + + err := r.Client.Get(ctx, types.NamespacedName{ + Name: name, + Namespace: namespace, + }, &existingRes) + + if err != nil { + return errors.Wrapf(err, "failed to get k8s resource -- Kind: %s, NamespacedName: %s/%s", kind, namespace, name) + } + if !r.CheckLabel(existingRes, map[string]string{constant.OpreqLabel: "true"}) && (newLabels == nil || newLabels[constant.OpreqLabel] != "true") { + return nil + } + + var existingHashedData string + var newHashedData string + if existingRes.GetAnnotations() != nil { + existingHashedData = existingRes.GetAnnotations()[constant.HashedData] + } + + if k8sResConfig != nil { + hashedData := sha256.Sum256(k8sResConfig.Raw) + newHashedData = hex.EncodeToString(hashedData[:7]) + } + + if existingHashedData != newHashedData { + // create a new template of k8s resource + var templatek8sRes unstructured.Unstructured + templatek8sRes.SetAPIVersion(apiversion) + templatek8sRes.SetKind(kind) + templatek8sRes.SetName(name) + templatek8sRes.SetNamespace(namespace) + + if newAnnotations == nil { + newAnnotations = make(map[string]string) + } + newAnnotations[constant.HashedData] = newHashedData + + if err := r.deleteK8sResource(ctx, existingRes, namespace); err != nil { + return errors.Wrap(err, "failed to update k8s resource") + } + if err := r.createK8sResource(ctx, templatek8sRes, k8sResConfig, newLabels, newAnnotations, ownerReferences); err != nil { + return errors.Wrap(err, "failed to update k8s resource") + } + } + return nil +} + +// update route resource +func (r *Reconciler) updateK8sRoute(ctx context.Context, existingK8sRes unstructured.Unstructured, k8sResConfig *runtime.RawExtension, newLabels, newAnnotations map[string]string, ownerReferences *[]operatorv1alpha1.OwnerReference) error { + kind := existingK8sRes.GetKind() + apiversion := existingK8sRes.GetAPIVersion() + name := existingK8sRes.GetName() + namespace := existingK8sRes.GetNamespace() + + existingRes := unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": apiversion, + "kind": kind, + }, + } + err := r.Client.Get(ctx, types.NamespacedName{ + Name: name, + Namespace: namespace, + }, &existingRes) + + if err != nil { + return errors.Wrapf(err, "failed to get k8s resource -- Kind: %s, NamespacedName: %s/%s", kind, namespace, name) + } + if !r.CheckLabel(existingRes, map[string]string{constant.OpreqLabel: "true"}) && (newLabels == nil || newLabels[constant.OpreqLabel] != "true") { + return nil + } + + existingAnnos := existingRes.GetAnnotations() + existingHostHash := existingAnnos["operator.ibm.com/odlm.route.hashedData"] + + if k8sResConfig != nil { + k8sResConfigDecoded := make(map[string]interface{}) + k8sResConfigUnmarshalErr := json.Unmarshal(k8sResConfig.Raw, &k8sResConfigDecoded) + if k8sResConfigUnmarshalErr != nil { + klog.Errorf("failed to unmarshal k8s Resource Config: %v", k8sResConfigUnmarshalErr) + } + + // Read the host from the OperandConfig + if newHost, found := k8sResConfigDecoded["spec"].(map[string]interface{})["host"].(string); found { + newHostHash := util.CalculateHash(newHost) + + // Only re-create the route if the custom host has been removed + if newHost == "" && existingHostHash != newHostHash { + + // create a new template of k8s resource + var templatek8sRes unstructured.Unstructured + templatek8sRes.SetAPIVersion(apiversion) + templatek8sRes.SetKind(kind) + templatek8sRes.SetName(name) + templatek8sRes.SetNamespace(namespace) + + if err := r.deleteK8sResource(ctx, existingRes, namespace); err != nil { + return errors.Wrap(err, "failed to delete Route for recreation") + } + if err := r.createK8sResource(ctx, templatek8sRes, k8sResConfig, newLabels, newAnnotations, ownerReferences); err != nil { + return errors.Wrap(err, "failed to update k8s resource") + } + } + } + } + return nil +} + func (r *Reconciler) deleteK8sResource(ctx context.Context, existingK8sRes unstructured.Unstructured, namespace string) error { kind := existingK8sRes.GetKind() diff --git a/controllers/util/util.go b/controllers/util/util.go index 3b009176..7247a41e 100644 --- a/controllers/util/util.go +++ b/controllers/util/util.go @@ -18,6 +18,8 @@ package util import ( "bytes" + "crypto/sha256" + "encoding/hex" "fmt" "os" "regexp" @@ -152,6 +154,14 @@ func StringSliceContentEqual(a, b []string) bool { return true } +func CalculateHash(input string) string { + if input == "" { + return "" + } + hashedData := sha256.Sum256([]byte(input)) + return hex.EncodeToString(hashedData[:7]) +} + // WaitTimeout waits for the waitgroup for the specified max timeout. // Returns true if waiting timed out. func WaitTimeout(wg *sync.WaitGroup, timeout time.Duration) bool { From 6baae188d1a4f2a506f28da885c359d01a5a905c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 26 Sep 2024 05:28:25 +0800 Subject: [PATCH 142/179] build(deps): bump golang from 1.23.0-bullseye to 1.23.1-bullseye (#1081) Bumps golang from 1.23.0-bullseye to 1.23.1-bullseye. --- updated-dependencies: - dependency-name: golang dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index a4775ec0..56c9002d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # Build the manager binary -FROM docker.io/golang:1.23.0-bullseye as builder +FROM docker.io/golang:1.23.1-bullseye as builder ARG GOARCH WORKDIR /workspace From 2d8d9d3f15171eabcde07d0d46cfc217ca8f6bbd Mon Sep 17 00:00:00 2001 From: YuChen Shen <59578388+YCShen1010@users.noreply.github.com> Date: Wed, 25 Sep 2024 23:20:25 -0400 Subject: [PATCH 143/179] Use PackageName name as the name of subscription (#1084) * use pkg name as the name of subscription Signed-off-by: YuChen * fix for test error Signed-off-by: YuChen --------- Signed-off-by: YuChen --- controllers/operandrequest/operandrequest_controller.go | 3 +++ controllers/operandrequest/reconcile_operator.go | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/controllers/operandrequest/operandrequest_controller.go b/controllers/operandrequest/operandrequest_controller.go index 29479fc5..e7429d38 100644 --- a/controllers/operandrequest/operandrequest_controller.go +++ b/controllers/operandrequest/operandrequest_controller.go @@ -100,6 +100,9 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctrl.Re if reflect.DeepEqual(existingInstance.Status, requestInstance.Status) { return } + + // Update requestInstance's resource version to avoid conflicts + requestInstance.ResourceVersion = existingInstance.ResourceVersion if err := r.Client.Status().Patch(ctx, requestInstance, client.MergeFrom(existingInstance)); err != nil && !apierrors.IsNotFound(err) { reconcileErr = utilerrors.NewAggregate([]error{reconcileErr, fmt.Errorf("error while patching OperandRequest.Status: %v", err)}) } diff --git a/controllers/operandrequest/reconcile_operator.go b/controllers/operandrequest/reconcile_operator.go index d53c3368..8955ef75 100644 --- a/controllers/operandrequest/reconcile_operator.go +++ b/controllers/operandrequest/reconcile_operator.go @@ -667,7 +667,7 @@ func (r *Reconciler) generateClusterObjects(o *operatorv1alpha1.Operator, regist // Subscription Object sub := &olmv1alpha1.Subscription{ ObjectMeta: metav1.ObjectMeta{ - Name: o.Name, + Name: o.PackageName, Namespace: namespace, Labels: labels, Annotations: annotations, @@ -683,7 +683,7 @@ func (r *Reconciler) generateClusterObjects(o *operatorv1alpha1.Operator, regist }, } sub.SetGroupVersionKind(schema.GroupVersionKind{Group: olmv1alpha1.SchemeGroupVersion.Group, Kind: "Subscription", Version: olmv1alpha1.SchemeGroupVersion.Version}) - klog.V(3).Info("Generating Subscription: ", o.Name, " in the Namespace: ", namespace) + klog.V(3).Info("Generating Subscription: ", o.PackageName, " in the Namespace: ", namespace) co.subscription = sub return co } From f611358e06c29a23cf570927a518ac5a821a1930 Mon Sep 17 00:00:00 2001 From: YuChen Shen <59578388+YCShen1010@users.noreply.github.com> Date: Sun, 29 Sep 2024 23:30:29 -0400 Subject: [PATCH 144/179] Enhance ODLM create/update logic by adding hash values (#1086) * hash comparison and deep merge all the resources Signed-off-by: YuChen * update hash number Signed-off-by: YuChen --------- Signed-off-by: YuChen --- controllers/constant/constant.go | 6 ++ .../operandrequest/reconcile_operand.go | 80 +++++++++++++------ controllers/util/merge.go | 4 + controllers/util/util.go | 33 +++++++- 4 files changed, 95 insertions(+), 28 deletions(-) diff --git a/controllers/constant/constant.go b/controllers/constant/constant.go index d9bdaa8e..25eca64b 100644 --- a/controllers/constant/constant.go +++ b/controllers/constant/constant.go @@ -64,6 +64,12 @@ const ( //HashedData is the key for checking the checksum of data section HashedData string = "hashedData" + //HashedData is the key for k8s Resource + K8sHashedData string = "operator.ibm.com/operand-depoyment-lifecycle-manager.hashedData" + + //RouteHash is the key for hash value of route + RouteHash string = "operator.ibm.com/odlm.route.hashedData" + //DefaultRequestTimeout is the default timeout for kube request DefaultRequestTimeout = 5 * time.Second diff --git a/controllers/operandrequest/reconcile_operand.go b/controllers/operandrequest/reconcile_operand.go index 1d173534..04964fbc 100644 --- a/controllers/operandrequest/reconcile_operand.go +++ b/controllers/operandrequest/reconcile_operand.go @@ -1014,14 +1014,26 @@ func (r *Reconciler) createK8sResource(ctx context.Context, k8sResTemplate unstr k8sResTemplate.Object[k] = v } + k8sResConfigBytes, err := json.Marshal(k8sResConfigDecoded) + if err != nil { + return errors.Wrap(err, "failed to marshal k8sResConfigDecoded") + } + + // Caculate the hash number of the new created template + _, templateHash := util.CalculateResHashes(nil, k8sResConfigBytes) + + newAnnotations = util.AddHashAnnotation(&k8sResTemplate, constant.K8sHashedData, templateHash, newAnnotations) + if kind == "Route" { if host, found := k8sResConfigDecoded["spec"].(map[string]interface{})["host"].(string); found { - hostHash := util.CalculateHash(host) + hostHash := util.CalculateHash([]byte(host)) + + // if newAnnotations == nil { + // newAnnotations = make(map[string]string) + // } + // newAnnotations[constant.RouteHash] = hostHash + newAnnotations = util.AddHashAnnotation(&k8sResTemplate, constant.RouteHash, hostHash, newAnnotations) - if newAnnotations == nil { - newAnnotations = make(map[string]string) - } - newAnnotations["operator.ibm.com/odlm.route.hashedData"] = hostHash } else { klog.Warningf("spec.host not found in Route %s/%s", namespace, name) } @@ -1064,6 +1076,7 @@ func (r *Reconciler) updateK8sResource(ctx context.Context, existingK8sRes unstr return errors.Wrap(err, "failed to update Route") } + // update the annotations of the Route host if the host is changed if k8sResConfig != nil { k8sResConfigDecoded := make(map[string]interface{}) if k8sResConfigUnmarshalErr := json.Unmarshal(k8sResConfig.Raw, &k8sResConfigDecoded); k8sResConfigUnmarshalErr != nil { @@ -1071,22 +1084,22 @@ func (r *Reconciler) updateK8sResource(ctx context.Context, existingK8sRes unstr } if host, found := k8sResConfigDecoded["spec"].(map[string]interface{})["host"].(string); found { - hostHash := util.CalculateHash(host) + hostHash := util.CalculateHash([]byte(host)) if newAnnotations == nil { newAnnotations = make(map[string]string) } - newAnnotations["operator.ibm.com/odlm.route.hashedData"] = hostHash + newAnnotations[constant.RouteHash] = hostHash } else { klog.Warningf("spec.host not found in Route %s/%s", namespace, name) } } } - // Update the k8s res + // Update the k8s resource err := wait.PollImmediate(constant.DefaultCRFetchPeriod, constant.DefaultCRFetchTimeout, func() (bool, error) { - existingK8sRes := unstructured.Unstructured{ + existingRes := unstructured.Unstructured{ Object: map[string]interface{}{ "apiVersion": apiversion, "kind": kind, @@ -1096,40 +1109,56 @@ func (r *Reconciler) updateK8sResource(ctx context.Context, existingK8sRes unstr err := r.Client.Get(ctx, types.NamespacedName{ Name: name, Namespace: namespace, - }, &existingK8sRes) - + }, &existingRes) if err != nil { return false, errors.Wrapf(err, "failed to get k8s resource -- Kind: %s, NamespacedName: %s/%s", kind, namespace, name) } + resourceVersion := existingRes.GetResourceVersion() - if !r.CheckLabel(existingK8sRes, map[string]string{constant.OpreqLabel: "true"}) && (newLabels == nil || newLabels[constant.OpreqLabel] != "true") { + if !r.CheckLabel(existingRes, map[string]string{constant.OpreqLabel: "true"}) && (newLabels == nil || newLabels[constant.OpreqLabel] != "true") { return true, nil } if k8sResConfig != nil { // Convert existing k8s resource to string - existingK8sResRaw, err := json.Marshal(existingK8sRes.Object) + existingResRaw, err := json.Marshal(existingRes.Object) if err != nil { return false, errors.Wrapf(err, "failed to marshal existing k8s resource -- Kind: %s, NamespacedName: %s/%s", kind, namespace, name) } - // Merge the existing CR and the CR from the OperandConfig - updatedExistingK8sRes := util.MergeCR(existingK8sResRaw, k8sResConfig.Raw) - // Update the existing k8s resource with the merged CR - existingK8sRes.Object = updatedExistingK8sRes + // Caculate the hash number of the new created template + existingHash, templateHash := util.CalculateResHashes(&existingRes, k8sResConfig.Raw) - r.EnsureAnnotation(existingK8sRes, newAnnotations) - r.EnsureLabel(existingK8sRes, newLabels) - if err := r.setOwnerReferences(ctx, &existingK8sRes, ownerReferences); err != nil { + // If the hash number of the existing k8s resource is different from the hash number of template, update the k8s resource + if existingHash != templateHash { + k8sResConfigDecoded := make(map[string]interface{}) + k8sResConfigUnmarshalErr := json.Unmarshal(k8sResConfig.Raw, &k8sResConfigDecoded) + if k8sResConfigUnmarshalErr != nil { + klog.Errorf("failed to unmarshal k8s Resource Config: %v", k8sResConfigUnmarshalErr) + } + for k, v := range k8sResConfigDecoded { + existingRes.Object[k] = v + } + newAnnotations = util.AddHashAnnotation(&existingRes, constant.K8sHashedData, templateHash, newAnnotations) + + } else { + // If the hash number are the same, then do the deep merge + // Merge the existing CR and the CR from the OperandConfig + updatedExistingRes := util.MergeCR(existingResRaw, k8sResConfig.Raw) + // Update the existing k8s resource with the merged CR + existingRes.Object = updatedExistingRes + } + + r.EnsureAnnotation(existingRes, newAnnotations) + r.EnsureLabel(existingRes, newLabels) + if err := r.setOwnerReferences(ctx, &existingRes, ownerReferences); err != nil { return false, errors.Wrapf(err, "failed to set ownerReferences for k8s resource -- Kind: %s, NamespacedName: %s/%s", kind, namespace, name) } klog.Infof("updating k8s resource with apiversion: %s, kind: %s, %s/%s", apiversion, kind, namespace, name) - resourceVersion := existingK8sRes.GetResourceVersion() - err = r.Update(ctx, &existingK8sRes) - + err = r.Update(ctx, &existingRes) if err != nil { return false, errors.Wrapf(err, "failed to update k8s resource -- Kind: %s, NamespacedName: %s/%s", kind, namespace, name) } @@ -1156,6 +1185,7 @@ func (r *Reconciler) updateK8sResource(ctx context.Context, existingK8sRes unstr } else { klog.Infof("No updates on k8s resource with apiversion: %s, kind: %s, %s/%s", apiversion, kind, namespace, name) } + } return true, nil }) @@ -1253,7 +1283,7 @@ func (r *Reconciler) updateK8sRoute(ctx context.Context, existingK8sRes unstruct } existingAnnos := existingRes.GetAnnotations() - existingHostHash := existingAnnos["operator.ibm.com/odlm.route.hashedData"] + existingHostHash := existingAnnos[constant.RouteHash] if k8sResConfig != nil { k8sResConfigDecoded := make(map[string]interface{}) @@ -1264,7 +1294,7 @@ func (r *Reconciler) updateK8sRoute(ctx context.Context, existingK8sRes unstruct // Read the host from the OperandConfig if newHost, found := k8sResConfigDecoded["spec"].(map[string]interface{})["host"].(string); found { - newHostHash := util.CalculateHash(newHost) + newHostHash := util.CalculateHash([]byte(newHost)) // Only re-create the route if the custom host has been removed if newHost == "" && existingHostHash != newHostHash { diff --git a/controllers/util/merge.go b/controllers/util/merge.go index 8d0743ff..d8dc046e 100644 --- a/controllers/util/merge.go +++ b/controllers/util/merge.go @@ -29,6 +29,7 @@ func MergeCR(defaultCR, changedCR []byte) map[string]interface{} { return make(map[string]interface{}) } + // Handle when only one CR is provided defaultCRDecoded := make(map[string]interface{}) changedCRDecoded := make(map[string]interface{}) if len(defaultCR) != 0 && len(changedCR) == 0 { @@ -52,9 +53,12 @@ func MergeCR(defaultCR, changedCR []byte) map[string]interface{} { if changedCRUnmarshalErr != nil { klog.Errorf("failed to unmarshal service spec: %v", changedCRUnmarshalErr) } + + // Merge both specs for key := range defaultCRDecoded { checkKeyBeforeMerging(key, defaultCRDecoded[key], changedCRDecoded[key], changedCRDecoded) } + return changedCRDecoded } diff --git a/controllers/util/util.go b/controllers/util/util.go index 7247a41e..eaa06478 100644 --- a/controllers/util/util.go +++ b/controllers/util/util.go @@ -37,6 +37,8 @@ import ( "k8s.io/apimachinery/pkg/runtime" "k8s.io/client-go/discovery" "k8s.io/client-go/util/jsonpath" + + constant "github.com/IBM/operand-deployment-lifecycle-manager/v4/controllers/constant" ) type TemplateValueRef struct { @@ -154,14 +156,39 @@ func StringSliceContentEqual(a, b []string) bool { return true } -func CalculateHash(input string) string { - if input == "" { +// CalculateHash calculates the hash value for single resource +func CalculateHash(input []byte) string { + if len(input) == 0 { return "" } - hashedData := sha256.Sum256([]byte(input)) + hashedData := sha256.Sum256(input) return hex.EncodeToString(hashedData[:7]) } +// CalculateResHashes calculates the hash for the existing cluster resource and the new template resource +func CalculateResHashes(fromCluster *unstructured.Unstructured, fromTemplate []byte) (string, string) { + templateHash := CalculateHash(fromTemplate) + + if fromCluster != nil { + clusterAnnos := fromCluster.GetAnnotations() + clusterHash := "" + if clusterAnnos != nil { + clusterHash = clusterAnnos[constant.K8sHashedData] + } + return clusterHash, templateHash + } + return "", templateHash +} + +// SetHashAnnotation sets the hash annotation in the object +func AddHashAnnotation(obj *unstructured.Unstructured, key, hash string, newAnnotations map[string]string) map[string]string { + if newAnnotations == nil { + newAnnotations = make(map[string]string) + } + newAnnotations[key] = hash + return newAnnotations +} + // WaitTimeout waits for the waitgroup for the specified max timeout. // Returns true if waiting timed out. func WaitTimeout(wg *sync.WaitGroup, timeout time.Duration) bool { From c1be25c1ddce5590a933a9a0cda0436e88ebde53 Mon Sep 17 00:00:00 2001 From: Daniel Fan Date: Mon, 30 Sep 2024 00:17:29 -0400 Subject: [PATCH 145/179] Add optionalFields into OperandConfig, to conditionally prune fields based on matchExpressions (#1085) Signed-off-by: Daniel Fan --- api/v1alpha1/operandconfig_types.go | 75 ++++++ ...fecycle-manager.clusterserviceversion.yaml | 8 +- .../operator.ibm.com_operandconfigs.yaml | 100 +++++++ .../operator.ibm.com_operandconfigs.yaml | 100 +++++++ config/rbac/role.yaml | 6 + .../operandrequest_controller.go | 1 + .../operandrequest/reconcile_operand.go | 104 +++++++- .../operandrequest/reconcile_operand_test.go | 169 ++++++++++++ controllers/util/util.go | 89 +++++++ controllers/util/util_test.go | 248 ++++++++++++++++++ 10 files changed, 889 insertions(+), 11 deletions(-) diff --git a/api/v1alpha1/operandconfig_types.go b/api/v1alpha1/operandconfig_types.go index 4b4e643f..755917f0 100644 --- a/api/v1alpha1/operandconfig_types.go +++ b/api/v1alpha1/operandconfig_types.go @@ -79,6 +79,61 @@ type ConfigResource struct { // OwnerReferences is the list of owner references. // +optional OwnerReferences []OwnerReference `json:"ownerReferences,omitempty"` + // OptionalFields is the list of fields that could be updated additionally. + // +optional + OptionalFields []OptionalField `json:"optionalFields,omitempty"` +} + +// +kubebuilder:pruning:PreserveUnknownFields +// OptionalField defines the optional field for the resource. +type OptionalField struct { + // Path is the json path of the field. + Path string `json:"path"` + // Operation is the operation of the field. + Operation Operation `json:"operation"` + // MatchExpressions is the match expression of the field. + // +optional + MatchExpressions []MatchExpression `json:"matchExpressions,omitempty"` + // ValueFrom is the field value from the object + // +optional + ValueFrom *ValueFrom `json:"valueFrom,omitempty"` +} + +// +kubebuilder:pruning:PreserveUnknownFields +// MatchExpression defines the match expression of the field. +type MatchExpression struct { + // Key is the key of the field. + Key string `json:"key"` + // Operator is the operator of the field. + Operator ExpressionOperator `json:"operator"` + // Values is the values of the field. + // +optional + Values []string `json:"values"` + // ObjectRef is the reference of the object. + // +optional + ObjectRef *ObjectRef `json:"objectRef,omitempty"` +} + +// ObjectRef defines the reference of the object. +type ObjectRef struct { + // APIVersion is the version of the object. + APIVersion string `json:"apiVersion"` + // Kind is the kind of the object. + Kind string `json:"kind"` + // Name is the name of the object. + Name string `json:"name"` + // Namespace is the namespace of the object. + // +optional + Namespace string `json:"namespace"` +} + +// ValueFrom defines the field value from the object. +type ValueFrom struct { + // Path is the json path of the field. + Path string `json:"path"` + // ObjectRef is the reference of the object. + // +optional + ObjectRef *ObjectRef `json:"objectRef,omitempty"` } type OwnerReference struct { @@ -161,6 +216,26 @@ const ( ServiceNone ServicePhase = "" ) +// Operation defines the operation of the field. +type Operation string + +// Operation type. +const ( + OperationAdd Operation = "add" + OperationRemove Operation = "remove" +) + +// Operator defines the operator type. +type ExpressionOperator string + +// Operator type. +const ( + OperatorIn ExpressionOperator = "In" + OperatorNotIn ExpressionOperator = "NotIn" + OperatorExists ExpressionOperator = "Exists" + OperatorDoesNotExist ExpressionOperator = "DoesNotExist" +) + // GetService obtains the service definition with the operand name. func (r *OperandConfig) GetService(operandName string) *ConfigService { for _, s := range r.Spec.Services { diff --git a/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml b/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml index 929d2e50..8049aca2 100644 --- a/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml +++ b/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml @@ -129,7 +129,7 @@ metadata: categories: Developer Tools, Monitoring, Logging & Tracing, Security certified: "false" containerImage: icr.io/cpopen/odlm:latest - createdAt: "2024-08-27T18:18:40Z" + createdAt: "2024-09-28T19:55:35Z" description: The Operand Deployment Lifecycle Manager provides a Kubernetes CRD-based API to manage the lifecycle of operands. nss.operator.ibm.com/managed-operators: ibm-odlm olm.skipRange: '>=1.2.0 <4.3.6' @@ -568,6 +568,12 @@ spec: spec: clusterPermissions: - rules: + - apiGroups: + - apiextensions.k8s.io + resources: + - customresourcedefinitions + verbs: + - get - apiGroups: - operator.ibm.com resources: diff --git a/bundle/manifests/operator.ibm.com_operandconfigs.yaml b/bundle/manifests/operator.ibm.com_operandconfigs.yaml index d0950bb8..3df97861 100644 --- a/bundle/manifests/operator.ibm.com_operandconfigs.yaml +++ b/bundle/manifests/operator.ibm.com_operandconfigs.yaml @@ -109,6 +109,106 @@ spec: namespace: description: Namespace is the namespace of the resource. type: string + optionalFields: + description: OptionalFields is the list of fields that + could be updated additionally. + items: + description: OptionalField defines the optional field + for the resource. + properties: + matchExpressions: + description: MatchExpressions is the match expression + of the field. + items: + description: MatchExpression defines the match + expression of the field. + properties: + key: + description: Key is the key of the field. + type: string + objectRef: + description: ObjectRef is the reference of + the object. + properties: + apiVersion: + description: APIVersion is the version + of the object. + type: string + kind: + description: Kind is the kind of the object. + type: string + name: + description: Name is the name of the object. + type: string + namespace: + description: Namespace is the namespace + of the object. + type: string + required: + - apiVersion + - kind + - name + type: object + operator: + description: Operator is the operator of the + field. + type: string + values: + description: Values is the values of the field. + items: + type: string + type: array + required: + - key + - operator + type: object + x-kubernetes-preserve-unknown-fields: true + type: array + operation: + description: Operation is the operation of the field. + type: string + path: + description: Path is the json path of the field. + type: string + valueFrom: + description: ValueFrom is the field value from the + object + properties: + objectRef: + description: ObjectRef is the reference of the + object. + properties: + apiVersion: + description: APIVersion is the version of + the object. + type: string + kind: + description: Kind is the kind of the object. + type: string + name: + description: Name is the name of the object. + type: string + namespace: + description: Namespace is the namespace + of the object. + type: string + required: + - apiVersion + - kind + - name + type: object + path: + description: Path is the json path of the field. + type: string + required: + - path + type: object + required: + - operation + - path + type: object + x-kubernetes-preserve-unknown-fields: true + type: array ownerReferences: description: OwnerReferences is the list of owner references. items: diff --git a/config/crd/bases/operator.ibm.com_operandconfigs.yaml b/config/crd/bases/operator.ibm.com_operandconfigs.yaml index 25503e44..f17f5343 100644 --- a/config/crd/bases/operator.ibm.com_operandconfigs.yaml +++ b/config/crd/bases/operator.ibm.com_operandconfigs.yaml @@ -105,6 +105,106 @@ spec: namespace: description: Namespace is the namespace of the resource. type: string + optionalFields: + description: OptionalFields is the list of fields that + could be updated additionally. + items: + description: OptionalField defines the optional field + for the resource. + properties: + matchExpressions: + description: MatchExpressions is the match expression + of the field. + items: + description: MatchExpression defines the match + expression of the field. + properties: + key: + description: Key is the key of the field. + type: string + objectRef: + description: ObjectRef is the reference of + the object. + properties: + apiVersion: + description: APIVersion is the version + of the object. + type: string + kind: + description: Kind is the kind of the object. + type: string + name: + description: Name is the name of the object. + type: string + namespace: + description: Namespace is the namespace + of the object. + type: string + required: + - apiVersion + - kind + - name + type: object + operator: + description: Operator is the operator of the + field. + type: string + values: + description: Values is the values of the field. + items: + type: string + type: array + required: + - key + - operator + type: object + x-kubernetes-preserve-unknown-fields: true + type: array + operation: + description: Operation is the operation of the field. + type: string + path: + description: Path is the json path of the field. + type: string + valueFrom: + description: ValueFrom is the field value from the + object + properties: + objectRef: + description: ObjectRef is the reference of the + object. + properties: + apiVersion: + description: APIVersion is the version of + the object. + type: string + kind: + description: Kind is the kind of the object. + type: string + name: + description: Name is the name of the object. + type: string + namespace: + description: Namespace is the namespace + of the object. + type: string + required: + - apiVersion + - kind + - name + type: object + path: + description: Path is the json path of the field. + type: string + required: + - path + type: object + required: + - operation + - path + type: object + x-kubernetes-preserve-unknown-fields: true + type: array ownerReferences: description: OwnerReferences is the list of owner references. items: diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml index 080d4471..a3017386 100644 --- a/config/rbac/role.yaml +++ b/config/rbac/role.yaml @@ -4,6 +4,12 @@ kind: ClusterRole metadata: name: operand-deployment-lifecycle-manager rules: +- apiGroups: + - apiextensions.k8s.io + resources: + - customresourcedefinitions + verbs: + - get - apiGroups: - operator.ibm.com resources: diff --git a/controllers/operandrequest/operandrequest_controller.go b/controllers/operandrequest/operandrequest_controller.go index e7429d38..458fd504 100644 --- a/controllers/operandrequest/operandrequest_controller.go +++ b/controllers/operandrequest/operandrequest_controller.go @@ -63,6 +63,7 @@ type clusterObjects struct { //+kubebuilder:rbac:groups=operator.ibm.com,resources=certmanagers;auditloggings,verbs=get;delete //+kubebuilder:rbac:groups=operators.coreos.com,resources=catalogsources,verbs=get +//+kubebuilder:rbac:groups=apiextensions.k8s.io,resources=customresourcedefinitions,verbs=get //+kubebuilder:rbac:groups=*,namespace="placeholder",resources=*,verbs=create;delete;get;list;patch;update;watch //+kubebuilder:rbac:groups=operator.ibm.com,namespace="placeholder",resources=operandrequests;operandrequests/status;operandrequests/finalizers,verbs=get;list;watch;create;update;patch;delete diff --git a/controllers/operandrequest/reconcile_operand.go b/controllers/operandrequest/reconcile_operand.go index 04964fbc..b70dc387 100644 --- a/controllers/operandrequest/reconcile_operand.go +++ b/controllers/operandrequest/reconcile_operand.go @@ -565,14 +565,14 @@ func (r *Reconciler) reconcileK8sResource(ctx context.Context, res operatorv1alp if err != nil && !apierrors.IsNotFound(err) { return errors.Wrapf(err, "failed to get k8s resource %s/%s", k8sResNs, res.Name) } else if apierrors.IsNotFound(err) { - if err := r.createK8sResource(ctx, k8sRes, res.Data, res.Labels, res.Annotations, &res.OwnerReferences); err != nil { + if err := r.createK8sResource(ctx, k8sRes, res.Data, res.Labels, res.Annotations, &res.OwnerReferences, &res.OptionalFields); err != nil { return err } } else { if res.Force { // Update k8s resource klog.V(3).Info("Found existing k8s resource: " + res.Name) - if err := r.updateK8sResource(ctx, k8sRes, res.Data, res.Labels, res.Annotations, &res.OwnerReferences); err != nil { + if err := r.updateK8sResource(ctx, k8sRes, res.Data, res.Labels, res.Annotations, &res.OwnerReferences, &res.OptionalFields); err != nil { return err } } else { @@ -999,7 +999,7 @@ func (r *Reconciler) checkCustomResource(ctx context.Context, requestInstance *o return nil } -func (r *Reconciler) createK8sResource(ctx context.Context, k8sResTemplate unstructured.Unstructured, k8sResConfig *runtime.RawExtension, newLabels, newAnnotations map[string]string, ownerReferences *[]operatorv1alpha1.OwnerReference) error { +func (r *Reconciler) createK8sResource(ctx context.Context, k8sResTemplate unstructured.Unstructured, k8sResConfig *runtime.RawExtension, newLabels, newAnnotations map[string]string, ownerReferences *[]operatorv1alpha1.OwnerReference, optionalFields *[]operatorv1alpha1.OptionalField) error { kind := k8sResTemplate.GetKind() name := k8sResTemplate.GetName() namespace := k8sResTemplate.GetNamespace() @@ -1040,6 +1040,9 @@ func (r *Reconciler) createK8sResource(ctx context.Context, k8sResTemplate unstr } } + if err := r.ExecuteOptionalFields(ctx, &k8sResTemplate, optionalFields); err != nil { + return errors.Wrap(err, "failed to execute optional fields") + } r.EnsureLabel(k8sResTemplate, map[string]string{constant.OpreqLabel: "true"}) r.EnsureLabel(k8sResTemplate, newLabels) r.EnsureAnnotation(k8sResTemplate, newAnnotations) @@ -1058,21 +1061,21 @@ func (r *Reconciler) createK8sResource(ctx context.Context, k8sResTemplate unstr return nil } -func (r *Reconciler) updateK8sResource(ctx context.Context, existingK8sRes unstructured.Unstructured, k8sResConfig *runtime.RawExtension, newLabels, newAnnotations map[string]string, ownerReferences *[]operatorv1alpha1.OwnerReference) error { +func (r *Reconciler) updateK8sResource(ctx context.Context, existingK8sRes unstructured.Unstructured, k8sResConfig *runtime.RawExtension, newLabels, newAnnotations map[string]string, ownerReferences *[]operatorv1alpha1.OwnerReference, optionalFields *[]operatorv1alpha1.OptionalField) error { kind := existingK8sRes.GetKind() apiversion := existingK8sRes.GetAPIVersion() name := existingK8sRes.GetName() namespace := existingK8sRes.GetNamespace() if kind == "Job" { - if err := r.updateK8sJob(ctx, existingK8sRes, k8sResConfig, newLabels, newAnnotations, ownerReferences); err != nil { + if err := r.updateK8sJob(ctx, existingK8sRes, k8sResConfig, newLabels, newAnnotations, ownerReferences, optionalFields); err != nil { return errors.Wrap(err, "failed to update Job") } return nil } if kind == "Route" { - if err := r.updateK8sRoute(ctx, existingK8sRes, k8sResConfig, newLabels, newAnnotations, ownerReferences); err != nil { + if err := r.updateK8sRoute(ctx, existingK8sRes, k8sResConfig, newLabels, newAnnotations, ownerReferences, optionalFields); err != nil { return errors.Wrap(err, "failed to update Route") } @@ -1150,6 +1153,9 @@ func (r *Reconciler) updateK8sResource(ctx context.Context, existingK8sRes unstr existingRes.Object = updatedExistingRes } + if err := r.ExecuteOptionalFields(ctx, &existingRes, optionalFields); err != nil { + return false, errors.Wrap(err, "failed to execute optional fields") + } r.EnsureAnnotation(existingRes, newAnnotations) r.EnsureLabel(existingRes, newLabels) if err := r.setOwnerReferences(ctx, &existingRes, ownerReferences); err != nil { @@ -1197,7 +1203,7 @@ func (r *Reconciler) updateK8sResource(ctx context.Context, existingK8sRes unstr return nil } -func (r *Reconciler) updateK8sJob(ctx context.Context, existingK8sRes unstructured.Unstructured, k8sResConfig *runtime.RawExtension, newLabels, newAnnotations map[string]string, ownerReferences *[]operatorv1alpha1.OwnerReference) error { +func (r *Reconciler) updateK8sJob(ctx context.Context, existingK8sRes unstructured.Unstructured, k8sResConfig *runtime.RawExtension, newLabels, newAnnotations map[string]string, ownerReferences *[]operatorv1alpha1.OwnerReference, optionalFields *[]operatorv1alpha1.OptionalField) error { kind := existingK8sRes.GetKind() apiversion := existingK8sRes.GetAPIVersion() @@ -1250,7 +1256,7 @@ func (r *Reconciler) updateK8sJob(ctx context.Context, existingK8sRes unstructur if err := r.deleteK8sResource(ctx, existingRes, namespace); err != nil { return errors.Wrap(err, "failed to update k8s resource") } - if err := r.createK8sResource(ctx, templatek8sRes, k8sResConfig, newLabels, newAnnotations, ownerReferences); err != nil { + if err := r.createK8sResource(ctx, templatek8sRes, k8sResConfig, newLabels, newAnnotations, ownerReferences, optionalFields); err != nil { return errors.Wrap(err, "failed to update k8s resource") } } @@ -1258,7 +1264,7 @@ func (r *Reconciler) updateK8sJob(ctx context.Context, existingK8sRes unstructur } // update route resource -func (r *Reconciler) updateK8sRoute(ctx context.Context, existingK8sRes unstructured.Unstructured, k8sResConfig *runtime.RawExtension, newLabels, newAnnotations map[string]string, ownerReferences *[]operatorv1alpha1.OwnerReference) error { +func (r *Reconciler) updateK8sRoute(ctx context.Context, existingK8sRes unstructured.Unstructured, k8sResConfig *runtime.RawExtension, newLabels, newAnnotations map[string]string, ownerReferences *[]operatorv1alpha1.OwnerReference, optionalFields *[]operatorv1alpha1.OptionalField) error { kind := existingK8sRes.GetKind() apiversion := existingK8sRes.GetAPIVersion() name := existingK8sRes.GetName() @@ -1309,7 +1315,7 @@ func (r *Reconciler) updateK8sRoute(ctx context.Context, existingK8sRes unstruct if err := r.deleteK8sResource(ctx, existingRes, namespace); err != nil { return errors.Wrap(err, "failed to delete Route for recreation") } - if err := r.createK8sResource(ctx, templatek8sRes, k8sResConfig, newLabels, newAnnotations, ownerReferences); err != nil { + if err := r.createK8sResource(ctx, templatek8sRes, k8sResConfig, newLabels, newAnnotations, ownerReferences, optionalFields); err != nil { return errors.Wrap(err, "failed to update k8s resource") } } @@ -1511,6 +1517,84 @@ func (r *Reconciler) setOwnerReferences(ctx context.Context, controlledRes *unst return nil } +func (r *Reconciler) ExecuteOptionalFields(ctx context.Context, resTemplate *unstructured.Unstructured, optionalFields *[]operatorv1alpha1.OptionalField) error { + if optionalFields != nil { + for _, field := range *optionalFields { + // Find the path from resTemplate + if value, err := util.SanitizeObjectString(field.Path, resTemplate.Object); err != nil || value == "" { + klog.Warningf("Skipping execute optional field, not find the path %s in the object -- Kind: %s, NamespacedName: %s/%s: %v", field.Path, resTemplate.GetKind(), resTemplate.GetNamespace(), resTemplate.GetName(), err) + continue + } + // Find the match expressions + if field.MatchExpressions != nil { + if !r.findMatchExpressions(ctx, field.MatchExpressions) { + klog.Infof("Skip operation '%s' for optional fields: %v for %s %s/%s", field.Operation, field.Path, resTemplate.GetKind(), resTemplate.GetNamespace(), resTemplate.GetName()) + continue + } + } + // Do operation + switch field.Operation { + case operatorv1alpha1.OperationRemove: + util.RemoveObjectField(resTemplate.Object, field.Path) + // case "Add": # TODO + default: + klog.Warningf("Invalid operation '%s' in optional fields: %v", field.Operation, field) + } + } + } + return nil +} + +func (r *Reconciler) findMatchExpressions(ctx context.Context, matchExpressions []operatorv1alpha1.MatchExpression) bool { + isMatch := false + for _, matchExpression := range matchExpressions { + if matchExpression.Key == "" || matchExpression.Operator == "" || matchExpression.ObjectRef == nil { + klog.Warningf("Invalid matchExpression: %v", matchExpression) + continue + } + // find value from the object + objRef := &unstructured.Unstructured{} + objRef.SetAPIVersion(matchExpression.ObjectRef.APIVersion) + objRef.SetKind(matchExpression.ObjectRef.Kind) + objRef.SetName(matchExpression.ObjectRef.Name) + if err := r.Reader.Get(ctx, types.NamespacedName{ + Name: matchExpression.ObjectRef.Name, + Namespace: matchExpression.ObjectRef.Namespace, + }, objRef); err != nil { + klog.Warningf("Failed to get the object %v in match expressions: %v", matchExpression.ObjectRef, err) + continue + } + value, _ := util.SanitizeObjectString(matchExpression.Key, objRef.Object) + + switch matchExpression.Operator { + case operatorv1alpha1.OperatorIn: + if util.Contains(matchExpression.Values, value) { + return true + } + case operatorv1alpha1.OperatorNotIn: + if util.Contains(matchExpression.Values, value) { + return false + } else { + isMatch = true + } + case operatorv1alpha1.OperatorExists: + if value != "" { + return true + } + case operatorv1alpha1.OperatorDoesNotExist: + if value != "" { + return false + } else { + isMatch = true + } + default: + klog.Warningf("Invalid operator %s in match expressions: %v", matchExpression.Operator, matchExpression) + } + } + + return isMatch +} + func (r *Reconciler) ServiceStatusIsReady(ctx context.Context, requestInstance *operatorv1alpha1.OperandRequest) (bool, error) { requestedServicesSet := make(map[string]struct{}) for _, req := range requestInstance.Spec.Requests { diff --git a/controllers/operandrequest/reconcile_operand_test.go b/controllers/operandrequest/reconcile_operand_test.go index 69bf5ac6..a88af6a0 100644 --- a/controllers/operandrequest/reconcile_operand_test.go +++ b/controllers/operandrequest/reconcile_operand_test.go @@ -20,6 +20,7 @@ import ( "context" "testing" + "github.com/pkg/errors" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -116,3 +117,171 @@ func TestSetOwnerReferences(t *testing.T) { } assert.Equal(t, expectedOwnerReferences, controlledRes.GetOwnerReferences()) } +func TestFindMatchExpressions(t *testing.T) { + // Create a fake client + client := fake.NewClientBuilder().Build() + + // Create a mock reader + reader := &MockReader{} + + // Create a reconciler instance + r := &Reconciler{ + ODLMOperator: &deploy.ODLMOperator{ + Client: client, + Reader: reader, + }, + } + + // Define test cases + tests := []struct { + name string + matchExpressions []operatorv1alpha1.MatchExpression + expectedResult bool + mockGetError error + mockGetValue string + }{ + { + name: "Valid In operator", + matchExpressions: []operatorv1alpha1.MatchExpression{ + { + Key: ".spec.replicas", + Operator: operatorv1alpha1.OperatorIn, + Values: []string{"3", "4"}, + ObjectRef: &operatorv1alpha1.ObjectRef{ + APIVersion: "apps/v1", + Kind: "Deployment", + Name: "test-deployment", + Namespace: "test-namespace", + }, + }, + }, + expectedResult: true, + mockGetValue: "3", + }, + { + name: "Valid NotIn operator", + matchExpressions: []operatorv1alpha1.MatchExpression{ + { + Key: ".spec.replicas", + Operator: operatorv1alpha1.OperatorNotIn, + Values: []string{"4", "5"}, + ObjectRef: &operatorv1alpha1.ObjectRef{ + APIVersion: "apps/v1", + Kind: "Deployment", + Name: "test-deployment", + Namespace: "test-namespace", + }, + }, + }, + expectedResult: true, + mockGetValue: "3", + }, + { + name: "Valid Exists operator", + matchExpressions: []operatorv1alpha1.MatchExpression{ + { + Key: ".spec.replicas", + Operator: operatorv1alpha1.OperatorExists, + ObjectRef: &operatorv1alpha1.ObjectRef{ + APIVersion: "apps/v1", + Kind: "Deployment", + Name: "test-deployment", + Namespace: "test-namespace", + }, + }, + }, + expectedResult: true, + mockGetValue: "1", + }, + { + name: "Valid DoesNotExist operator", + matchExpressions: []operatorv1alpha1.MatchExpression{ + { + Key: ".spec.replicas", + Operator: operatorv1alpha1.OperatorDoesNotExist, + ObjectRef: &operatorv1alpha1.ObjectRef{ + APIVersion: "apps/v1", + Kind: "Deployment", + Name: "test-deployment", + Namespace: "test-namespace", + }, + }, + }, + expectedResult: false, + mockGetValue: "1", + }, + { + name: "Valid DoesNotExist operator with non-exist parh .spec.replica", + matchExpressions: []operatorv1alpha1.MatchExpression{ + { + Key: ".spec.replica", + Operator: operatorv1alpha1.OperatorDoesNotExist, + ObjectRef: &operatorv1alpha1.ObjectRef{ + APIVersion: "apps/v1", + Kind: "Deployment", + Name: "test-deployment", + Namespace: "test-namespace", + }, + }, + }, + expectedResult: true, + mockGetValue: "", + }, + { + name: "Invalid match expression", + matchExpressions: []operatorv1alpha1.MatchExpression{ + { + Key: "", + Operator: "In", + Values: []string{"3"}, + ObjectRef: &operatorv1alpha1.ObjectRef{ + APIVersion: "apps/v1", + Kind: "Deployment", + Name: "test-deployment", + Namespace: "test-namespace", + }, + }, + }, + expectedResult: false, + }, + { + name: "Failed to get object with path .spec.replica", + matchExpressions: []operatorv1alpha1.MatchExpression{ + { + Key: ".spec.replica", + Operator: operatorv1alpha1.OperatorIn, + Values: []string{"3"}, + ObjectRef: &operatorv1alpha1.ObjectRef{ + APIVersion: "apps/v1", + Kind: "Deployment", + Name: "test-deployment", + Namespace: "test-namespace", + }, + }, + }, + expectedResult: false, + mockGetError: errors.New("failed to get object"), + mockGetValue: "", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Mock the Get method of the reader + reader.On("Get", mock.Anything, types.NamespacedName{Name: "test-deployment", Namespace: "test-namespace"}, mock.AnythingOfType("*unstructured.Unstructured")).Return(tt.mockGetError).Run(func(args mock.Arguments) { + if tt.mockGetError == nil { + obj := args.Get(2).(*unstructured.Unstructured) + obj.Object["spec"] = map[string]interface{}{ + "replicas": tt.mockGetValue, + } + } + }) + + // Call the findMatchExpressions function + result := r.findMatchExpressions(context.Background(), tt.matchExpressions) + + // Assert the result + assert.Equal(t, tt.expectedResult, result) + }) + } +} diff --git a/controllers/util/util.go b/controllers/util/util.go index eaa06478..4545016e 100644 --- a/controllers/util/util.go +++ b/controllers/util/util.go @@ -436,3 +436,92 @@ func FindMinSemverFromAnnotations(annotations map[string]string, curChannel stri semverlList, semVerChannelMappings := FindSemverFromAnnotations(annotations) return FindMinSemver(curChannel, semverlList, semVerChannelMappings) } + +// RemoveObjectField removes the field from the object according to the jsonPath +// jsonPath is a string that represents the path to the field in the object, always starts with "." +func RemoveObjectField(obj interface{}, jsonPath string) { + // Remove the first dot in the beginning of the jsonPath + jsonPath = strings.TrimPrefix(jsonPath, ".") + fields := strings.Split(jsonPath, ".") + + // Check if the object is a map + if objMap, ok := obj.(map[string]interface{}); ok { + removeField(objMap, fields) + } +} + +// removeField removes the field from the object according to the jsonPath +func removeField(obj map[string]interface{}, fields []string) { + // Check if fields is in the format of one item in the list. For example "container[0]" + if strings.Contains(fields[0], "[") { + // Get the field name and the index + field := strings.Split(fields[0], "[")[0] + index, _ := strconv.Atoi(strings.TrimSuffix(strings.TrimPrefix(fields[0], field+"["), "]")) + // Check if the field is a list + if _, ok := obj[field].([]interface{}); !ok { + return + } + // Check if the index is out of range + if index >= len(obj[field].([]interface{})) { + return + } + // Remove the value from the list + removeField(obj[field].([]interface{})[index].(map[string]interface{}), fields[1:]) + return + } + // Check if the field is the last field in the list + if len(fields) == 1 { + delete(obj, fields[0]) + return + } + // Check if the field is a map + if _, ok := obj[fields[0]].(map[string]interface{}); !ok { + return + } + // Remove the value from the map + removeField(obj[fields[0]].(map[string]interface{}), fields[1:]) +} + +// AddObjectField adds the field to the object according to the jsonPath +// jsonPath is a string that represents the path to the field in the object, always starts with "." +func AddObjectField(obj interface{}, jsonPath string, value interface{}) { + // Remove the first dot in the beginning of the jsonPath if it exists + jsonPath = strings.TrimPrefix(jsonPath, ".") + fields := strings.Split(jsonPath, ".") + + // Check if the object is a map + if objMap, ok := obj.(map[string]interface{}); ok { + addField(objMap, fields, value) + } +} + +func addField(obj map[string]interface{}, fields []string, value interface{}) { + // Check if fields is in the format of one item in the list. For example "container[0]" + if strings.Contains(fields[0], "[") { + // Get the field name and the index + field := strings.Split(fields[0], "[")[0] + index, _ := strconv.Atoi(strings.TrimSuffix(strings.TrimPrefix(fields[0], field+"["), "]")) + // Check if the field is a list + if _, ok := obj[field].([]interface{}); !ok { + obj[field] = make([]interface{}, 0) + } + // Check if the index is out of range + if index >= len(obj[field].([]interface{})) { + obj[field] = append(obj[field].([]interface{}), make(map[string]interface{})) + } + // Add the value to the list + addField(obj[field].([]interface{})[index].(map[string]interface{}), fields[1:], value) + return + } + // Check if the field is the last field in the list + if len(fields) == 1 { + obj[fields[0]] = value + return + } + // Check if the field is a map + if _, ok := obj[fields[0]].(map[string]interface{}); !ok { + obj[fields[0]] = make(map[string]interface{}) + } + // Add the value to the map + addField(obj[fields[0]].(map[string]interface{}), fields[1:], value) +} diff --git a/controllers/util/util_test.go b/controllers/util/util_test.go index 311df979..9f70e6c6 100644 --- a/controllers/util/util_test.go +++ b/controllers/util/util_test.go @@ -21,6 +21,7 @@ import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" ) var _ = Describe("Get environmental variables", func() { @@ -258,3 +259,250 @@ var _ = Describe("FindMaxSemver", func() { Expect(FindMaxSemver(curChannel, semverList, semVerChannelMappings)).Should(Equal(expected)) }) }) + +var _ = Describe("RemoveObjectField", func() { + It("Should remove the specified field from the object", func() { + obj := &unstructured.Unstructured{ + Object: map[string]interface{}{ + "metadata": map[string]interface{}{ + "name": "test", + "namespace": "default", + }, + "spec": map[string]interface{}{ + "replicas": 3, + }, + }, + } + + RemoveObjectField(obj.Object, ".metadata.namespace") + + expected := &unstructured.Unstructured{ + Object: map[string]interface{}{ + "metadata": map[string]interface{}{ + "name": "test", + }, + "spec": map[string]interface{}{ + "replicas": 3, + }, + }, + } + + Expect(obj).Should(Equal(expected)) + }) + + It("Should remove nested fields from the object", func() { + obj := &unstructured.Unstructured{ + Object: map[string]interface{}{ + "metadata": map[string]interface{}{ + "name": "test", + "namespace": "default", + "labels": map[string]interface{}{ + "app": "myapp", + }, + }, + "spec": map[string]interface{}{ + "replicas": 3, + }, + }, + } + + RemoveObjectField(obj.Object, ".metadata.labels.app") + + expected := &unstructured.Unstructured{ + Object: map[string]interface{}{ + "metadata": map[string]interface{}{ + "name": "test", + "namespace": "default", + "labels": map[string]interface{}{}, + }, + "spec": map[string]interface{}{ + "replicas": 3, + }, + }, + } + + Expect(obj).Should(Equal(expected)) + }) + + It("Should do nothing if the field does not exist", func() { + obj := &unstructured.Unstructured{ + Object: map[string]interface{}{ + "metadata": map[string]interface{}{ + "name": "test", + "namespace": "default", + }, + "spec": map[string]interface{}{ + "replicas": 3, + }, + }, + } + + RemoveObjectField(obj.Object, ".metadata.labels.app") + + expected := &unstructured.Unstructured{ + Object: map[string]interface{}{ + "metadata": map[string]interface{}{ + "name": "test", + "namespace": "default", + }, + "spec": map[string]interface{}{ + "replicas": 3, + }, + }, + } + + Expect(obj).Should(Equal(expected)) + }) + + It("Should remove field and all its nested fields from the object", func() { + obj := &unstructured.Unstructured{ + Object: map[string]interface{}{ + "metadata": map[string]interface{}{ + "name": "test", + "namespace": "default", + "labels": map[string]interface{}{ + "app": "myapp", + }, + }, + "spec": map[string]interface{}{ + "replicas": 3, + }, + }, + } + + RemoveObjectField(obj.Object, ".metadata") + + expected := &unstructured.Unstructured{ + Object: map[string]interface{}{ + "spec": map[string]interface{}{ + "replicas": 3, + }, + }, + } + + Expect(obj).Should(Equal(expected)) + }) +}) + +var _ = Describe("AddObjectField", func() { + It("Should add a new field to the object", func() { + obj := &unstructured.Unstructured{ + Object: map[string]interface{}{ + "metadata": map[string]interface{}{ + "name": "test", + }, + "spec": map[string]interface{}{ + "replicas": 3, + }, + }, + } + + AddObjectField(obj.Object, ".metadata.namespace", "default") + + expected := &unstructured.Unstructured{ + Object: map[string]interface{}{ + "metadata": map[string]interface{}{ + "name": "test", + "namespace": "default", + }, + "spec": map[string]interface{}{ + "replicas": 3, + }, + }, + } + + Expect(obj).Should(Equal(expected)) + }) + + It("Should add a nested field to the object", func() { + obj := &unstructured.Unstructured{ + Object: map[string]interface{}{ + "metadata": map[string]interface{}{ + "name": "test", + }, + "spec": map[string]interface{}{ + "replicas": 3, + }, + }, + } + + AddObjectField(obj.Object, ".metadata.labels.app", "myapp") + + expected := &unstructured.Unstructured{ + Object: map[string]interface{}{ + "metadata": map[string]interface{}{ + "name": "test", + "labels": map[string]interface{}{ + "app": "myapp", + }, + }, + "spec": map[string]interface{}{ + "replicas": 3, + }, + }, + } + + Expect(obj).Should(Equal(expected)) + }) + + It("Should overwrite an existing field in the object", func() { + obj := &unstructured.Unstructured{ + Object: map[string]interface{}{ + "metadata": map[string]interface{}{ + "name": "test", + }, + "spec": map[string]interface{}{ + "replicas": 3, + }, + }, + } + + AddObjectField(obj.Object, ".spec.replicas", 5) + + expected := &unstructured.Unstructured{ + Object: map[string]interface{}{ + "metadata": map[string]interface{}{ + "name": "test", + }, + "spec": map[string]interface{}{ + "replicas": 5, + }, + }, + } + + Expect(obj).Should(Equal(expected)) + }) + + It("Should create nested maps if they do not exist", func() { + obj := &unstructured.Unstructured{ + Object: map[string]interface{}{ + "metadata": map[string]interface{}{ + "name": "test", + }, + }, + } + + AddObjectField(obj.Object, ".spec.template.spec.containers[0].name", "nginx") + + expected := &unstructured.Unstructured{ + Object: map[string]interface{}{ + "metadata": map[string]interface{}{ + "name": "test", + }, + "spec": map[string]interface{}{ + "template": map[string]interface{}{ + "spec": map[string]interface{}{ + "containers": []interface{}{ + map[string]interface{}{ + "name": "nginx", + }, + }, + }, + }, + }, + }, + } + + Expect(obj).Should(Equal(expected)) + }) +}) From 2f1f1e76ec80e527d02a4ec9104a5e161780fc95 Mon Sep 17 00:00:00 2001 From: YuChen Shen <59578388+YCShen1010@users.noreply.github.com> Date: Mon, 30 Sep 2024 13:32:29 -0400 Subject: [PATCH 146/179] omit empty value (#1087) Signed-off-by: YuChen --- api/v1alpha1/operandconfig_types.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/v1alpha1/operandconfig_types.go b/api/v1alpha1/operandconfig_types.go index 755917f0..4a7fc94b 100644 --- a/api/v1alpha1/operandconfig_types.go +++ b/api/v1alpha1/operandconfig_types.go @@ -108,7 +108,7 @@ type MatchExpression struct { Operator ExpressionOperator `json:"operator"` // Values is the values of the field. // +optional - Values []string `json:"values"` + Values []string `json:"values,omitempty"` // ObjectRef is the reference of the object. // +optional ObjectRef *ObjectRef `json:"objectRef,omitempty"` From b7388f49e67f0ffd1d4bf8715a826883536af732 Mon Sep 17 00:00:00 2001 From: YuChen Shen <59578388+YCShen1010@users.noreply.github.com> Date: Mon, 7 Oct 2024 14:41:41 -0400 Subject: [PATCH 147/179] Bump version to 4.3.7 fo SC2 4.6.8 (#1089) Signed-off-by: YuChen --- Makefile | 2 +- ...eployment-lifecycle-manager.clusterserviceversion.yaml | 8 ++++---- ...eployment-lifecycle-manager.clusterserviceversion.yaml | 4 ++-- version/version.go | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Makefile b/Makefile index 5c2560a8..dc05d59e 100644 --- a/Makefile +++ b/Makefile @@ -84,7 +84,7 @@ OPERATOR_IMAGE_NAME ?= odlm # Current Operator bundle image name BUNDLE_IMAGE_NAME ?= odlm-operator-bundle # Current Operator version -OPERATOR_VERSION ?= 4.3.6 +OPERATOR_VERSION ?= 4.3.7 # Kind cluster name KIND_CLUSTER_NAME ?= "odlm" diff --git a/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml b/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml index 8049aca2..2d801f5e 100644 --- a/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml +++ b/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml @@ -132,7 +132,7 @@ metadata: createdAt: "2024-09-28T19:55:35Z" description: The Operand Deployment Lifecycle Manager provides a Kubernetes CRD-based API to manage the lifecycle of operands. nss.operator.ibm.com/managed-operators: ibm-odlm - olm.skipRange: '>=1.2.0 <4.3.6' + olm.skipRange: '>=1.2.0 <4.3.7' operators.openshift.io/infrastructure-features: '["disconnected"]' operators.operatorframework.io/builder: operator-sdk-v1.32.0 operators.operatorframework.io/project_layout: go.kubebuilder.io/v3 @@ -143,7 +143,7 @@ metadata: operatorframework.io/arch.ppc64le: supported operatorframework.io/arch.s390x: supported operatorframework.io/os.linux: supported - name: operand-deployment-lifecycle-manager.v4.3.6 + name: operand-deployment-lifecycle-manager.v4.3.7 namespace: placeholder spec: apiservicedefinitions: {} @@ -868,7 +868,7 @@ spec: minKubeVersion: 1.19.0 provider: name: IBM - version: 4.3.6 + version: 4.3.7 relatedImages: - - image: icr.io/cpopen/odlm:4.3.6 + - image: icr.io/cpopen/odlm:4.3.7 name: ODLM_IMAGE diff --git a/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml b/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml index e797eb9f..76e19d10 100644 --- a/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml +++ b/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml @@ -11,7 +11,7 @@ metadata: description: The Operand Deployment Lifecycle Manager provides a Kubernetes CRD-based API to manage the lifecycle of operands. nss.operator.ibm.com/managed-operators: ibm-odlm - olm.skipRange: '>=1.2.0 <4.3.6' + olm.skipRange: '>=1.2.0 <4.3.7' operators.openshift.io/infrastructure-features: '["disconnected"]' operators.operatorframework.io/builder: operator-sdk-v1.2.0 operators.operatorframework.io/project_layout: go.kubebuilder.io/v2 @@ -482,6 +482,6 @@ spec: provider: name: IBM relatedImages: - - image: icr.io/cpopen/odlm:4.3.6 + - image: icr.io/cpopen/odlm:4.3.7 name: ODLM_IMAGE version: 0.0.0 diff --git a/version/version.go b/version/version.go index 95dd04cb..e90a7b2f 100644 --- a/version/version.go +++ b/version/version.go @@ -17,5 +17,5 @@ package version var ( - Version = "4.3.6" + Version = "4.3.7" ) From b196a877446004fa2d4a13438a13c1deb7468a00 Mon Sep 17 00:00:00 2001 From: Adam Shank <42580017+ashank07@users.noreply.github.com> Date: Wed, 9 Oct 2024 10:13:18 -0400 Subject: [PATCH 148/179] Revert "build(deps): bump golang from 1.23.0-bullseye to 1.23.1-bullseye (#1081)" (#1090) This reverts commit 6baae188d1a4f2a506f28da885c359d01a5a905c. --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 56c9002d..a4775ec0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # Build the manager binary -FROM docker.io/golang:1.23.1-bullseye as builder +FROM docker.io/golang:1.23.0-bullseye as builder ARG GOARCH WORKDIR /workspace From 90ac731b60d2232d29e1bfb4cf2e08e64659d17d Mon Sep 17 00:00:00 2001 From: Travis CI User Date: Thu, 10 Oct 2024 17:23:08 +0000 Subject: [PATCH 149/179] Trigger build with new base image --- base_images.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base_images.json b/base_images.json index fba9a7de..4d8de89c 100644 --- a/base_images.json +++ b/base_images.json @@ -44,6 +44,6 @@ "sourceImage": "ubi9-minimal", "sourceTag": "9.4-1227.1726694542", "destImage": "node-v20-ubi9-minimal", - "nodeVersion": "20.17.0" + "nodeVersion": "20.18.0" } ] From 962c1addcc878e9e8b4b4c220afbe398656ca543 Mon Sep 17 00:00:00 2001 From: Adam Shank <42580017+ashank07@users.noreply.github.com> Date: Thu, 10 Oct 2024 16:02:39 -0400 Subject: [PATCH 150/179] Test with bookworm golang (#1091) --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index a4775ec0..3ac68046 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # Build the manager binary -FROM docker.io/golang:1.23.0-bullseye as builder +FROM docker-na-public.artifactory.swg-devops.com/hyc-cloud-private-dockerhub-docker-remote/golang:1.23.2 as builder ARG GOARCH WORKDIR /workspace From 8fbfdcdefd0994030d4d4dfe6ccef35189277076 Mon Sep 17 00:00:00 2001 From: Allen Li <46284272+qpdpQ@users.noreply.github.com> Date: Thu, 17 Oct 2024 12:45:46 -0400 Subject: [PATCH 151/179] label length limitation (#1092) * label length limitation Signed-off-by: Allen Li * remove string conversion Signed-off-by: Allen Li * update var name Signed-off-by: Allen Li * use annotations instead of label Signed-off-by: Allen Li --------- Signed-off-by: Allen Li --- controllers/constant/constant.go | 4 +-- .../operandrequest_controller.go | 6 ++-- controllers/operator/manager.go | 31 +++++++++++++------ controllers/util/util.go | 25 +++++++++++++++ 4 files changed, 51 insertions(+), 15 deletions(-) diff --git a/controllers/constant/constant.go b/controllers/constant/constant.go index 25eca64b..49fe0044 100644 --- a/controllers/constant/constant.go +++ b/controllers/constant/constant.go @@ -34,8 +34,8 @@ const ( //InternalOpreqLabel is the label used label the OperandRequest internally created by ODLM OperandOnlyLabel string = "operator.ibm.com/operand-only" - //ODLMReferenceLabel is the label used to label the resources used for ODLM operand value reference - ODLMReferenceLabel string = "operator.ibm.com/referenced-by-odlm-resource" + //ODLMReferenceAnnotation is the annotation used to annotate the resources used for ODLM operand value reference + ODLMReferenceAnnotation string = "operator.ibm.com/referenced-by-odlm-resource" //ODLMWatchedLabel is the label used to label the resources watched by ODLM for value reference ODLMWatchedLabel string = "operator.ibm.com/watched-by-odlm" diff --git a/controllers/operandrequest/operandrequest_controller.go b/controllers/operandrequest/operandrequest_controller.go index 458fd504..ef3d1b6b 100644 --- a/controllers/operandrequest/operandrequest_controller.go +++ b/controllers/operandrequest/operandrequest_controller.go @@ -322,11 +322,11 @@ func (r *Reconciler) getConfigToRequestMapper() handler.MapFunc { func (r *Reconciler) getReferenceToRequestMapper() handler.MapFunc { ctx := context.Background() return func(object client.Object) []ctrl.Request { - labels := object.GetLabels() - if labels == nil { + annotations := object.GetAnnotations() + if annotations == nil { return []ctrl.Request{} } - odlmReference, ok := labels[constant.ODLMReferenceLabel] + odlmReference, ok := annotations[constant.ODLMReferenceAnnotation] if !ok { return []ctrl.Request{} } diff --git a/controllers/operator/manager.go b/controllers/operator/manager.go index 6cb646fd..68fa2dd2 100644 --- a/controllers/operator/manager.go +++ b/controllers/operator/manager.go @@ -473,22 +473,24 @@ func (m *ODLMOperator) GetClusterServiceVersionList(ctx context.Context, sub *ol packageName := sub.Spec.Package csvNamespace := sub.Namespace + labelKey := packageName + "." + csvNamespace + labelKey = util.GetFirstNCharacter(labelKey, 63) // Get the ClusterServiceVersion list with label operators.coreos.com/packageName.csvNamespace='' csvList := &olmv1alpha1.ClusterServiceVersionList{} opts := []client.ListOption{ - client.MatchingLabels{fmt.Sprintf("operators.coreos.com/%s.%s", packageName, csvNamespace): ""}, + client.MatchingLabels{fmt.Sprintf("operators.coreos.com/%s", labelKey): ""}, client.InNamespace(csvNamespace), } if err := m.Reader.List(ctx, csvList, opts...); err != nil { if apierrors.IsNotFound(err) || len(csvList.Items) == 0 { - klog.V(3).Infof("No ClusterServiceVersion found with label operators.coreos.com/%s.%s", packageName, csvNamespace) + klog.V(3).Infof("No ClusterServiceVersion found with label operators.coreos.com/%s", labelKey) return nil, nil } - return nil, errors.Wrapf(err, "failed to list ClusterServiceVersions with label operators.coreos.com/%s.%s", packageName, csvNamespace) + return nil, errors.Wrapf(err, "failed to list ClusterServiceVersions with label operators.coreos.com/%s", labelKey) } else if len(csvList.Items) > 1 { - klog.Warningf("Multiple ClusterServiceVersions found with label operators.coreos.com/%s.%s", packageName, csvNamespace) + klog.Warningf("Multiple ClusterServiceVersions found with label operators.coreos.com/%s", labelKey) } var csvs []*olmv1alpha1.ClusterServiceVersion @@ -836,8 +838,11 @@ func (m *ODLMOperator) GetValueRefFromConfigMap(ctx context.Context, instanceTyp // Set the Value Reference label for the ConfigMap util.EnsureLabelsForConfigMap(cm, map[string]string{ - constant.ODLMReferenceLabel: instanceType + "." + instanceNs + "." + instanceName, - constant.ODLMWatchedLabel: "true", + constant.ODLMWatchedLabel: "true", + }) + // Set the Value Reference Annotation for the ConfigMap + util.EnsureAnnotationForConfigMap(cm, map[string]string{ + constant.ODLMReferenceAnnotation: instanceType + "." + instanceNs + "." + instanceName, }) // Update the ConfigMap with the Value Reference label if err := m.Update(ctx, cm); err != nil { @@ -865,8 +870,11 @@ func (m *ODLMOperator) GetValueRefFromSecret(ctx context.Context, instanceType, // Set the Value Reference label for the Secret util.EnsureLabelsForSecret(secret, map[string]string{ - constant.ODLMReferenceLabel: instanceType + "." + instanceNs + "." + instanceName, - constant.ODLMWatchedLabel: "true", + constant.ODLMWatchedLabel: "true", + }) + // Set the Value Reference Annotation for the Secret + util.EnsureAnnotationsForSecret(secret, map[string]string{ + constant.ODLMReferenceAnnotation: instanceType + "." + instanceNs + "." + instanceName, }) // Update the Secret with the Value Reference label if err := m.Update(ctx, secret); err != nil { @@ -896,8 +904,11 @@ func (m *ODLMOperator) GetValueRefFromObject(ctx context.Context, instanceType, // Set the Value Reference label for the object m.EnsureLabel(obj, map[string]string{ - constant.ODLMReferenceLabel: instanceType + "." + instanceNs + "." + instanceName, - constant.ODLMWatchedLabel: "true", + constant.ODLMWatchedLabel: "true", + }) + // Set the Value Reference Annotation for the Secret + m.EnsureAnnotation(obj, map[string]string{ + constant.ODLMReferenceAnnotation: instanceType + "." + instanceNs + "." + instanceName, }) // Update the object with the Value Reference label if err := m.Update(ctx, &obj); err != nil { diff --git a/controllers/util/util.go b/controllers/util/util.go index 4545016e..ec4c924b 100644 --- a/controllers/util/util.go +++ b/controllers/util/util.go @@ -302,6 +302,15 @@ func EnsureLabelsForSecret(secret *corev1.Secret, labels map[string]string) { } } +func EnsureAnnotationsForSecret(secret *corev1.Secret, annotatinos map[string]string) { + if secret.Annotations == nil { + secret.Annotations = make(map[string]string) + } + for k, v := range annotatinos { + secret.Annotations[k] = v + } +} + func EnsureLabelsForConfigMap(cm *corev1.ConfigMap, labels map[string]string) { if cm.Labels == nil { cm.Labels = make(map[string]string) @@ -311,6 +320,15 @@ func EnsureLabelsForConfigMap(cm *corev1.ConfigMap, labels map[string]string) { } } +func EnsureAnnotationForConfigMap(cm *corev1.ConfigMap, annotations map[string]string) { + if cm.Annotations == nil { + cm.Annotations = make(map[string]string) + } + for k, v := range annotations { + cm.Labels[k] = v + } +} + func EnsureLabelsForRoute(r *ocproute.Route, labels map[string]string) { if r.Labels == nil { r.Labels = make(map[string]string) @@ -525,3 +543,10 @@ func addField(obj map[string]interface{}, fields []string, value interface{}) { // Add the value to the map addField(obj[fields[0]].(map[string]interface{}), fields[1:], value) } + +func GetFirstNCharacter(str string, n int) string { + if n >= len(str) { + return str + } + return str[:n] +} From cc65c9e88b06c0788d6ba4cc8618b89cb9963935 Mon Sep 17 00:00:00 2001 From: Allen Li <46284272+qpdpQ@users.noreply.github.com> Date: Fri, 18 Oct 2024 14:23:46 -0400 Subject: [PATCH 152/179] fix typo in utils (#1093) Signed-off-by: Allen Li --- controllers/util/util.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/controllers/util/util.go b/controllers/util/util.go index ec4c924b..86ae4fff 100644 --- a/controllers/util/util.go +++ b/controllers/util/util.go @@ -325,7 +325,7 @@ func EnsureAnnotationForConfigMap(cm *corev1.ConfigMap, annotations map[string]s cm.Annotations = make(map[string]string) } for k, v := range annotations { - cm.Labels[k] = v + cm.Annotations[k] = v } } From 885f03ebf7097ea975fe46508024023635eb2c1d Mon Sep 17 00:00:00 2001 From: Allen Li <46284272+qpdpQ@users.noreply.github.com> Date: Tue, 22 Oct 2024 14:00:52 -0400 Subject: [PATCH 153/179] ensure label within length limitation (#1094) Signed-off-by: Allen Li --- controllers/operator/manager.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/controllers/operator/manager.go b/controllers/operator/manager.go index 68fa2dd2..d7a4adf8 100644 --- a/controllers/operator/manager.go +++ b/controllers/operator/manager.go @@ -597,8 +597,9 @@ func (m *ODLMOperator) GetOperandFromRegistry(ctx context.Context, reg *apiv1alp excludedCatalogSources = strings.Split(reg.Annotations["excluded-catalogsource"], ",") } // Get catalog used by ODLM itself by check its own subscription + labelKey := util.GetFirstNCharacter("ibm-odlm"+"."+util.GetOperatorNamespace(), 63) opts := []client.ListOption{ - client.MatchingLabels{fmt.Sprintf("operators.coreos.com/ibm-odlm.%s", util.GetOperatorNamespace()): ""}, + client.MatchingLabels{fmt.Sprintf("operators.coreos.com/%s", labelKey): ""}, client.InNamespace(util.GetOperatorNamespace()), } odlmCatalog := "" From 7a535ebd0f64ad78c785e9d916d805962cec5d50 Mon Sep 17 00:00:00 2001 From: YuChen Shen <59578388+YCShen1010@users.noreply.github.com> Date: Wed, 30 Oct 2024 15:55:59 -0400 Subject: [PATCH 154/179] Delete k8s resources by checking the label from OperandConfig (#1095) * delete k8s resources by checking from OperandConfig Signed-off-by: YuChen * new label condition check Signed-off-by: YuChen --------- Signed-off-by: YuChen --- .../operandrequest/reconcile_operand.go | 113 ++++++++++-------- 1 file changed, 60 insertions(+), 53 deletions(-) diff --git a/controllers/operandrequest/reconcile_operand.go b/controllers/operandrequest/reconcile_operand.go index b70dc387..f977bc6f 100644 --- a/controllers/operandrequest/reconcile_operand.go +++ b/controllers/operandrequest/reconcile_operand.go @@ -1116,6 +1116,7 @@ func (r *Reconciler) updateK8sResource(ctx context.Context, existingK8sRes unstr if err != nil { return false, errors.Wrapf(err, "failed to get k8s resource -- Kind: %s, NamespacedName: %s/%s", kind, namespace, name) } + resourceVersion := existingRes.GetResourceVersion() if !r.CheckLabel(existingRes, map[string]string{constant.OpreqLabel: "true"}) && (newLabels == nil || newLabels[constant.OpreqLabel] != "true") { @@ -1253,7 +1254,7 @@ func (r *Reconciler) updateK8sJob(ctx context.Context, existingK8sRes unstructur } newAnnotations[constant.HashedData] = newHashedData - if err := r.deleteK8sResource(ctx, existingRes, namespace); err != nil { + if err := r.deleteK8sResource(ctx, existingRes, newLabels, namespace); err != nil { return errors.Wrap(err, "failed to update k8s resource") } if err := r.createK8sResource(ctx, templatek8sRes, k8sResConfig, newLabels, newAnnotations, ownerReferences, optionalFields); err != nil { @@ -1312,7 +1313,7 @@ func (r *Reconciler) updateK8sRoute(ctx context.Context, existingK8sRes unstruct templatek8sRes.SetName(name) templatek8sRes.SetNamespace(namespace) - if err := r.deleteK8sResource(ctx, existingRes, namespace); err != nil { + if err := r.deleteK8sResource(ctx, existingRes, newLabels, namespace); err != nil { return errors.Wrap(err, "failed to delete Route for recreation") } if err := r.createK8sResource(ctx, templatek8sRes, k8sResConfig, newLabels, newAnnotations, ownerReferences, optionalFields); err != nil { @@ -1324,7 +1325,56 @@ func (r *Reconciler) updateK8sRoute(ctx context.Context, existingK8sRes unstruct return nil } -func (r *Reconciler) deleteK8sResource(ctx context.Context, existingK8sRes unstructured.Unstructured, namespace string) error { +// deleteAllK8sResource remove k8s resource base on OperandConfig +func (r *Reconciler) deleteAllK8sResource(ctx context.Context, csc *operatorv1alpha1.OperandConfig, operandName, namespace string) error { + + service := csc.GetService(operandName) + if service == nil { + return nil + } + + var k8sResourceList []operatorv1alpha1.ConfigResource + k8sResourceList = append(k8sResourceList, service.Resources...) + + merr := &util.MultiErr{} + var ( + wg sync.WaitGroup + ) + for _, k8sRes := range k8sResourceList { + k8sResShouldBeDeleted := unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": k8sRes.APIVersion, + "kind": k8sRes.Kind, + "metadata": map[string]interface{}{ + "name": k8sRes.Name, + }, + }, + } + k8sNamespace := namespace + if k8sRes.Namespace != "" { + k8sNamespace = k8sRes.Namespace + } + + wg.Add(1) + go func() { + defer wg.Done() + if err := r.deleteK8sResource(ctx, k8sResShouldBeDeleted, k8sRes.Labels, k8sNamespace); err != nil { + r.Mutex.Lock() + defer r.Mutex.Unlock() + merr.Add(err) + return + } + }() + } + wg.Wait() + + if len(merr.Errors) != 0 { + return merr + } + return nil +} + +func (r *Reconciler) deleteK8sResource(ctx context.Context, existingK8sRes unstructured.Unstructured, newLabels map[string]string, namespace string) error { kind := existingK8sRes.GetKind() apiversion := existingK8sRes.GetAPIVersion() @@ -1346,7 +1396,13 @@ func (r *Reconciler) deleteK8sResource(ctx context.Context, existingK8sRes unstr if apierrors.IsNotFound(err) { klog.V(3).Infof("There is no k8s resource: %s from kind: %s", name, kind) } else { - if r.CheckLabel(k8sResShouldBeDeleted, map[string]string{constant.OpreqLabel: "true"}) && !r.CheckLabel(k8sResShouldBeDeleted, map[string]string{constant.NotUninstallLabel: "true"}) { + // If the existing k8s resources has the OpreqLabel and does not have the NotUninstallLabel, delete it + // If the OpreqLabel is difined in OperandConfig resource, delete it + hasOpreqLabel := r.CheckLabel(k8sResShouldBeDeleted, map[string]string{constant.OpreqLabel: "true"}) + hasNotUninstallLabel := r.CheckLabel(k8sResShouldBeDeleted, map[string]string{constant.NotUninstallLabel: "true"}) + opreqLabelInConfig := newLabels != nil && newLabels[constant.OpreqLabel] == "true" + + if (hasOpreqLabel && !hasNotUninstallLabel) || opreqLabelInConfig { klog.V(3).Infof("Deleting k8s resource: %s from kind: %s", name, kind) err := r.Delete(ctx, &k8sResShouldBeDeleted, client.PropagationPolicy(metav1.DeletePropagationBackground)) if err != nil && !apierrors.IsNotFound(err) { @@ -1378,55 +1434,6 @@ func (r *Reconciler) deleteK8sResource(ctx context.Context, existingK8sRes unstr return nil } -// deleteAllK8sResource remove k8s resource base on OperandConfig -func (r *Reconciler) deleteAllK8sResource(ctx context.Context, csc *operatorv1alpha1.OperandConfig, operandName, namespace string) error { - - service := csc.GetService(operandName) - if service == nil { - return nil - } - - var k8sResourceList []operatorv1alpha1.ConfigResource - k8sResourceList = append(k8sResourceList, service.Resources...) - - merr := &util.MultiErr{} - var ( - wg sync.WaitGroup - ) - for _, k8sRes := range k8sResourceList { - k8sResShouldBeDeleted := unstructured.Unstructured{ - Object: map[string]interface{}{ - "apiVersion": k8sRes.APIVersion, - "kind": k8sRes.Kind, - "metadata": map[string]interface{}{ - "name": k8sRes.Name, - }, - }, - } - k8sNamespace := namespace - if k8sRes.Namespace != "" { - k8sNamespace = k8sRes.Namespace - } - - wg.Add(1) - go func() { - defer wg.Done() - if err := r.deleteK8sResource(ctx, k8sResShouldBeDeleted, k8sNamespace); err != nil { - r.Mutex.Lock() - defer r.Mutex.Unlock() - merr.Add(err) - return - } - }() - } - wg.Wait() - - if len(merr.Errors) != 0 { - return merr - } - return nil -} - func (r *Reconciler) checkResAuth(ctx context.Context, verbs []string, k8sResTemplate unstructured.Unstructured) bool { kind := k8sResTemplate.GetKind() apiversion := k8sResTemplate.GetAPIVersion() From dd83aced32de0750881f262e53d1aea14112afd5 Mon Sep 17 00:00:00 2001 From: YuChen Shen <59578388+YCShen1010@users.noreply.github.com> Date: Tue, 12 Nov 2024 11:29:12 -0500 Subject: [PATCH 155/179] Bump version to 4.3.8 fo SC2 4.6.9 (#1096) Signed-off-by: YuChen --- Makefile | 2 +- ...eployment-lifecycle-manager.clusterserviceversion.yaml | 8 ++++---- ...eployment-lifecycle-manager.clusterserviceversion.yaml | 4 ++-- version/version.go | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Makefile b/Makefile index dc05d59e..a664e22e 100644 --- a/Makefile +++ b/Makefile @@ -84,7 +84,7 @@ OPERATOR_IMAGE_NAME ?= odlm # Current Operator bundle image name BUNDLE_IMAGE_NAME ?= odlm-operator-bundle # Current Operator version -OPERATOR_VERSION ?= 4.3.7 +OPERATOR_VERSION ?= 4.3.8 # Kind cluster name KIND_CLUSTER_NAME ?= "odlm" diff --git a/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml b/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml index 2d801f5e..085be9b4 100644 --- a/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml +++ b/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml @@ -132,7 +132,7 @@ metadata: createdAt: "2024-09-28T19:55:35Z" description: The Operand Deployment Lifecycle Manager provides a Kubernetes CRD-based API to manage the lifecycle of operands. nss.operator.ibm.com/managed-operators: ibm-odlm - olm.skipRange: '>=1.2.0 <4.3.7' + olm.skipRange: '>=1.2.0 <4.3.8' operators.openshift.io/infrastructure-features: '["disconnected"]' operators.operatorframework.io/builder: operator-sdk-v1.32.0 operators.operatorframework.io/project_layout: go.kubebuilder.io/v3 @@ -143,7 +143,7 @@ metadata: operatorframework.io/arch.ppc64le: supported operatorframework.io/arch.s390x: supported operatorframework.io/os.linux: supported - name: operand-deployment-lifecycle-manager.v4.3.7 + name: operand-deployment-lifecycle-manager.v4.3.8 namespace: placeholder spec: apiservicedefinitions: {} @@ -868,7 +868,7 @@ spec: minKubeVersion: 1.19.0 provider: name: IBM - version: 4.3.7 + version: 4.3.8 relatedImages: - - image: icr.io/cpopen/odlm:4.3.7 + - image: icr.io/cpopen/odlm:4.3.8 name: ODLM_IMAGE diff --git a/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml b/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml index 76e19d10..f92e9a77 100644 --- a/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml +++ b/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml @@ -11,7 +11,7 @@ metadata: description: The Operand Deployment Lifecycle Manager provides a Kubernetes CRD-based API to manage the lifecycle of operands. nss.operator.ibm.com/managed-operators: ibm-odlm - olm.skipRange: '>=1.2.0 <4.3.7' + olm.skipRange: '>=1.2.0 <4.3.8' operators.openshift.io/infrastructure-features: '["disconnected"]' operators.operatorframework.io/builder: operator-sdk-v1.2.0 operators.operatorframework.io/project_layout: go.kubebuilder.io/v2 @@ -482,6 +482,6 @@ spec: provider: name: IBM relatedImages: - - image: icr.io/cpopen/odlm:4.3.7 + - image: icr.io/cpopen/odlm:4.3.8 name: ODLM_IMAGE version: 0.0.0 diff --git a/version/version.go b/version/version.go index e90a7b2f..b00044c8 100644 --- a/version/version.go +++ b/version/version.go @@ -17,5 +17,5 @@ package version var ( - Version = "4.3.7" + Version = "4.3.8" ) From bb44e653ce96f364f2866dd04ad10b13de4718e9 Mon Sep 17 00:00:00 2001 From: Travis CI User Date: Fri, 15 Nov 2024 22:15:01 +0000 Subject: [PATCH 156/179] Trigger build with new base image --- base_images.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/base_images.json b/base_images.json index 4d8de89c..c7109111 100644 --- a/base_images.json +++ b/base_images.json @@ -7,7 +7,7 @@ "destStage": "edge", "destNamespace": "build-images", "destImage": "ubi9-micro", - "tag": "9.4-15", + "tag": "9.5-1731519709", "updatePackages": [] }, { @@ -18,7 +18,7 @@ "destStage": "edge", "destNamespace": "build-images", "destImage": "ubi9", - "tag": "9.4-1214.1726694543", + "tag": "9.5-1731517889", "updatePackages": [] }, { @@ -29,20 +29,20 @@ "destStage": "edge", "destNamespace": "build-images", "destImage": "ubi9-minimal", - "tag": "9.4-1227.1726694542", + "tag": "9.5-1731593028", "updatePackages": [] }, { "imageType": "node", "sourceImage": "ubi9-minimal", - "sourceTag": "9.4-1227.1726694542", + "sourceTag": "9.5-1731593028", "destImage": "node-v18-ubi9-minimal", - "nodeVersion": "18.20.4" + "nodeVersion": "18.20.5" }, { "imageType": "node", "sourceImage": "ubi9-minimal", - "sourceTag": "9.4-1227.1726694542", + "sourceTag": "9.5-1731593028", "destImage": "node-v20-ubi9-minimal", "nodeVersion": "20.18.0" } From ad4b8926d2de28e4bc1786b6e87d29e7269cc448 Mon Sep 17 00:00:00 2001 From: Daniel Fan Date: Wed, 20 Nov 2024 14:13:19 -0500 Subject: [PATCH 157/179] Tolerate both opt.channel and opt.FallbackChannels for one operator (#1098) * Reconciliation will tolerate both opt.channel and opt.FallbackChannels for one operator Signed-off-by: Daniel Fan * trigger reconciliation when subscription annotation is updated Signed-off-by: Daniel Fan --------- Signed-off-by: Daniel Fan --- controllers/operandrequest/operandrequest_controller.go | 4 +++- controllers/operandrequest/reconcile_operator.go | 5 ++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/controllers/operandrequest/operandrequest_controller.go b/controllers/operandrequest/operandrequest_controller.go index ef3d1b6b..2af1f715 100644 --- a/controllers/operandrequest/operandrequest_controller.go +++ b/controllers/operandrequest/operandrequest_controller.go @@ -399,7 +399,9 @@ func (r *Reconciler) SetupWithManager(mgr ctrl.Manager) error { oldObject := e.ObjectOld.(*olmv1alpha1.Subscription) newObject := e.ObjectNew.(*olmv1alpha1.Subscription) if oldObject.Labels != nil && oldObject.Labels[constant.OpreqLabel] == "true" { - return (oldObject.Status.InstalledCSV != "" && newObject.Status.InstalledCSV != "" && oldObject.Status.InstalledCSV != newObject.Status.InstalledCSV) + statusToggle := (oldObject.Status.InstalledCSV != "" && newObject.Status.InstalledCSV != "" && oldObject.Status.InstalledCSV != newObject.Status.InstalledCSV) + metadataToggle := !reflect.DeepEqual(oldObject.Annotations, newObject.Annotations) + return statusToggle || metadataToggle } return false }, diff --git a/controllers/operandrequest/reconcile_operator.go b/controllers/operandrequest/reconcile_operator.go index 8955ef75..3012ccc2 100644 --- a/controllers/operandrequest/reconcile_operator.go +++ b/controllers/operandrequest/reconcile_operator.go @@ -254,9 +254,12 @@ func (r *Reconciler) reconcileSubscription(ctx context.Context, requestInstance sub.Spec.Channel = minChannel } + channels := []string{opt.Channel} + if channels = append(channels, opt.FallbackChannels...); util.Contains(channels, sub.Spec.Channel) { + isMatchedChannel = true + } // update the spec iff channel in sub matches channel if sub.Spec.Channel == opt.Channel { - isMatchedChannel = true sub.Spec.CatalogSource = opt.SourceName sub.Spec.CatalogSourceNamespace = opt.SourceNamespace sub.Spec.Package = opt.PackageName From 5667aa097ff0de2451589aace9d9148761e61b83 Mon Sep 17 00:00:00 2001 From: YuChen Shen <59578388+YCShen1010@users.noreply.github.com> Date: Thu, 28 Nov 2024 23:42:27 -0500 Subject: [PATCH 158/179] add cluster permission check for v3 resources (#1097) Signed-off-by: YuChen --- .../operandrequest/reconcile_operand.go | 52 +++++++++++-------- 1 file changed, 29 insertions(+), 23 deletions(-) diff --git a/controllers/operandrequest/reconcile_operand.go b/controllers/operandrequest/reconcile_operand.go index f977bc6f..ed081821 100644 --- a/controllers/operandrequest/reconcile_operand.go +++ b/controllers/operandrequest/reconcile_operand.go @@ -669,29 +669,35 @@ func (r *Reconciler) deleteAllCustomResource(ctx context.Context, csv *olmv1alph // Compare the name of OperandConfig and CRD name if strings.EqualFold(kind, crdName) { - err := r.Client.Get(ctx, types.NamespacedName{ - Name: name, - Namespace: namespace, - }, &crTemplate) - if err != nil && !apierrors.IsNotFound(err) { - merr.Add(err) - continue - } - if apierrors.IsNotFound(err) { - klog.V(2).Info("Finish Deleting the CR: " + kind) - continue - } - if r.CheckLabel(crTemplate, map[string]string{constant.OpreqLabel: "true"}) { - wg.Add(1) - go func() { - defer wg.Done() - if err := r.deleteCustomResource(ctx, crTemplate, namespace); err != nil { - r.Mutex.Lock() - defer r.Mutex.Unlock() - merr.Add(err) - return - } - }() + if r.checkResAuth(ctx, []string{"get"}, crTemplate) { + + err := r.Client.Get(ctx, types.NamespacedName{ + Name: name, + Namespace: namespace, + }, &crTemplate) + if err != nil && !apierrors.IsNotFound(err) { + merr.Add(err) + continue + } + if apierrors.IsNotFound(err) { + klog.V(2).Info("Finish Deleting the CR: " + kind) + continue + } + if r.CheckLabel(crTemplate, map[string]string{constant.OpreqLabel: "true"}) { + wg.Add(1) + go func() { + defer wg.Done() + if r.checkResAuth(ctx, []string{"delete"}, crTemplate) { + if err := r.deleteCustomResource(ctx, crTemplate, namespace); err != nil { + r.Mutex.Lock() + defer r.Mutex.Unlock() + merr.Add(err) + return + } + } + }() + } + } } From 1b6ff4cb032b0b7bdbd8f6a62eaa3a332f423e85 Mon Sep 17 00:00:00 2001 From: YuChen Shen <59578388+YCShen1010@users.noreply.github.com> Date: Fri, 29 Nov 2024 10:58:27 -0500 Subject: [PATCH 159/179] Discover private CatalogSource only if no catalog cluster permission exists (#1099) * read catalogsource permission only for non-private ctrsource Signed-off-by: YuChen * add test case for checkResAuth function in manager.go Signed-off-by: YuChen * add create mock test or ODLMoperator Signed-off-by: YuChen * update test case Signed-off-by: YuChen --------- Signed-off-by: YuChen --- controllers/operator/manager.go | 31 ++++++++++++++ controllers/operator/manager_test.go | 64 ++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+) diff --git a/controllers/operator/manager.go b/controllers/operator/manager.go index d7a4adf8..6ecf4ae0 100644 --- a/controllers/operator/manager.go +++ b/controllers/operator/manager.go @@ -27,6 +27,7 @@ import ( operatorsv1 "github.com/operator-framework/operator-lifecycle-manager/pkg/package-server/apis/operators/v1" "github.com/pkg/errors" "golang.org/x/mod/semver" + authorizationv1 "k8s.io/api/authorization/v1" corev1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" @@ -172,11 +173,19 @@ func (m *ODLMOperator) GetCatalogSourceAndChannelFromPackage(ctx context.Context if excludedCatalogSources != nil && util.Contains(excludedCatalogSources, pm.Status.CatalogSource) { continue } + + hasCatalogPermission := m.CheckResAuth(ctx, namespace, "operators.coreos.com", "catalogsources", "get") + if !hasCatalogPermission { + klog.V(2).Infof("No permission to get CatalogSource %s in the namespace %s", pm.Status.CatalogSource, pm.Status.CatalogSourceNamespace) + continue + } + // Fetch the CatalogSource if cluster permission allows catalogsource := &olmv1alpha1.CatalogSource{} if err := m.Reader.Get(ctx, types.NamespacedName{Name: pm.Status.CatalogSource, Namespace: pm.Status.CatalogSourceNamespace}, catalogsource); err != nil { klog.Warning(err) continue } + currentCatalog := CatalogSource{ Name: pm.Status.CatalogSource, Namespace: pm.Status.CatalogSourceNamespace, @@ -220,6 +229,28 @@ func (m *ODLMOperator) GetCatalogSourceAndChannelFromPackage(ctx context.Context } } +func (m *ODLMOperator) CheckResAuth(ctx context.Context, namespace, group, resource, verb string) bool { + sar := &authorizationv1.SubjectAccessReview{ + Spec: authorizationv1.SubjectAccessReviewSpec{ + ResourceAttributes: &authorizationv1.ResourceAttributes{ + Namespace: namespace, + Group: group, + Resource: resource, + Verb: verb, + }, + }, + } + if err := m.Create(ctx, sar); err != nil { + return false + } + + if !sar.Status.Allowed { + return false + } + + return true +} + func channelCheck(channelName string, channelList []operatorsv1.PackageChannel) bool { for _, channel := range channelList { if channelName == channel.Name { diff --git a/controllers/operator/manager_test.go b/controllers/operator/manager_test.go index 4d55b5e6..221469e3 100644 --- a/controllers/operator/manager_test.go +++ b/controllers/operator/manager_test.go @@ -18,11 +18,14 @@ package operator import ( "context" + "fmt" "reflect" "testing" olmv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1" operatorsv1 "github.com/operator-framework/operator-lifecycle-manager/pkg/package-server/apis/operators/v1" + "github.com/stretchr/testify/mock" + authorizationv1 "k8s.io/api/authorization/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "sigs.k8s.io/controller-runtime/pkg/client" ) @@ -302,10 +305,18 @@ func TestGetCatalogSourceAndChannelFromPackage(t *testing.T) { CatalogSourceList: CatalogSourceList, } + mockClient := &MockClient{} + operator := &ODLMOperator{ Reader: fakeReader, + Client: mockClient, } + mockClient.mock.On("Create", ctx, mock.Anything, mock.Anything).Return(nil).Run(func(args mock.Arguments) { + sar := args.Get(1).(*authorizationv1.SubjectAccessReview) + sar.Status.Allowed = true + }) + registryNs := "registry-namespace" odlmCatalog := "odlm-catalog" odlmCatalogNs := "odlm-namespace" @@ -400,6 +411,59 @@ func TestGetCatalogSourceAndChannelFromPackage(t *testing.T) { } +type MockClient struct { + mock mock.Mock + client.Client +} + +func (m *MockClient) Create(ctx context.Context, obj client.Object, opts ...client.CreateOption) error { + args := m.mock.Called(ctx, obj, opts) + return args.Error(0) +} + +func TestCheckResAuth(t *testing.T) { + ctx := context.TODO() + + mockClient := &MockClient{} + operator := &ODLMOperator{ + Client: mockClient, + } + + namespace := "test-namespace" + group := "test-group" + resource := "test-resource" + verb := "get" + + // Test when SubjectAccessReview is allowed + mockClient.mock.On("Create", ctx, mock.Anything, mock.Anything).Return(nil).Run(func(args mock.Arguments) { + sar := args.Get(1).(*authorizationv1.SubjectAccessReview) + sar.Status.Allowed = true + }) + + if !operator.CheckResAuth(ctx, namespace, group, resource, verb) { + t.Errorf("Expected CheckResAuth to return true, but got false") + } + + // Test when SubjectAccessReview is not allowed + mockClient.mock.ExpectedCalls = nil + mockClient.mock.On("Create", ctx, mock.Anything, mock.Anything).Return(nil).Run(func(args mock.Arguments) { + sar := args.Get(1).(*authorizationv1.SubjectAccessReview) + sar.Status.Allowed = false + }) + + if operator.CheckResAuth(ctx, namespace, group, resource, verb) { + t.Errorf("Expected CheckResAuth to return false, but got true") + } + + // Test when Create returns an error + mockClient.mock.ExpectedCalls = nil + mockClient.mock.On("Create", ctx, mock.Anything, mock.Anything).Return(fmt.Errorf("create error")) + + if operator.CheckResAuth(ctx, namespace, group, resource, verb) { + t.Errorf("Expected CheckResAuth to return false, but got true") + } +} + func assertCatalogSourceAndChannel(t *testing.T, catalogSourceName, expectedCatalogSourceName, catalogSourceNs, expectedCatalogSourceNs, availableChannel, expectedAvailableChannel string) { t.Helper() From 78df37065d1692ddec412b2e80fd0c9790b9165e Mon Sep 17 00:00:00 2001 From: Daniel Fan Date: Fri, 29 Nov 2024 19:22:28 -0500 Subject: [PATCH 160/179] Use SelfSubjectAccessReview to check ODLM's permission on getting catalog (#1100) Signed-off-by: Daniel Fan --- controllers/operator/manager.go | 13 ++++++------- controllers/operator/manager_test.go | 10 +++++----- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/controllers/operator/manager.go b/controllers/operator/manager.go index 6ecf4ae0..855542aa 100644 --- a/controllers/operator/manager.go +++ b/controllers/operator/manager.go @@ -174,7 +174,7 @@ func (m *ODLMOperator) GetCatalogSourceAndChannelFromPackage(ctx context.Context continue } - hasCatalogPermission := m.CheckResAuth(ctx, namespace, "operators.coreos.com", "catalogsources", "get") + hasCatalogPermission := m.CheckResAuth(ctx, pm.Status.CatalogSourceNamespace, "operators.coreos.com", "catalogsources", "get") if !hasCatalogPermission { klog.V(2).Infof("No permission to get CatalogSource %s in the namespace %s", pm.Status.CatalogSource, pm.Status.CatalogSourceNamespace) continue @@ -230,8 +230,8 @@ func (m *ODLMOperator) GetCatalogSourceAndChannelFromPackage(ctx context.Context } func (m *ODLMOperator) CheckResAuth(ctx context.Context, namespace, group, resource, verb string) bool { - sar := &authorizationv1.SubjectAccessReview{ - Spec: authorizationv1.SubjectAccessReviewSpec{ + sar := &authorizationv1.SelfSubjectAccessReview{ + Spec: authorizationv1.SelfSubjectAccessReviewSpec{ ResourceAttributes: &authorizationv1.ResourceAttributes{ Namespace: namespace, Group: group, @@ -241,14 +241,13 @@ func (m *ODLMOperator) CheckResAuth(ctx context.Context, namespace, group, resou }, } if err := m.Create(ctx, sar); err != nil { + klog.Errorf("Failed to check operator permission for Kind %s in namespace %s: %v", resource, namespace, err) return false } - if !sar.Status.Allowed { - return false - } + klog.V(2).Infof("Operator %s permission in namespace %s for Kind: %s, Allowed: %t, Denied: %t, Reason: %s", verb, namespace, resource, sar.Status.Allowed, sar.Status.Denied, sar.Status.Reason) - return true + return sar.Status.Allowed } func channelCheck(channelName string, channelList []operatorsv1.PackageChannel) bool { diff --git a/controllers/operator/manager_test.go b/controllers/operator/manager_test.go index 221469e3..d99dc98e 100644 --- a/controllers/operator/manager_test.go +++ b/controllers/operator/manager_test.go @@ -313,7 +313,7 @@ func TestGetCatalogSourceAndChannelFromPackage(t *testing.T) { } mockClient.mock.On("Create", ctx, mock.Anything, mock.Anything).Return(nil).Run(func(args mock.Arguments) { - sar := args.Get(1).(*authorizationv1.SubjectAccessReview) + sar := args.Get(1).(*authorizationv1.SelfSubjectAccessReview) sar.Status.Allowed = true }) @@ -434,9 +434,9 @@ func TestCheckResAuth(t *testing.T) { resource := "test-resource" verb := "get" - // Test when SubjectAccessReview is allowed + // Test when SelfSubjectAccessReview is allowed mockClient.mock.On("Create", ctx, mock.Anything, mock.Anything).Return(nil).Run(func(args mock.Arguments) { - sar := args.Get(1).(*authorizationv1.SubjectAccessReview) + sar := args.Get(1).(*authorizationv1.SelfSubjectAccessReview) sar.Status.Allowed = true }) @@ -444,10 +444,10 @@ func TestCheckResAuth(t *testing.T) { t.Errorf("Expected CheckResAuth to return true, but got false") } - // Test when SubjectAccessReview is not allowed + // Test when SelfSubjectAccessReview is not allowed mockClient.mock.ExpectedCalls = nil mockClient.mock.On("Create", ctx, mock.Anything, mock.Anything).Return(nil).Run(func(args mock.Arguments) { - sar := args.Get(1).(*authorizationv1.SubjectAccessReview) + sar := args.Get(1).(*authorizationv1.SelfSubjectAccessReview) sar.Status.Allowed = false }) From 511cb5a55ffb4479141a0d2a76ff9a542eedb1b7 Mon Sep 17 00:00:00 2001 From: Travis CI User Date: Mon, 9 Dec 2024 22:49:30 +0000 Subject: [PATCH 161/179] Trigger build with new base image --- base_images.json | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/base_images.json b/base_images.json index c7109111..93226383 100644 --- a/base_images.json +++ b/base_images.json @@ -3,11 +3,11 @@ "imageType": "external", "sourceRepo": "registry.access.redhat.com", "sourceNamespace": "ubi9", - "sourceImage": "ubi-micro", + "sourceImage": "ubi-minimal", "destStage": "edge", "destNamespace": "build-images", - "destImage": "ubi9-micro", - "tag": "9.5-1731519709", + "destImage": "ubi9-minimal", + "tag": "9.5-1731593028", "updatePackages": [] }, { @@ -18,32 +18,32 @@ "destStage": "edge", "destNamespace": "build-images", "destImage": "ubi9", - "tag": "9.5-1731517889", + "tag": "9.5-1732804088", "updatePackages": [] }, { "imageType": "external", "sourceRepo": "registry.access.redhat.com", "sourceNamespace": "ubi9", - "sourceImage": "ubi-minimal", + "sourceImage": "ubi-micro", "destStage": "edge", "destNamespace": "build-images", - "destImage": "ubi9-minimal", - "tag": "9.5-1731593028", + "destImage": "ubi9-micro", + "tag": "9.5-1733126338", "updatePackages": [] }, { "imageType": "node", "sourceImage": "ubi9-minimal", "sourceTag": "9.5-1731593028", - "destImage": "node-v18-ubi9-minimal", - "nodeVersion": "18.20.5" + "destImage": "node-v20-ubi9-minimal", + "nodeVersion": "20.18.1" }, { "imageType": "node", "sourceImage": "ubi9-minimal", "sourceTag": "9.5-1731593028", - "destImage": "node-v20-ubi9-minimal", - "nodeVersion": "20.18.0" + "destImage": "node-v22-ubi9-minimal", + "nodeVersion": "22.11.0" } ] From f1a67b7bec7a42ea807fc4623b1124e88ff0adb0 Mon Sep 17 00:00:00 2001 From: Allen Li <46284272+qpdpQ@users.noreply.github.com> Date: Tue, 10 Dec 2024 11:16:22 -0500 Subject: [PATCH 162/179] Bump version to 4.3.9 for CS 4.6.10 (#1102) Signed-off-by: Allen Li --- Makefile | 2 +- ...eployment-lifecycle-manager.clusterserviceversion.yaml | 8 ++++---- ...eployment-lifecycle-manager.clusterserviceversion.yaml | 4 ++-- version/version.go | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Makefile b/Makefile index a664e22e..d4496b8d 100644 --- a/Makefile +++ b/Makefile @@ -84,7 +84,7 @@ OPERATOR_IMAGE_NAME ?= odlm # Current Operator bundle image name BUNDLE_IMAGE_NAME ?= odlm-operator-bundle # Current Operator version -OPERATOR_VERSION ?= 4.3.8 +OPERATOR_VERSION ?= 4.3.9 # Kind cluster name KIND_CLUSTER_NAME ?= "odlm" diff --git a/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml b/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml index 085be9b4..738e739d 100644 --- a/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml +++ b/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml @@ -132,7 +132,7 @@ metadata: createdAt: "2024-09-28T19:55:35Z" description: The Operand Deployment Lifecycle Manager provides a Kubernetes CRD-based API to manage the lifecycle of operands. nss.operator.ibm.com/managed-operators: ibm-odlm - olm.skipRange: '>=1.2.0 <4.3.8' + olm.skipRange: '>=1.2.0 <4.3.9' operators.openshift.io/infrastructure-features: '["disconnected"]' operators.operatorframework.io/builder: operator-sdk-v1.32.0 operators.operatorframework.io/project_layout: go.kubebuilder.io/v3 @@ -143,7 +143,7 @@ metadata: operatorframework.io/arch.ppc64le: supported operatorframework.io/arch.s390x: supported operatorframework.io/os.linux: supported - name: operand-deployment-lifecycle-manager.v4.3.8 + name: operand-deployment-lifecycle-manager.v4.3.9 namespace: placeholder spec: apiservicedefinitions: {} @@ -868,7 +868,7 @@ spec: minKubeVersion: 1.19.0 provider: name: IBM - version: 4.3.8 + version: 4.3.9 relatedImages: - - image: icr.io/cpopen/odlm:4.3.8 + - image: icr.io/cpopen/odlm:4.3.9 name: ODLM_IMAGE diff --git a/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml b/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml index f92e9a77..0740a326 100644 --- a/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml +++ b/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml @@ -11,7 +11,7 @@ metadata: description: The Operand Deployment Lifecycle Manager provides a Kubernetes CRD-based API to manage the lifecycle of operands. nss.operator.ibm.com/managed-operators: ibm-odlm - olm.skipRange: '>=1.2.0 <4.3.8' + olm.skipRange: '>=1.2.0 <4.3.9' operators.openshift.io/infrastructure-features: '["disconnected"]' operators.operatorframework.io/builder: operator-sdk-v1.2.0 operators.operatorframework.io/project_layout: go.kubebuilder.io/v2 @@ -482,6 +482,6 @@ spec: provider: name: IBM relatedImages: - - image: icr.io/cpopen/odlm:4.3.8 + - image: icr.io/cpopen/odlm:4.3.9 name: ODLM_IMAGE version: 0.0.0 diff --git a/version/version.go b/version/version.go index b00044c8..57140a6d 100644 --- a/version/version.go +++ b/version/version.go @@ -17,5 +17,5 @@ package version var ( - Version = "4.3.8" + Version = "4.3.9" ) From b1408f84a4f7639f0e2b60807101e823e31ca374 Mon Sep 17 00:00:00 2001 From: Travis CI User Date: Mon, 6 Jan 2025 21:43:34 +0000 Subject: [PATCH 163/179] Trigger build with new base image --- base_images.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/base_images.json b/base_images.json index 93226383..00d825b7 100644 --- a/base_images.json +++ b/base_images.json @@ -7,7 +7,7 @@ "destStage": "edge", "destNamespace": "build-images", "destImage": "ubi9-minimal", - "tag": "9.5-1731593028", + "tag": "9.5-1734497536", "updatePackages": [] }, { @@ -18,7 +18,7 @@ "destStage": "edge", "destNamespace": "build-images", "destImage": "ubi9", - "tag": "9.5-1732804088", + "tag": "9.5-1734495538", "updatePackages": [] }, { @@ -29,21 +29,21 @@ "destStage": "edge", "destNamespace": "build-images", "destImage": "ubi9-micro", - "tag": "9.5-1733126338", + "tag": "9.5-1734513256", "updatePackages": [] }, { "imageType": "node", "sourceImage": "ubi9-minimal", - "sourceTag": "9.5-1731593028", + "sourceTag": "9.5-1734497536", "destImage": "node-v20-ubi9-minimal", "nodeVersion": "20.18.1" }, { "imageType": "node", "sourceImage": "ubi9-minimal", - "sourceTag": "9.5-1731593028", + "sourceTag": "9.5-1734497536", "destImage": "node-v22-ubi9-minimal", - "nodeVersion": "22.11.0" + "nodeVersion": "22.12.0" } ] From a61b000c6eede37afe224f2c25ccd271e36493e3 Mon Sep 17 00:00:00 2001 From: Travis CI User Date: Wed, 15 Jan 2025 19:25:28 +0000 Subject: [PATCH 164/179] Trigger build with new base image --- base_images.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/base_images.json b/base_images.json index 00d825b7..1d01ee81 100644 --- a/base_images.json +++ b/base_images.json @@ -7,7 +7,7 @@ "destStage": "edge", "destNamespace": "build-images", "destImage": "ubi9-minimal", - "tag": "9.5-1734497536", + "tag": "9.5-1736404155", "updatePackages": [] }, { @@ -18,7 +18,7 @@ "destStage": "edge", "destNamespace": "build-images", "destImage": "ubi9", - "tag": "9.5-1734495538", + "tag": "9.5-1736404036", "updatePackages": [] }, { @@ -29,21 +29,21 @@ "destStage": "edge", "destNamespace": "build-images", "destImage": "ubi9-micro", - "tag": "9.5-1734513256", + "tag": "9.5-1736426761", "updatePackages": [] }, { "imageType": "node", "sourceImage": "ubi9-minimal", - "sourceTag": "9.5-1734497536", + "sourceTag": "9.5-1736404155", "destImage": "node-v20-ubi9-minimal", "nodeVersion": "20.18.1" }, { "imageType": "node", "sourceImage": "ubi9-minimal", - "sourceTag": "9.5-1734497536", + "sourceTag": "9.5-1736404155", "destImage": "node-v22-ubi9-minimal", - "nodeVersion": "22.12.0" + "nodeVersion": "22.13.0" } ] From d7bf88ec8c74f7d91a0ab80b2770b2822c4e7e69 Mon Sep 17 00:00:00 2001 From: Daniel Fan Date: Mon, 20 Jan 2025 13:14:48 -0500 Subject: [PATCH 165/179] Check if Object is updated except certain label and annotations (#1104) * Check if Object is updated except certain label and annotations Signed-off-by: Daniel Fan * update test case to include more checks Signed-off-by: Daniel Fan * correct log info Signed-off-by: Daniel Fan * use Reader instead of Client to get ConfigMap/Secret that are referred Signed-off-by: Daniel Fan --------- Signed-off-by: Daniel Fan --- .../operandrequest_controller.go | 4 ++ .../operandrequest_controller_test.go | 52 +++++++++++++------ .../operandrequest/reconcile_operand.go | 2 +- controllers/operator/manager.go | 40 +++++++++++++- controllers/testutil/test_util.go | 2 +- 5 files changed, 81 insertions(+), 19 deletions(-) diff --git a/controllers/operandrequest/operandrequest_controller.go b/controllers/operandrequest/operandrequest_controller.go index 2af1f715..2804d1ca 100644 --- a/controllers/operandrequest/operandrequest_controller.go +++ b/controllers/operandrequest/operandrequest_controller.go @@ -376,6 +376,10 @@ func (r *Reconciler) SetupWithManager(mgr ctrl.Manager) error { return false }, UpdateFunc: func(e event.UpdateEvent) bool { + // If the object is not updated except the ODLMWatchedLabel label or ODLMReferenceAnnotation annotation, return false + if !r.ObjectIsUpdatedWithException(&e.ObjectOld, &e.ObjectNew) { + return false + } labels := e.ObjectNew.GetLabels() if labels != nil { if labelValue, ok := labels[constant.ODLMWatchedLabel]; ok && labelValue == "true" { diff --git a/controllers/operandrequest/operandrequest_controller_test.go b/controllers/operandrequest/operandrequest_controller_test.go index a63ad87d..71c15273 100644 --- a/controllers/operandrequest/operandrequest_controller_test.go +++ b/controllers/operandrequest/operandrequest_controller_test.go @@ -325,6 +325,13 @@ var _ = Describe("OperandRequest controller", func() { return err }, testutil.Timeout, testutil.Interval).Should(Succeed()) + By("Checking the status of first OperandRequest") + Eventually(func() operatorv1alpha1.ClusterPhase { + requestInstance1 := &operatorv1alpha1.OperandRequest{} + Expect(k8sClient.Get(ctx, requestKey1, requestInstance1)).Should(Succeed()) + return requestInstance1.Status.Phase + }, testutil.Timeout, testutil.Interval).Should(Equal(operatorv1alpha1.ClusterPhaseRunning)) + By("Disabling the jaeger operator from first OperandRequest") requestInstance1 := &operatorv1alpha1.OperandRequest{} Expect(k8sClient.Get(ctx, requestKey1, requestInstance1)).Should(Succeed()) @@ -338,6 +345,13 @@ var _ = Describe("OperandRequest controller", func() { return err }, testutil.Timeout, testutil.Interval).Should(Succeed()) + By("Checking the status of first OperandRequest after updating the Operand") + Eventually(func() operatorv1alpha1.ClusterPhase { + requestInstance1 := &operatorv1alpha1.OperandRequest{} + Expect(k8sClient.Get(ctx, requestKey1, requestInstance1)).Should(Succeed()) + return requestInstance1.Status.Phase + }, testutil.Timeout, testutil.Interval).Should(Equal(operatorv1alpha1.ClusterPhaseRunning)) + By("Disabling the jaeger operator from second OperandRequest") requestInstance2 := &operatorv1alpha1.OperandRequest{} Expect(k8sClient.Get(ctx, requestKey2, requestInstance2)).Should(Succeed()) @@ -351,20 +365,7 @@ var _ = Describe("OperandRequest controller", func() { return err != nil && errors.IsNotFound(err) }, testutil.Timeout, testutil.Interval).Should(BeTrue()) - By("Deleting the first OperandRequest") - Expect(k8sClient.Delete(ctx, request1)).Should(Succeed()) - - By("Checking mongodb operator has not been deleted") - Eventually(func() error { - mongodbCSV := &olmv1alpha1.ClusterServiceVersion{} - err := k8sClient.Get(ctx, types.NamespacedName{Name: "mongodb-atlas-kubernetes-csv.v0.0.1", Namespace: operatorNamespaceName}, mongodbCSV) - return err - }, testutil.Timeout, testutil.Interval).Should(Succeed()) - - By("Deleting the second OperandRequest") - Expect(k8sClient.Delete(ctx, request2)).Should(Succeed()) - - By("Checking the k8s resource has been deleted") + By("Checking jaeger k8s resource has been deleted") Eventually(func() bool { jaegerConfigMap := &corev1.ConfigMap{} err := k8sClient.Get(context.TODO(), types.NamespacedName{Name: "jaeger-configmap", Namespace: registryNamespaceName}, jaegerConfigMap) @@ -376,13 +377,34 @@ var _ = Describe("OperandRequest controller", func() { return err != nil && errors.IsNotFound(err) }, testutil.Timeout, testutil.Interval).Should(BeTrue()) - By("Checking operators have been deleted") + By("Checking jaeger operators have been deleted") Eventually(func() bool { jaegerCSV := &olmv1alpha1.ClusterServiceVersion{} err := k8sClient.Get(ctx, types.NamespacedName{Name: "jaeger-csv.v0.0.1", Namespace: operatorNamespaceName}, jaegerCSV) return err != nil && errors.IsNotFound(err) }, testutil.Timeout, testutil.Interval).Should(BeTrue()) + By("Checking the status of second OperandRequest after updating the Operand") + Eventually(func() operatorv1alpha1.ClusterPhase { + requestInstance2 := &operatorv1alpha1.OperandRequest{} + Expect(k8sClient.Get(ctx, requestKey2, requestInstance2)).Should(Succeed()) + return requestInstance2.Status.Phase + }, testutil.Timeout, testutil.Interval).Should(Equal(operatorv1alpha1.ClusterPhaseRunning)) + + By("Deleting the first OperandRequest") + Expect(k8sClient.Delete(ctx, request1)).Should(Succeed()) + + By("Checking mongodb operator has not been deleted") + Eventually(func() error { + mongodbCSV := &olmv1alpha1.ClusterServiceVersion{} + err := k8sClient.Get(ctx, types.NamespacedName{Name: "mongodb-atlas-kubernetes-csv.v0.0.1", Namespace: operatorNamespaceName}, mongodbCSV) + return err + }, testutil.Timeout, testutil.Interval).Should(Succeed()) + + By("Deleting the second OperandRequest") + Expect(k8sClient.Delete(ctx, request2)).Should(Succeed()) + + By("Checking the mongodb-atlas operator has been deleted") Eventually(func() bool { mongodbCSV := &olmv1alpha1.ClusterServiceVersion{} err := k8sClient.Get(ctx, types.NamespacedName{Name: "mongodb-atlas-kubernetes-csv.v0.0.1", Namespace: operatorNamespaceName}, mongodbCSV) diff --git a/controllers/operandrequest/reconcile_operand.go b/controllers/operandrequest/reconcile_operand.go index ed081821..128b856e 100644 --- a/controllers/operandrequest/reconcile_operand.go +++ b/controllers/operandrequest/reconcile_operand.go @@ -576,7 +576,7 @@ func (r *Reconciler) reconcileK8sResource(ctx context.Context, res operatorv1alp return err } } else { - klog.V(2).Infof("Skip the k8s resource %s/%s which is not created by ODLM", res.Kind, res.Name) + klog.V(2).Infof("Skip the k8s resource %s %s/%s whose force field is false", res.Kind, k8sResNs, res.Name) } } } else { diff --git a/controllers/operator/manager.go b/controllers/operator/manager.go index 855542aa..a99b554c 100644 --- a/controllers/operator/manager.go +++ b/controllers/operator/manager.go @@ -20,6 +20,7 @@ import ( "context" "encoding/json" "fmt" + "reflect" "sort" "strings" @@ -859,7 +860,7 @@ func (m *ODLMOperator) ParseObjectRef(ctx context.Context, obj *util.ObjectRef, func (m *ODLMOperator) GetValueRefFromConfigMap(ctx context.Context, instanceType, instanceName, instanceNs, cmName, cmNs, configMapKey string) (string, error) { cm := &corev1.ConfigMap{} - if err := m.Client.Get(ctx, types.NamespacedName{Name: cmName, Namespace: cmNs}, cm); err != nil { + if err := m.Reader.Get(ctx, types.NamespacedName{Name: cmName, Namespace: cmNs}, cm); err != nil { if apierrors.IsNotFound(err) { klog.V(2).Infof("Configmap %s/%s is not found", cmNs, cmName) return "", nil @@ -891,7 +892,7 @@ func (m *ODLMOperator) GetValueRefFromConfigMap(ctx context.Context, instanceTyp func (m *ODLMOperator) GetValueRefFromSecret(ctx context.Context, instanceType, instanceName, instanceNs, secretName, secretNs, secretKey string) (string, error) { secret := &corev1.Secret{} - if err := m.Client.Get(ctx, types.NamespacedName{Name: secretName, Namespace: secretNs}, secret); err != nil { + if err := m.Reader.Get(ctx, types.NamespacedName{Name: secretName, Namespace: secretNs}, secret); err != nil { if apierrors.IsNotFound(err) { klog.V(3).Infof("Secret %s/%s is not found", secretNs, secretName) return "", nil @@ -959,3 +960,38 @@ func (m *ODLMOperator) GetValueRefFromObject(ctx context.Context, instanceType, klog.V(2).Infof("Get value %s from %s %s/%s", sanitizedString, objKind, obj.GetNamespace(), obj.GetName()) return sanitizedString, nil } + +// ObjectIsUpdatedWithException checks if the object is updated except for the ODLMWatchedLabel and ODLMReferenceAnnotation +func (m *ODLMOperator) ObjectIsUpdatedWithException(oldObj, newObj *client.Object) bool { + oldObject := *oldObj + newObject := *newObj + + // Check if labels are the same except for ODLMWatchedLabel + oldLabels := oldObject.GetLabels() + newLabels := newObject.GetLabels() + if oldLabels != nil && newLabels != nil { + delete(oldLabels, constant.ODLMWatchedLabel) + delete(newLabels, constant.ODLMWatchedLabel) + } + if !reflect.DeepEqual(oldLabels, newLabels) { + return true + } + + // Check if annotations are the same except for ODLMReferenceAnnotation + oldAnnotations := oldObject.GetAnnotations() + newAnnotations := newObject.GetAnnotations() + if oldAnnotations != nil && newAnnotations != nil { + delete(oldAnnotations, constant.ODLMReferenceAnnotation) + delete(newAnnotations, constant.ODLMReferenceAnnotation) + } + if !reflect.DeepEqual(oldAnnotations, newAnnotations) { + return true + } + + // Check if other parts of the object are unchanged + oldObject.SetLabels(nil) + oldObject.SetAnnotations(nil) + newObject.SetLabels(nil) + newObject.SetAnnotations(nil) + return !reflect.DeepEqual(oldObject, newObject) +} diff --git a/controllers/testutil/test_util.go b/controllers/testutil/test_util.go index 4eddc18e..c79c6e2a 100644 --- a/controllers/testutil/test_util.go +++ b/controllers/testutil/test_util.go @@ -200,7 +200,7 @@ func OperandConfigObj(name, namespace string) *apiv1alpha1.OperandConfig { } }`), }, - Force: false, + Force: true, }, }, }, From 2512f44f72b8b743e3fdfc1702ac8fc6c5fb5798 Mon Sep 17 00:00:00 2001 From: Piotr Godowski Date: Tue, 21 Jan 2025 21:35:51 +0100 Subject: [PATCH 166/179] add required OLM metadata (#1103) * add required OLM metadata ..as defined in https://docs.redhat.com/en/documentation/red_hat_software_certification/2024/html-single/red_hat_openshift_software_certification_policy_guide/index#con-operator-requirements_openshift-sw-cert-policy-products-managed and required by RH Certification * update the base file --------- Co-authored-by: Piotr Godowski --- ...deployment-lifecycle-manager.clusterserviceversion.yaml | 7 +++++++ ...deployment-lifecycle-manager.clusterserviceversion.yaml | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml b/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml index 738e739d..57506a00 100644 --- a/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml +++ b/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml @@ -138,6 +138,13 @@ metadata: operators.operatorframework.io/project_layout: go.kubebuilder.io/v3 repository: https://github.com/IBM/operand-deployment-lifecycle-manager support: IBM + features.operators.openshift.io/disconnected: "true" + features.operators.openshift.io/fips-compliant: "true" + features.operators.openshift.io/proxy-aware: "false" + features.operators.openshift.io/tls-profiles: "false" + features.operators.openshift.io/token-auth-aws: "false" + features.operators.openshift.io/token-auth-azure: "false" + features.operators.openshift.io/token-auth-gcp: "false" labels: operatorframework.io/arch.amd64: supported operatorframework.io/arch.ppc64le: supported diff --git a/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml b/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml index 0740a326..fc966d91 100644 --- a/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml +++ b/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml @@ -17,6 +17,13 @@ metadata: operators.operatorframework.io/project_layout: go.kubebuilder.io/v2 repository: https://github.com/IBM/operand-deployment-lifecycle-manager support: IBM + features.operators.openshift.io/disconnected: "true" + features.operators.openshift.io/fips-compliant: "true" + features.operators.openshift.io/proxy-aware: "false" + features.operators.openshift.io/tls-profiles: "false" + features.operators.openshift.io/token-auth-aws: "false" + features.operators.openshift.io/token-auth-azure: "false" + features.operators.openshift.io/token-auth-gcp: "false" labels: operatorframework.io/arch.amd64: supported operatorframework.io/arch.ppc64le: supported From 2ca6b1181565a23d2c0d7daacc9711c36f217c9d Mon Sep 17 00:00:00 2001 From: Travis CI User Date: Mon, 27 Jan 2025 16:35:48 +0000 Subject: [PATCH 167/179] Trigger build with new base image --- base_images.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/base_images.json b/base_images.json index 1d01ee81..a4b990e3 100644 --- a/base_images.json +++ b/base_images.json @@ -37,13 +37,13 @@ "sourceImage": "ubi9-minimal", "sourceTag": "9.5-1736404155", "destImage": "node-v20-ubi9-minimal", - "nodeVersion": "20.18.1" + "nodeVersion": "20.18.2" }, { "imageType": "node", "sourceImage": "ubi9-minimal", "sourceTag": "9.5-1736404155", "destImage": "node-v22-ubi9-minimal", - "nodeVersion": "22.13.0" + "nodeVersion": "22.13.1" } ] From 32664c5228457d654bb507fb505bce2ca6240e5c Mon Sep 17 00:00:00 2001 From: Ben Luzarraga <31223504+bluzarraga@users.noreply.github.com> Date: Wed, 29 Jan 2025 16:31:57 -0600 Subject: [PATCH 168/179] update net to 0.33 (#1107) Signed-off-by: Ben Luzarraga --- go.mod | 10 +++++----- go.sum | 24 ++++++++++++------------ 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/go.mod b/go.mod index 8548e7a6..e0b7b60b 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,7 @@ require ( github.com/operator-framework/operator-lifecycle-manager v0.17.0 github.com/pkg/errors v0.9.1 github.com/stretchr/testify v1.9.0 - golang.org/x/mod v0.8.0 + golang.org/x/mod v0.17.0 k8s.io/api v0.24.3 k8s.io/apimachinery v0.24.17 k8s.io/client-go v0.24.3 @@ -85,11 +85,11 @@ require ( go.uber.org/atomic v1.7.0 // indirect go.uber.org/multierr v1.6.0 // indirect go.uber.org/zap v1.19.1 // indirect - golang.org/x/net v0.23.0 // indirect + golang.org/x/net v0.33.0 // indirect golang.org/x/oauth2 v0.11.0 // indirect - golang.org/x/sys v0.18.0 // indirect - golang.org/x/term v0.18.0 // indirect - golang.org/x/text v0.14.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/term v0.27.0 // indirect + golang.org/x/text v0.21.0 // indirect golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect google.golang.org/appengine v1.6.7 // indirect diff --git a/go.sum b/go.sum index 88adc21f..62405276 100644 --- a/go.sum +++ b/go.sum @@ -1108,8 +1108,8 @@ golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/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.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= -golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8= -golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1172,8 +1172,8 @@ golang.org/x/net v0.0.0-20210825183410-e898025ed96a/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= -golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= +golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= +golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1202,8 +1202,8 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/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.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= -golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= +golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1298,12 +1298,12 @@ golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= -golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= +golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8= -golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= +golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q= +golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1314,8 +1314,8 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= From 020bc452f74624143bd8a42b06cd13ef93295654 Mon Sep 17 00:00:00 2001 From: Ben Luzarraga <31223504+bluzarraga@users.noreply.github.com> Date: Thu, 30 Jan 2025 12:01:55 -0600 Subject: [PATCH 169/179] prototype ODLM w/o olm (#1105) * poc for demo Signed-off-by: Ben Luzarraga * translate csv to deployment Signed-off-by: Ben Luzarraga * facilitate test builds Signed-off-by: Ben Luzarraga * build debugging Signed-off-by: Ben Luzarraga * debug statement Signed-off-by: Ben Luzarraga * bump version Signed-off-by: Ben Luzarraga * debug statement Signed-off-by: Ben Luzarraga * debug statement Signed-off-by: Ben Luzarraga * troubleshooting Signed-off-by: Ben Luzarraga * troubleshooting Signed-off-by: Ben Luzarraga * troubleshooting Signed-off-by: Ben Luzarraga * preliminary changes for odlm delete operands Signed-off-by: Ben Luzarraga * remove test files from noolm controller Signed-off-by: Ben Luzarraga * refactor some cleanup code Signed-off-by: Ben Luzarraga --------- Signed-off-by: Ben Luzarraga --- Makefile | 4 +- .../operandrequestnoolm_controller.go | 439 +++++ .../operandrequestnoolm/reconcile_operand.go | 1657 +++++++++++++++++ .../operandrequestnoolm/reconcile_operator.go | 783 ++++++++ controllers/operator/manager.go | 42 + controllers/util/util.go | 9 + main.go | 24 +- 7 files changed, 2950 insertions(+), 8 deletions(-) create mode 100644 controllers/operandrequestnoolm/operandrequestnoolm_controller.go create mode 100644 controllers/operandrequestnoolm/reconcile_operand.go create mode 100644 controllers/operandrequestnoolm/reconcile_operator.go diff --git a/Makefile b/Makefile index d4496b8d..e0c488cb 100644 --- a/Makefile +++ b/Makefile @@ -65,7 +65,7 @@ else endif # Default image repo -QUAY_REGISTRY ?= quay.io/opencloudio +QUAY_REGISTRY ?= quay.io/luzarragaben ifeq ($(BUILD_LOCALLY),0) ARTIFACTORYA_REGISTRY ?= "docker-na-public.artifactory.swg-devops.com/hyc-cloud-private-integration-docker-local/ibmcom" @@ -89,7 +89,7 @@ OPERATOR_VERSION ?= 4.3.9 # Kind cluster name KIND_CLUSTER_NAME ?= "odlm" # Operator image tag for test -OPERATOR_TEST_TAG ?= dev-test +OPERATOR_TEST_TAG ?= nolm-controller3 # Options for 'bundle-build' ifneq ($(origin CHANNELS), undefined) diff --git a/controllers/operandrequestnoolm/operandrequestnoolm_controller.go b/controllers/operandrequestnoolm/operandrequestnoolm_controller.go new file mode 100644 index 00000000..86b7d1ad --- /dev/null +++ b/controllers/operandrequestnoolm/operandrequestnoolm_controller.go @@ -0,0 +1,439 @@ +// +// Copyright 2022 IBM Corporation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package operandrequestnoolm + +import ( + "context" + "fmt" + "reflect" + "regexp" + "strings" + "sync" + "time" + + gset "github.com/deckarep/golang-set" + olmv1 "github.com/operator-framework/api/pkg/operators/v1" + olmv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1" + "github.com/pkg/errors" + authorizationv1 "k8s.io/api/authorization/v1" + corev1 "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/types" + utilerrors "k8s.io/apimachinery/pkg/util/errors" + "k8s.io/klog" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/builder" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller" + "sigs.k8s.io/controller-runtime/pkg/event" + "sigs.k8s.io/controller-runtime/pkg/handler" + "sigs.k8s.io/controller-runtime/pkg/predicate" + "sigs.k8s.io/controller-runtime/pkg/source" + + operatorv1alpha1 "github.com/IBM/operand-deployment-lifecycle-manager/v4/api/v1alpha1" + "github.com/IBM/operand-deployment-lifecycle-manager/v4/controllers/constant" + deploy "github.com/IBM/operand-deployment-lifecycle-manager/v4/controllers/operator" +) + +// Reconciler reconciles a OperandRequest object +type Reconciler struct { + *deploy.ODLMOperator + StepSize int + Mutex sync.Mutex +} +type clusterObjects struct { + namespace *corev1.Namespace + operatorGroup *olmv1.OperatorGroup + subscription *olmv1alpha1.Subscription +} + +//+kubebuilder:rbac:groups=operator.ibm.com,resources=certmanagers;auditloggings,verbs=get;delete +//+kubebuilder:rbac:groups=operators.coreos.com,resources=catalogsources,verbs=get +//+kubebuilder:rbac:groups=apiextensions.k8s.io,resources=customresourcedefinitions,verbs=get + +//+kubebuilder:rbac:groups=*,namespace="placeholder",resources=*,verbs=create;delete;get;list;patch;update;watch +//+kubebuilder:rbac:groups=operator.ibm.com,namespace="placeholder",resources=operandrequests;operandrequests/status;operandrequests/finalizers,verbs=get;list;watch;create;update;patch;delete +//+kubebuilder:rbac:groups="",namespace="placeholder",resources=configmaps;secrets;services;namespaces,verbs=create;delete;get;list;patch;update;watch +//+kubebuilder:rbac:groups=route.openshift.io,namespace="placeholder",resources=routes,verbs=create;delete;get;list;patch;update;watch +//+kubebuilder:rbac:groups=operators.coreos.com,namespace="placeholder",resources=operatorgroups;installplans,verbs=create;delete;get;list;patch;update;watch +//+kubebuilder:rbac:groups=k8s.keycloak.org,namespace="placeholder",resources=keycloaks;keycloakrealmimports,verbs=create;delete;get;list;patch;update;watch +//+kubebuilder:rbac:groups=packages.operators.coreos.com,namespace="placeholder",resources=packagemanifests,verbs=get;list;patch;update;watch +//+kubebuilder:rbac:groups=operators.coreos.com,namespace="placeholder",resources=clusterserviceversions;subscriptions,verbs=create;delete;get;list;patch;update;watch + +// Reconcile reads that state of the cluster for a OperandRequest object and makes changes based on the state read +// and what is in the OperandRequest.Spec +// Note: +// The Controller will requeue the Request to be processed again if the returned error is non-nil or +// Result.Requeue is true, otherwise upon completion it will remove the work from the queue. +func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctrl.Result, reconcileErr error) { + // Fetch the OperandRequest instance + requestInstance := &operatorv1alpha1.OperandRequest{} + if err := r.Client.Get(ctx, req.NamespacedName, requestInstance); err != nil { + // Error reading the object - requeue the request. + return ctrl.Result{}, client.IgnoreNotFound(err) + } + + originalInstance := requestInstance.DeepCopy() + + // Always attempt to patch the status after each reconciliation. + defer func() { + // get the latest instance from the server and check if the status has changed + existingInstance := &operatorv1alpha1.OperandRequest{} + if err := r.Client.Get(ctx, req.NamespacedName, existingInstance); err != nil && !apierrors.IsNotFound(err) { + // Error reading the latest object - requeue the request. + reconcileErr = utilerrors.NewAggregate([]error{reconcileErr, fmt.Errorf("error while get latest OperandRequest.Status from server: %v", err)}) + } + + if reflect.DeepEqual(existingInstance.Status, requestInstance.Status) { + return + } + + // Update requestInstance's resource version to avoid conflicts + requestInstance.ResourceVersion = existingInstance.ResourceVersion + if err := r.Client.Status().Patch(ctx, requestInstance, client.MergeFrom(existingInstance)); err != nil && !apierrors.IsNotFound(err) { + reconcileErr = utilerrors.NewAggregate([]error{reconcileErr, fmt.Errorf("error while patching OperandRequest.Status: %v", err)}) + } + if reconcileErr != nil { + klog.Errorf("failed to patch status for OperandRequest %s: %v", req.NamespacedName.String(), reconcileErr) + } + }() + + // Remove finalizer when DeletionTimestamp none zero + if !requestInstance.ObjectMeta.DeletionTimestamp.IsZero() { + //TODO determine if necessary + // Check and clean up the subscriptions + // err := r.checkFinalizer(ctx, requestInstance) + // if err != nil { + // klog.Errorf("failed to clean up the subscriptions for OperandRequest %s: %v", req.NamespacedName.String(), err) + // return ctrl.Result{}, err + // } + + originalReq := requestInstance.DeepCopy() + // Update finalizer to allow delete CR + if requestInstance.RemoveFinalizer() { + err := r.Patch(ctx, requestInstance, client.MergeFrom(originalReq)) + if err != nil { + klog.Errorf("failed to remove finalizer for OperandRequest %s: %v", req.NamespacedName.String(), err) + return ctrl.Result{}, client.IgnoreNotFound(err) + } + } + return ctrl.Result{}, nil + } + + // Check if operator has the update permission to update OperandRequest + hasPermission := r.checkPermission(ctx, req) + if !hasPermission { + klog.Warningf("No permission to update OperandRequest") + return ctrl.Result{RequeueAfter: 3 * time.Second}, nil + } + + klog.V(1).Infof("Reconciling OperandRequest: %s", req.NamespacedName) + // Update labels for the request + if requestInstance.UpdateLabels() { + if err := r.Patch(ctx, requestInstance, client.MergeFrom(originalInstance)); err != nil { + klog.Errorf("failed to update the labels for OperandRequest %s: %v", req.NamespacedName.String(), err) + return ctrl.Result{}, err + } + } + + // Initialize the status for OperandRequest instance + if !requestInstance.InitRequestStatus(&r.Mutex) { + return ctrl.Result{Requeue: true}, nil + } + + // Add finalizer to the instance + if isAdded, err := r.addFinalizer(ctx, requestInstance); err != nil { + klog.Errorf("failed to add finalizer for OperandRequest %s: %v", req.NamespacedName.String(), err) + return ctrl.Result{}, err + } else if !isAdded { + return ctrl.Result{Requeue: true}, err + } + + // TODO remove this section + // Reconcile Operators + // if err := r.reconcileOperator(ctx, requestInstance); err != nil { + // klog.Errorf("failed to reconcile Operators for OperandRequest %s: %v", req.NamespacedName.String(), err) + // return ctrl.Result{}, err + // } + + // Reconcile Operands + if merr := r.reconcileOperand(ctx, requestInstance); len(merr.Errors) != 0 { + klog.Errorf("failed to reconcile Operands for OperandRequest %s: %v", req.NamespacedName.String(), merr) + return ctrl.Result{}, merr + } + + // Check if all csv deploy succeed + if requestInstance.Status.Phase != operatorv1alpha1.ClusterPhaseRunning { + klog.V(2).Info("Waiting for all operators and operands to be deployed successfully ...") + return ctrl.Result{RequeueAfter: constant.DefaultRequeueDuration}, nil + } + + //check if status.services is present (if a relevant service was requested), requeue again if service is not ready yet + if isReady, err := r.ServiceStatusIsReady(ctx, requestInstance); !isReady || err != nil { + return ctrl.Result{RequeueAfter: constant.DefaultRequeueDuration}, nil + } + + klog.V(1).Infof("Finished reconciling OperandRequest: %s", req.NamespacedName) + return ctrl.Result{RequeueAfter: constant.DefaultSyncPeriod}, reconcileErr +} + +func (r *Reconciler) checkPermission(ctx context.Context, req ctrl.Request) bool { + // Check update permission + if !r.checkUpdateAuth(ctx, req.Namespace, "operator.ibm.com", "operandrequests") { + return false + } + if !r.checkUpdateAuth(ctx, req.Namespace, "operator.ibm.com", "operandrequests/status") { + return false + } + return true +} + +// Check if operator has permission to update OperandRequest +func (r *Reconciler) checkUpdateAuth(ctx context.Context, namespace, group, resource string) bool { + sar := &authorizationv1.SelfSubjectAccessReview{ + Spec: authorizationv1.SelfSubjectAccessReviewSpec{ + ResourceAttributes: &authorizationv1.ResourceAttributes{ + Namespace: namespace, + Verb: "update", + Group: group, + Resource: resource, + }, + }, + } + + if err := r.Create(ctx, sar); err != nil { + klog.Errorf("Failed to check operator update permission: %v", err) + return false + } + + klog.V(3).Infof("Operator update permission in namespace %s, Allowed: %t, Denied: %t, Reason: %s", namespace, sar.Status.Allowed, sar.Status.Denied, sar.Status.Reason) + return sar.Status.Allowed +} + +func (r *Reconciler) addFinalizer(ctx context.Context, cr *operatorv1alpha1.OperandRequest) (bool, error) { + if cr.GetDeletionTimestamp() == nil { + originalReq := cr.DeepCopy() + added := cr.EnsureFinalizer() + if added { + // Add finalizer to OperandRequest instance + err := r.Patch(ctx, cr, client.MergeFrom(originalReq)) + if err != nil { + return false, errors.Wrapf(err, "failed to update the OperandRequest %s/%s", cr.Namespace, cr.Name) + } + return false, nil + } + } + return true, nil +} + +func (r *Reconciler) checkFinalizer(ctx context.Context, requestInstance *operatorv1alpha1.OperandRequest) error { + klog.V(1).Infof("Deleting OperandRequest %s in the namespace %s", requestInstance.Name, requestInstance.Namespace) + remainingOperands := gset.NewSet() + for _, m := range requestInstance.Status.Members { + remainingOperands.Add(m.Name) + } + // TODO: update to check OperandRequest status to see if member is user managed or not + // existingSub := &olmv1alpha1.SubscriptionList{} + + // opts := []client.ListOption{ + // client.MatchingLabels(map[string]string{constant.OpreqLabel: "true"}), + // } + + // if err := r.Client.List(ctx, existingSub, opts...); err != nil { + // return err + // } + // if len(existingSub.Items) == 0 { + // return nil + // } + // Delete all the subscriptions that created by current request + if err := r.absentOperatorsAndOperands(ctx, requestInstance, &remainingOperands); err != nil { + return err + } + return nil +} + +func (r *Reconciler) getRegistryToRequestMapper() handler.MapFunc { + ctx := context.Background() + return func(object client.Object) []ctrl.Request { + requestList, _ := r.ListOperandRequestsByRegistry(ctx, types.NamespacedName{Namespace: object.GetNamespace(), Name: object.GetName()}) + + requests := []ctrl.Request{} + for _, request := range requestList { + namespaceName := types.NamespacedName{Name: request.Name, Namespace: request.Namespace} + req := ctrl.Request{NamespacedName: namespaceName} + requests = append(requests, req) + } + return requests + } +} + +func (r *Reconciler) getSubToRequestMapper() handler.MapFunc { + return func(object client.Object) []ctrl.Request { + reg, _ := regexp.Compile(`^(.*)\.(.*)\.(.*)\/request`) + annotations := object.GetAnnotations() + var reqName, reqNamespace string + for annotation := range annotations { + if reg.MatchString(annotation) { + annotationSlices := strings.Split(annotation, ".") + reqNamespace = annotationSlices[0] + reqName = annotationSlices[1] + } + } + if reqNamespace == "" || reqName == "" { + return []ctrl.Request{} + } + return []ctrl.Request{ + {NamespacedName: types.NamespacedName{ + Name: reqName, + Namespace: reqNamespace, + }}, + } + } +} + +func (r *Reconciler) getConfigToRequestMapper() handler.MapFunc { + ctx := context.Background() + return func(object client.Object) []ctrl.Request { + requestList, _ := r.ListOperandRequestsByConfig(ctx, types.NamespacedName{Namespace: object.GetNamespace(), Name: object.GetName()}) + + requests := []ctrl.Request{} + for _, request := range requestList { + namespaceName := types.NamespacedName{Name: request.Name, Namespace: request.Namespace} + req := ctrl.Request{NamespacedName: namespaceName} + requests = append(requests, req) + } + return requests + } +} + +func (r *Reconciler) getReferenceToRequestMapper() handler.MapFunc { + ctx := context.Background() + return func(object client.Object) []ctrl.Request { + annotations := object.GetAnnotations() + if annotations == nil { + return []ctrl.Request{} + } + odlmReference, ok := annotations[constant.ODLMReferenceAnnotation] + if !ok { + return []ctrl.Request{} + } + odlmReferenceSlices := strings.Split(odlmReference, ".") + if len(odlmReferenceSlices) != 3 { + return []ctrl.Request{} + } + + var requestList []operatorv1alpha1.OperandRequest + if odlmReferenceSlices[0] == "OperandConfig" { + requestList, _ = r.ListOperandRequestsByConfig(ctx, types.NamespacedName{Namespace: odlmReferenceSlices[1], Name: odlmReferenceSlices[2]}) + } else if odlmReferenceSlices[0] == "OperandRegistry" { + requestList, _ = r.ListOperandRequestsByRegistry(ctx, types.NamespacedName{Namespace: odlmReferenceSlices[1], Name: odlmReferenceSlices[2]}) + } else { + return []ctrl.Request{} + } + + requests := []ctrl.Request{} + for _, request := range requestList { + namespaceName := types.NamespacedName{Name: request.Name, Namespace: request.Namespace} + req := ctrl.Request{NamespacedName: namespaceName} + requests = append(requests, req) + } + return requests + } +} + +// SetupWithManager adds OperandRequest controller to the manager. +func (r *Reconciler) SetupWithManager(mgr ctrl.Manager) error { + options := controller.Options{ + MaxConcurrentReconciles: r.MaxConcurrentReconciles, // Set the desired value for max concurrent reconciles. + } + ReferencePredicates := predicate.Funcs{ + CreateFunc: func(e event.CreateEvent) bool { + labels := e.Object.GetLabels() + // only return true when both conditions are met at the same time: + // 1. label contain key "constant.ODLMWatchedLabel" and value is true + // 2. label does not contain key "constant.OpbiTypeLabel" with value "copy" + if labels != nil { + if labelValue, ok := labels[constant.ODLMWatchedLabel]; ok && labelValue == "true" { + if labelValue, ok := labels[constant.OpbiTypeLabel]; ok && labelValue == "copy" { + return false + } + return true + } + } + return false + }, + UpdateFunc: func(e event.UpdateEvent) bool { + labels := e.ObjectNew.GetLabels() + if labels != nil { + if labelValue, ok := labels[constant.ODLMWatchedLabel]; ok && labelValue == "true" { + if labelValue, ok := labels[constant.OpbiTypeLabel]; ok && labelValue == "copy" { + return false + } + return true + } + } + return false + }, + DeleteFunc: func(e event.DeleteEvent) bool { + return true + }, + } + return ctrl.NewControllerManagedBy(mgr). + WithOptions(options). + For(&operatorv1alpha1.OperandRequest{}, builder.WithPredicates(predicate.GenerationChangedPredicate{})). + Watches(&source.Kind{Type: &olmv1alpha1.Subscription{}}, handler.EnqueueRequestsFromMapFunc(r.getSubToRequestMapper()), builder.WithPredicates(predicate.Funcs{ + UpdateFunc: func(e event.UpdateEvent) bool { + oldObject := e.ObjectOld.(*olmv1alpha1.Subscription) + newObject := e.ObjectNew.(*olmv1alpha1.Subscription) + if oldObject.Labels != nil && oldObject.Labels[constant.OpreqLabel] == "true" { + statusToggle := (oldObject.Status.InstalledCSV != "" && newObject.Status.InstalledCSV != "" && oldObject.Status.InstalledCSV != newObject.Status.InstalledCSV) + metadataToggle := !reflect.DeepEqual(oldObject.Annotations, newObject.Annotations) + return statusToggle || metadataToggle + } + return false + }, + DeleteFunc: func(e event.DeleteEvent) bool { + // Evaluates to false if the object has been confirmed deleted. + return false + }, + })). + Watches(&source.Kind{Type: &operatorv1alpha1.OperandRegistry{}}, handler.EnqueueRequestsFromMapFunc(r.getRegistryToRequestMapper()), builder.WithPredicates(predicate.Funcs{ + UpdateFunc: func(e event.UpdateEvent) bool { + oldObject := e.ObjectOld.(*operatorv1alpha1.OperandRegistry) + newObject := e.ObjectNew.(*operatorv1alpha1.OperandRegistry) + return !reflect.DeepEqual(oldObject.Spec, newObject.Spec) || !reflect.DeepEqual(oldObject.GetAnnotations(), newObject.GetAnnotations()) + }, + DeleteFunc: func(e event.DeleteEvent) bool { + // Evaluates to false if the object has been confirmed deleted. + return !e.DeleteStateUnknown + }, + })). + Watches(&source.Kind{Type: &operatorv1alpha1.OperandConfig{}}, handler.EnqueueRequestsFromMapFunc(r.getConfigToRequestMapper()), builder.WithPredicates(predicate.Funcs{ + DeleteFunc: func(e event.DeleteEvent) bool { + // Evaluates to false if the object has been confirmed deleted. + return !e.DeleteStateUnknown + }, + UpdateFunc: func(e event.UpdateEvent) bool { + oldObject := e.ObjectOld.(*operatorv1alpha1.OperandConfig) + newObject := e.ObjectNew.(*operatorv1alpha1.OperandConfig) + return !reflect.DeepEqual(oldObject.Spec, newObject.Spec) + }, + })). + Watches(&source.Kind{Type: &corev1.ConfigMap{}}, handler.EnqueueRequestsFromMapFunc(r.getReferenceToRequestMapper()), builder.WithPredicates(ReferencePredicates)). + Watches(&source.Kind{Type: &corev1.Secret{}}, handler.EnqueueRequestsFromMapFunc(r.getReferenceToRequestMapper()), builder.WithPredicates(ReferencePredicates)). + Complete(r) +} diff --git a/controllers/operandrequestnoolm/reconcile_operand.go b/controllers/operandrequestnoolm/reconcile_operand.go new file mode 100644 index 00000000..2fe2a9bf --- /dev/null +++ b/controllers/operandrequestnoolm/reconcile_operand.go @@ -0,0 +1,1657 @@ +// +// Copyright 2022 IBM Corporation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package operandrequestnoolm + +import ( + "context" + "crypto/sha256" + "encoding/hex" + "encoding/json" + "fmt" + "strconv" + "strings" + "sync" + "time" + + "github.com/pkg/errors" + appsv1 "k8s.io/api/apps/v1" + authorizationv1 "k8s.io/api/authorization/v1" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/equality" + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/api/meta" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + runtime "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/client-go/discovery" + "k8s.io/klog" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + + operatorv1alpha1 "github.com/IBM/operand-deployment-lifecycle-manager/v4/api/v1alpha1" + constant "github.com/IBM/operand-deployment-lifecycle-manager/v4/controllers/constant" + util "github.com/IBM/operand-deployment-lifecycle-manager/v4/controllers/util" +) + +func (r *Reconciler) reconcileOperand(ctx context.Context, requestInstance *operatorv1alpha1.OperandRequest) *util.MultiErr { + klog.V(1).Infof("Reconciling Operands for OperandRequest: %s/%s", requestInstance.GetNamespace(), requestInstance.GetName()) + // Update request status + defer func() { + requestInstance.UpdateClusterPhase() + }() + + merr := &util.MultiErr{} + if err := r.checkCustomResource(ctx, requestInstance); err != nil { + merr.Add(err) + return merr + } + for _, req := range requestInstance.Spec.Requests { + registryKey := requestInstance.GetRegistryKey(req) + registryInstance, err := r.GetOperandRegistry(ctx, registryKey) + if err != nil { + merr.Add(errors.Wrapf(err, "failed to get the OperandRegistry %s", registryKey.String())) + continue + } + + for i, operand := range req.Operands { + + opdRegistry, err := r.GetOperandFromRegistry(ctx, registryInstance, operand.Name) + if err != nil { + klog.Warningf("Failed to get the Operand %s from the OperandRegistry %s", operand.Name, registryKey.String()) + merr.Add(errors.Wrapf(err, "failed to get the Operand %s from the OperandRegistry %s", operand.Name, registryKey.String())) + continue + } else if opdRegistry == nil { + klog.Warningf("Cannot find %s in the OperandRegistry instance %s in the namespace %s ", operand.Name, req.Registry, req.RegistryNamespace) + requestInstance.SetMemberStatus(operand.Name, operatorv1alpha1.OperatorNotFound, operatorv1alpha1.ServiceNotFound, &r.Mutex) + continue + } + + // Set no-op operator to Running status + if opdRegistry.InstallMode == operatorv1alpha1.InstallModeNoop { + requestInstance.SetNoSuitableRegistryCondition(registryKey.String(), opdRegistry.Name+" is in maintenance status", operatorv1alpha1.ResourceTypeOperandRegistry, corev1.ConditionTrue, &r.Mutex) + requestInstance.SetMemberStatus(operand.Name, operatorv1alpha1.OperatorRunning, operatorv1alpha1.ServiceRunning, &r.Mutex) + continue + } + + operatorName := opdRegistry.Name + + klog.V(1).Info("Looking for deployment for the operator: ", operatorName) + + // Looking for the CSV + namespace := r.GetOperatorNamespace(opdRegistry.InstallMode, opdRegistry.Namespace) + + //TODO remove this section + // sub, err := r.GetSubscription(ctx, operatorName, namespace, registryInstance.Namespace, opdRegistry.PackageName) + // if err != nil { + // merr.Add(errors.Wrapf(err, "failed to get the Subscription %s in the namespace %s and %s", operatorName, namespace, registryInstance.Namespace)) + // return merr + // } + + // if !opdRegistry.UserManaged { + // if sub == nil { + // klog.Warningf("There is no Subscription %s or %s in the namespace %s and %s", operatorName, opdRegistry.PackageName, namespace, registryInstance.Namespace) + // continue + // } + + // if _, ok := sub.Labels[constant.OpreqLabel]; !ok { + // // Subscription existing and not managed by OperandRequest controller + // klog.Warningf("Subscription %s in the namespace %s isn't created by ODLM", sub.Name, sub.Namespace) + // } + + // // It the installplan is not created yet, ODLM will try later + // if sub.Status.Install == nil || sub.Status.InstallPlanRef.Name == "" { + // klog.Warningf("The Installplan for Subscription %s is not ready. Will check it again", sub.Name) + // requestInstance.SetMemberStatus(operand.Name, operatorv1alpha1.OperatorInstalling, "", &r.Mutex) + // continue + // } + + // // If the installplan is deleted after is completed, ODLM won't block the CR update. + // ipName := sub.Status.InstallPlanRef.Name + // ipNamespace := sub.Namespace + // ip := &olmv1alpha1.InstallPlan{} + // ipKey := types.NamespacedName{ + // Name: ipName, + // Namespace: ipNamespace, + // } + // if err := r.Client.Get(ctx, ipKey, ip); err != nil { + // if !apierrors.IsNotFound(err) { + // merr.Add(errors.Wrapf(err, "failed to get Installplan")) + // } + // } else if ip.Status.Phase == olmv1alpha1.InstallPlanPhaseFailed { + // klog.Errorf("installplan %s/%s is failed", ipNamespace, ipName) + // requestInstance.SetMemberStatus(operand.Name, operatorv1alpha1.OperatorFailed, "", &r.Mutex) + // continue + // } + + // } + + //var csv *olmv1alpha1.ClusterServiceVersion + var deployment *appsv1.Deployment + + //TODO need to translate this if block to look for deployments and not CSVs + deploymentList, err := r.GetDeploymentListFromPackage(ctx, opdRegistry.PackageName, opdRegistry.Namespace) + if err != nil { + merr.Add(err) + requestInstance.SetMemberStatus(operand.Name, operatorv1alpha1.OperatorFailed, "", &r.Mutex) + continue + } + deployment = deploymentList[0] + + //TODO change this block to deal with an empty list of deployments instead of csvs + if deployment == nil { + klog.Warningf("Deployment for %s in the namespace %s is not ready yet, retry", operatorName, namespace) + requestInstance.SetMemberStatus(operand.Name, operatorv1alpha1.OperatorInstalling, "", &r.Mutex) + continue + } + + // TODO determine if we need to reimagine this function for noolm use, do we want odlm cleaning up extra deployments? How should ODLM know the difference between "good" and "bad" deployments? + //otherwise get rid of it + // if err := r.DeleteRedundantCSV(ctx, csv.Name, csv.Namespace, registryKey.Namespace, opdRegistry.PackageName); err != nil { + // merr.Add(errors.Wrapf(err, "failed to delete the redundant ClusterServiceVersion %s in the namespace %s", csv.Name, csv.Namespace)) + // requestInstance.SetMemberStatus(operand.Name, operatorv1alpha1.OperatorFailed, "", &r.Mutex) + // continue + // } + + //TODO git rid of this section + // if !opdRegistry.UserManaged { + // // find the OperandRequest which has the same operator's channel or fallback channels as existing subscription. + // // ODLM will only reconcile Operand based on OperandConfig for this OperandRequest + // channels := []string{opdRegistry.Channel} + // if channels = append(channels, opdRegistry.FallbackChannels...); !util.Contains(channels, sub.Spec.Channel) { + // klog.Infof("Subscription %s in the namespace %s is NOT managed by %s/%s, Skip reconciling Operands", sub.Name, sub.Namespace, requestInstance.Namespace, requestInstance.Name) + // requestInstance.SetMemberStatus(operand.Name, operatorv1alpha1.OperatorFailed, "", &r.Mutex) + // continue + // } + // } + + //TODO update to deployment name + klog.V(3).Info("Generating customresource base on Deployment: ", deployment.GetName()) + requestInstance.SetMemberStatus(operand.Name, operatorv1alpha1.OperatorRunning, "", &r.Mutex) + + // Merge and Generate CR + if operand.Kind == "" { + configInstance, err := r.GetOperandConfig(ctx, registryKey) + if err == nil { + // Check the requested Service Config if exist in specific OperandConfig + opdConfig := configInstance.GetService(operand.Name) + if opdConfig == nil && !opdRegistry.UserManaged { + klog.V(2).Infof("There is no service: %s from the OperandConfig instance: %s/%s, Skip reconciling Operands", operand.Name, registryKey.Namespace, req.Registry) + continue + } + //TODO pass through deployment values here + err = r.reconcileCRwithConfig(ctx, opdConfig, configInstance.Name, configInstance.Namespace, deployment, requestInstance, operand.Name, deployment.Namespace, &r.Mutex) + if err != nil { + merr.Add(err) + requestInstance.SetMemberStatus(operand.Name, "", operatorv1alpha1.ServiceFailed, &r.Mutex) + continue + } + } else if apierrors.IsNotFound(err) { + klog.Infof("Not Found OperandConfig: %s/%s", operand.Name, err) + } else { + merr.Add(errors.Wrapf(err, "failed to get the OperandConfig %s", registryKey.String())) + continue + } + + } else { + err = r.reconcileCRwithRequest(ctx, requestInstance, operand, types.NamespacedName{Name: requestInstance.Name, Namespace: requestInstance.Namespace}, i, deployment.Namespace, &r.Mutex) + if err != nil { + merr.Add(err) + requestInstance.SetMemberStatus(operand.Name, "", operatorv1alpha1.ServiceFailed, &r.Mutex) + continue + } + } + requestInstance.SetMemberStatus(operand.Name, "", operatorv1alpha1.ServiceRunning, &r.Mutex) + } + } + if len(merr.Errors) != 0 { + return merr + } + klog.V(1).Infof("Finished reconciling Operands for OperandRequest: %s/%s", requestInstance.GetNamespace(), requestInstance.GetName()) + return &util.MultiErr{} +} + +// reconcileCRwithConfig merge and create custom resource base on OperandConfig and deployment alm-examples +func (r *Reconciler) reconcileCRwithConfig(ctx context.Context, service *operatorv1alpha1.ConfigService, opConfigName, opConfigNs string, deployment *appsv1.Deployment, requestInstance *operatorv1alpha1.OperandRequest, operandName string, operatorNamespace string, mu sync.Locker) error { + merr := &util.MultiErr{} + + // Create k8s resources required by service + if service.Resources != nil { + // Get the chunk size + var chunkSize int + if r.StepSize > 0 { + chunkSize = r.StepSize + } else { + chunkSize = 1 + } + var wg sync.WaitGroup + semaphore := make(chan struct{}, chunkSize) + + for i := range service.Resources { + wg.Add(1) + semaphore <- struct{}{} + go func(res operatorv1alpha1.ConfigResource) { + defer wg.Done() + defer func() { <-semaphore }() // release semaphore + err := r.reconcileK8sResourceWithRetries(ctx, res, service.Name, opConfigName, opConfigNs) + if err != nil { + merr.Add(err) + } + }(service.Resources[i]) + } + + wg.Wait() + + if len(merr.Errors) != 0 { + return merr + } + } + + //TODO change this to deployment, make sure GetAnnotations works for deployments the same way + almExamples := deployment.GetAnnotations()["alm-examples"] + + // Convert CR template string to slice + var almExampleList []interface{} + err := json.Unmarshal([]byte(almExamples), &almExampleList) + if err != nil { + return errors.Wrapf(err, "failed to convert alm-examples in the Subscription %s/%s to slice", opConfigNs, service.Name) + } + + foundMap := make(map[string]bool) + for cr := range service.Spec { + foundMap[cr] = false + } + + serviceObject, err := util.ObjectToNewUnstructured(service) + if err != nil { + klog.Errorf("Failed to convert OperandConfig service object %s to unstructured.Unstructured object", service.Name) + return err + } + + if err := r.ParseValueReferenceInObject(ctx, "spec", serviceObject.Object["spec"], serviceObject.Object, "OperandConfig", opConfigName, opConfigNs); err != nil { + klog.Errorf("Failed to parse value reference for service %s: %v", service.Name, err) + return err + } + // cover unstructured.Unstructured object to original OperandConfig object + if err := runtime.DefaultUnstructuredConverter.FromUnstructured(serviceObject.Object, service); err != nil { + klog.Errorf("Failed to convert unstructured.Unstructured object to service object %s", service.Name) + return err + } + + // Merge OperandConfig and ClusterServiceVersion alm-examples + for _, almExample := range almExampleList { + // Create an unstructured object for CR and check its value + var crFromALM unstructured.Unstructured + crFromALM.Object = almExample.(map[string]interface{}) + + name := crFromALM.GetName() + spec := crFromALM.Object["spec"] + if spec == nil { + continue + } + + err := r.Client.Get(ctx, types.NamespacedName{ + Name: name, + Namespace: opConfigNs, + }, &crFromALM) + + foundInConfig := false + for cr := range service.Spec { + if strings.EqualFold(crFromALM.GetKind(), cr) { + foundMap[cr] = true + foundInConfig = true + } + } + + if !foundInConfig { + //TODO change to deployment + klog.Warningf("%v in the alm-example doesn't exist in the OperandConfig for %v", crFromALM.GetKind(), deployment.GetName()) + continue + } + + if err != nil && !apierrors.IsNotFound(err) { + merr.Add(errors.Wrapf(err, "failed to get the custom resource %s/%s", opConfigNs, name)) + continue + } else if apierrors.IsNotFound(err) { + // Create Custom Resource + if err := r.compareConfigandExample(ctx, crFromALM, service, opConfigNs); err != nil { + merr.Add(err) + continue + } + } else { + if r.CheckLabel(crFromALM, map[string]string{constant.OpreqLabel: "true"}) { + // Update or Delete Custom Resource + if err := r.existingCustomResource(ctx, crFromALM, spec.(map[string]interface{}), service, opConfigNs); err != nil { + merr.Add(err) + continue + } + statusFromCR, err := r.getOperandStatus(crFromALM) + if err != nil { + return err + } + serviceKind := crFromALM.GetKind() + if serviceKind != "OperandRequest" && statusFromCR.ObjectName != "" { + var resources []operatorv1alpha1.OperandStatus + resources = append(resources, statusFromCR) + serviceStatus := newServiceStatus(operandName, operatorNamespace, resources) + if seterr := requestInstance.SetServiceStatus(ctx, serviceStatus, r.Client, mu); seterr != nil { + return seterr + } + } + } else { + klog.V(2).Info("Skip the custom resource not created by ODLM") + } + } + } + if len(merr.Errors) != 0 { + return merr + } + + for cr, found := range foundMap { + if !found { + //TODO change to deployment + klog.Warningf("Custom resource %v doesn't exist in the alm-example of %v", cr, deployment.GetName()) + } + } + + return nil +} + +// reconcileCRwithRequest merge and create custom resource base on OperandRequest and CSV alm-examples +func (r *Reconciler) reconcileCRwithRequest(ctx context.Context, requestInstance *operatorv1alpha1.OperandRequest, operand operatorv1alpha1.Operand, requestKey types.NamespacedName, index int, operatorNamespace string, mu sync.Locker) error { + merr := &util.MultiErr{} + + // Create an unstructured object for CR and check its value + var crFromRequest unstructured.Unstructured + + if operand.APIVersion == "" { + return fmt.Errorf("the APIVersion of operand is empty for operator %s", operand.Name) + } + + if operand.Kind == "" { + return fmt.Errorf("the Kind of operand is empty for operator %s", operand.Name) + } + + var name string + if operand.InstanceName == "" { + crInfo := sha256.Sum256([]byte(operand.APIVersion + operand.Kind + strconv.Itoa(index))) + name = requestKey.Name + "-" + hex.EncodeToString(crInfo[:7]) + } else { + name = operand.InstanceName + } + + crFromRequest.SetName(name) + crFromRequest.SetNamespace(requestKey.Namespace) + crFromRequest.SetAPIVersion(operand.APIVersion) + crFromRequest.SetKind(operand.Kind) + // Set the OperandRequest as the owner of the CR from request + if err := controllerutil.SetOwnerReference(requestInstance, &crFromRequest, r.Scheme); err != nil { + merr.Add(errors.Wrapf(err, "failed to set ownerReference for custom resource %s/%s", requestKey.Namespace, name)) + } + + err := r.Client.Get(ctx, types.NamespacedName{ + Name: name, + Namespace: requestKey.Namespace, + }, &crFromRequest) + + if err != nil && !apierrors.IsNotFound(err) { + merr.Add(errors.Wrapf(err, "failed to get custom resource %s/%s", requestKey.Namespace, name)) + } else if apierrors.IsNotFound(err) { + // Create Custom resource + if err := r.createCustomResource(ctx, crFromRequest, requestKey.Namespace, operand.Kind, operand.Spec.Raw); err != nil { + merr.Add(err) + } + requestInstance.SetMemberCRStatus(operand.Name, name, operand.Kind, operand.APIVersion, &r.Mutex) + } else { + if r.CheckLabel(crFromRequest, map[string]string{constant.OpreqLabel: "true"}) { + // Update or Delete Custom resource + klog.V(3).Info("Found existing custom resource: " + operand.Kind) + if err := r.updateCustomResource(ctx, crFromRequest, requestKey.Namespace, operand.Kind, operand.Spec.Raw, map[string]interface{}{}, requestInstance); err != nil { + return err + } + statusFromCR, err := r.getOperandStatus(crFromRequest) + if err != nil { + return err + } + if operand.Kind != "OperandRequest" && statusFromCR.ObjectName != "" { + var resources []operatorv1alpha1.OperandStatus + resources = append(resources, statusFromCR) + serviceStatus := newServiceStatus(operand.Name, operatorNamespace, resources) + seterr := requestInstance.SetServiceStatus(ctx, serviceStatus, r.Client, mu) + if seterr != nil { + return seterr + } + } + } else { + klog.V(2).Info("Skip the custom resource not created by ODLM") + } + } + + if len(merr.Errors) != 0 { + return merr + } + return nil +} + +func (r *Reconciler) getOperandStatus(existingCR unstructured.Unstructured) (operatorv1alpha1.OperandStatus, error) { + var emptyStatus operatorv1alpha1.OperandStatus + byteStatus, err := json.Marshal(existingCR.Object["status"]) + if err != nil { + klog.Error(err) + return emptyStatus, err + } + var rawStatus map[string]interface{} + err = json.Unmarshal(byteStatus, &rawStatus) + if err != nil { + klog.Error(err) + return emptyStatus, err + } + var serviceStatus operatorv1alpha1.OperandStatus + byteService, err := json.Marshal(rawStatus["service"]) + if err != nil { + klog.Error(err) + return emptyStatus, err + } + err = json.Unmarshal(byteService, &serviceStatus) + if err != nil { + klog.Error(err) + return emptyStatus, err + } + return serviceStatus, nil +} + +func newServiceStatus(operatorName string, namespace string, resources []operatorv1alpha1.OperandStatus) operatorv1alpha1.ServiceStatus { + var serviceSpec operatorv1alpha1.ServiceStatus + serviceSpec.OperatorName = operatorName + serviceSpec.Namespace = namespace + // serviceSpec.Type = "Ready" //should this be something more specific? Like operandNameReady? + status := "Ready" + for i := range resources { + if resources[i].Status == "NotReady" { + status = "NotReady" + break + } else { + for j := range resources[i].ManagedResources { + if resources[i].ManagedResources[j].Status == "NotReady" { + status = "NotReady" + break + } + } + } + } + serviceSpec.Status = status //TODO logic to determine readiness + serviceSpec.Resources = resources + return serviceSpec +} + +func (r *Reconciler) reconcileK8sResourceWithRetries(ctx context.Context, res operatorv1alpha1.ConfigResource, serviceName, opConfigName, opConfigNs string) error { + var err error + for i := 0; i < int(constant.DefaultCRRetryNumber); i++ { + err = r.reconcileK8sResource(ctx, res, serviceName, opConfigName, opConfigNs) + if err == nil { + return nil + } + klog.Errorf("Failed to reconcile k8s resource -- Kind: %s, NamespacedName: %s/%s with error: %v", res.Kind, res.Namespace, res.Name, err) + if i < int(constant.DefaultCRRetryNumber)-1 { + waitTime := time.Duration((1 << i) * 4 * int(time.Second)) + klog.Warningf("Retry reconcile k8s resource -- Kind: %s, NamespacedName: %s/%s after waiting %v", res.Kind, res.Namespace, res.Name, waitTime) + time.Sleep(waitTime) + } + } + return err +} + +func (r *Reconciler) reconcileK8sResource(ctx context.Context, res operatorv1alpha1.ConfigResource, serviceName, opConfigName, opConfigNs string) error { + if res.APIVersion == "" { + return fmt.Errorf("the APIVersion of k8s resource is empty for operator %s", serviceName) + } + + if res.Kind == "" { + return fmt.Errorf("the Kind of k8s resource is empty for operator %s", serviceName) + } + if res.Name == "" { + return fmt.Errorf("the Name of k8s resource is empty for operator %s", serviceName) + } + var k8sResNs string + if res.Namespace == "" { + k8sResNs = opConfigNs + } else { + k8sResNs = res.Namespace + } + + resObject, err := util.ObjectToNewUnstructured(&res) + if err != nil { + klog.Errorf("Failed to convert %s %s/%s object to unstructured.Unstructured object", res.Kind, k8sResNs, res.Name) + return err + } + + if err := r.ParseValueReferenceInObject(ctx, "data", resObject.Object["data"], resObject.Object, "OperandConfig", opConfigName, opConfigNs); err != nil { + klog.Errorf("Failed to parse value reference in resource %s/%s: %v", k8sResNs, res.Name, err) + return err + } + // cover unstructured.Unstructured object to original OperandConfig object + if err := runtime.DefaultUnstructuredConverter.FromUnstructured(resObject.Object, &res); err != nil { + klog.Errorf("Failed to convert unstructured.Unstructured object to %s %s/%s object", res.Kind, k8sResNs, res.Name) + return err + } + + var k8sRes unstructured.Unstructured + k8sRes.SetAPIVersion(res.APIVersion) + k8sRes.SetKind(res.Kind) + k8sRes.SetName(res.Name) + k8sRes.SetNamespace(k8sResNs) + + verbs := []string{"create", "delete", "get", "update"} + if r.checkResAuth(ctx, verbs, k8sRes) { + err := r.Client.Get(ctx, types.NamespacedName{ + Name: res.Name, + Namespace: k8sResNs, + }, &k8sRes) + + if err != nil && !apierrors.IsNotFound(err) { + return errors.Wrapf(err, "failed to get k8s resource %s/%s", k8sResNs, res.Name) + } else if apierrors.IsNotFound(err) { + if err := r.createK8sResource(ctx, k8sRes, res.Data, res.Labels, res.Annotations, &res.OwnerReferences, &res.OptionalFields); err != nil { + return err + } + } else { + if res.Force { + // Update k8s resource + klog.V(3).Info("Found existing k8s resource: " + res.Name) + if err := r.updateK8sResource(ctx, k8sRes, res.Data, res.Labels, res.Annotations, &res.OwnerReferences, &res.OptionalFields); err != nil { + return err + } + } else { + klog.V(2).Infof("Skip the k8s resource %s/%s which is not created by ODLM", res.Kind, res.Name) + } + } + } else { + klog.Infof("ODLM doesn't have enough permission to reconcile k8s resource -- Kind: %s, NamespacedName: %s/%s", res.Kind, k8sResNs, res.Name) + } + return nil +} + +// deleteAllCustomResource remove custom resource base on OperandConfig and CSV alm-examples +func (r *Reconciler) deleteAllCustomResource(ctx context.Context, deployment *appsv1.Deployment, requestInstance *operatorv1alpha1.OperandRequest, csc *operatorv1alpha1.OperandConfig, operandName, namespace string) error { + + customeResourceMap := make(map[string]operatorv1alpha1.OperandCRMember) + for _, member := range requestInstance.Status.Members { + if len(member.OperandCRList) != 0 { + if member.Name == operandName { + for _, cr := range member.OperandCRList { + customeResourceMap[member.Name+"/"+cr.Kind+"/"+cr.Name] = cr + } + } + } + } + + merr := &util.MultiErr{} + var ( + wg sync.WaitGroup + ) + for index, opdMember := range customeResourceMap { + crShouldBeDeleted := unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": opdMember.APIVersion, + "kind": opdMember.Kind, + "metadata": map[string]interface{}{ + "name": opdMember.Name, + }, + }, + } + + var ( + operatorName = strings.Split(index, "/")[0] + opdMember = opdMember + ) + + wg.Add(1) + go func() { + defer wg.Done() + if err := r.deleteCustomResource(ctx, crShouldBeDeleted, requestInstance.Namespace); err != nil { + r.Mutex.Lock() + defer r.Mutex.Unlock() + merr.Add(err) + return + } + requestInstance.RemoveMemberCRStatus(operatorName, opdMember.Name, opdMember.Kind, &r.Mutex) + }() + } + wg.Wait() + + if len(merr.Errors) != 0 { + klog.Errorf("Failed to delete custom resource from OperandRequest for operator %s", operandName) + return merr + } + + service := csc.GetService(operandName) + if service == nil { + return nil + } + almExamples := deployment.GetAnnotations()["alm-examples"] + klog.V(2).Info("Delete all the custom resource from Subscription ", service.Name) + + // Create a slice for crTemplates + var almExamplesRaw []interface{} + + // Convert CR template string to slice + err := json.Unmarshal([]byte(almExamples), &almExamplesRaw) + if err != nil { + return errors.Wrapf(err, "failed to convert alm-examples in the Subscription %s to slice", service.Name) + } + + // Merge OperandConfig and ClusterServiceVersion alm-examples + for _, crFromALM := range almExamplesRaw { + + // Get CR from the alm-example + var crTemplate unstructured.Unstructured + crTemplate.Object = crFromALM.(map[string]interface{}) + crTemplate.SetNamespace(namespace) + name := crTemplate.GetName() + // Get the kind of CR + kind := crTemplate.GetKind() + // Delete the CR + for crdName := range service.Spec { + + // Compare the name of OperandConfig and CRD name + if strings.EqualFold(kind, crdName) { + if r.checkResAuth(ctx, []string{"get"}, crTemplate) { + + err := r.Client.Get(ctx, types.NamespacedName{ + Name: name, + Namespace: namespace, + }, &crTemplate) + if err != nil && !apierrors.IsNotFound(err) { + merr.Add(err) + continue + } + if apierrors.IsNotFound(err) { + klog.V(2).Info("Finish Deleting the CR: " + kind) + continue + } + if r.CheckLabel(crTemplate, map[string]string{constant.OpreqLabel: "true"}) { + wg.Add(1) + go func() { + defer wg.Done() + if r.checkResAuth(ctx, []string{"delete"}, crTemplate) { + if err := r.deleteCustomResource(ctx, crTemplate, namespace); err != nil { + r.Mutex.Lock() + defer r.Mutex.Unlock() + merr.Add(err) + return + } + } + }() + } + + } + + } + + } + } + wg.Wait() + if len(merr.Errors) != 0 { + klog.Errorf("Failed to delete custom resource from OperandConfig for operator %s", operandName) + return merr + } + + return nil +} + +func (r *Reconciler) compareConfigandExample(ctx context.Context, crTemplate unstructured.Unstructured, service *operatorv1alpha1.ConfigService, namespace string) error { + kind := crTemplate.GetKind() + + for crdName, crdConfig := range service.Spec { + // Compare the name of OperandConfig and CRD name + if strings.EqualFold(kind, crdName) { + klog.V(3).Info("Found OperandConfig spec for custom resource: " + kind) + err := r.createCustomResource(ctx, crTemplate, namespace, crdName, crdConfig.Raw) + if err != nil { + return errors.Wrapf(err, "failed to create custom resource -- Kind: %s", kind) + } + } + } + return nil +} + +func (r *Reconciler) createCustomResource(ctx context.Context, crTemplate unstructured.Unstructured, namespace, crName string, crConfig []byte) error { + + //Convert CR template spec to string + specJSONString, _ := json.Marshal(crTemplate.Object["spec"]) + + // Merge CR template spec and OperandConfig spec + mergedCR := util.MergeCR(specJSONString, crConfig) + + crTemplate.Object["spec"] = mergedCR + crTemplate.SetNamespace(namespace) + + r.EnsureLabel(crTemplate, map[string]string{constant.OpreqLabel: "true"}) + + // Create the CR + crerr := r.Create(ctx, &crTemplate) + if crerr != nil && !apierrors.IsAlreadyExists(crerr) { + return errors.Wrap(crerr, "failed to create custom resource") + } + + klog.V(2).Info("Finish creating the Custom Resource: ", crName) + + return nil +} + +func (r *Reconciler) existingCustomResource(ctx context.Context, existingCR unstructured.Unstructured, specFromALM map[string]interface{}, service *operatorv1alpha1.ConfigService, namespace string) error { + kind := existingCR.GetKind() + + var found bool + for crName, crdConfig := range service.Spec { + // Compare the name of OperandConfig and CRD name + if strings.EqualFold(kind, crName) { + found = true + klog.V(3).Info("Found OperandConfig spec for custom resource: " + kind) + err := r.updateCustomResource(ctx, existingCR, namespace, crName, crdConfig.Raw, specFromALM) + if err != nil { + return errors.Wrap(err, "failed to update custom resource") + } + } + } + if !found { + err := r.deleteCustomResource(ctx, existingCR, namespace) + if err != nil { + return err + } + } + return nil +} + +func (r *Reconciler) updateCustomResource(ctx context.Context, existingCR unstructured.Unstructured, namespace, crName string, crConfig []byte, configFromALM map[string]interface{}, owners ...metav1.Object) error { + + kind := existingCR.GetKind() + apiversion := existingCR.GetAPIVersion() + name := existingCR.GetName() + // Update the CR + err := wait.PollImmediate(constant.DefaultCRFetchPeriod, constant.DefaultCRFetchTimeout, func() (bool, error) { + + existingCR := unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": apiversion, + "kind": kind, + }, + } + + err := r.Client.Get(ctx, types.NamespacedName{ + Name: name, + Namespace: namespace, + }, &existingCR) + + if err != nil { + return false, errors.Wrapf(err, "failed to get custom resource -- Kind: %s, NamespacedName: %s/%s", kind, namespace, name) + } + + if !r.CheckLabel(existingCR, map[string]string{constant.OpreqLabel: "true"}) { + return true, nil + } + + forceUpdate := false + for _, owner := range owners { + if err := controllerutil.SetOwnerReference(owner, &existingCR, r.Scheme); err != nil { + return false, errors.Wrapf(err, "failed to set ownerReference for custom resource %s/%s", existingCR.GetNamespace(), existingCR.GetName()) + } + forceUpdate = true + } + + configFromALMRaw, err := json.Marshal(configFromALM) + if err != nil { + klog.Error(err) + return false, err + } + + existingCRRaw, err := json.Marshal(existingCR.Object["spec"]) + if err != nil { + klog.Error(err) + return false, err + } + + // Merge spec from ALM example and existing CR + updatedExistingCR := util.MergeCR(configFromALMRaw, existingCRRaw) + + updatedExistingCRRaw, err := json.Marshal(updatedExistingCR) + if err != nil { + klog.Error(err) + return false, err + } + + // Merge spec from update existing CR and OperandConfig spec + updatedCRSpec := util.MergeCR(updatedExistingCRRaw, crConfig) + + if equality.Semantic.DeepEqual(existingCR.Object["spec"], updatedCRSpec) && !forceUpdate { + return true, nil + } + + CRgeneration := existingCR.GetGeneration() + + klog.V(2).Infof("updating custom resource with apiversion: %s, kind: %s, %s/%s", apiversion, kind, namespace, name) + + existingCR.Object["spec"] = updatedCRSpec + err = r.Update(ctx, &existingCR) + + if err != nil { + return false, errors.Wrapf(err, "failed to update custom resource -- Kind: %s, NamespacedName: %s/%s", kind, namespace, name) + } + + UpdatedCR := unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": apiversion, + "kind": kind, + }, + } + + err = r.Client.Get(ctx, types.NamespacedName{ + Name: name, + Namespace: namespace, + }, &UpdatedCR) + + if err != nil { + return false, errors.Wrapf(err, "failed to get custom resource -- Kind: %s, NamespacedName: %s/%s", kind, namespace, name) + + } + + if UpdatedCR.GetGeneration() != CRgeneration { + klog.V(2).Info("Finish updating the Custom Resource: ", crName) + } + + return true, nil + }) + + if err != nil { + return errors.Wrapf(err, "failed to update custom resource -- Kind: %s, NamespacedName: %s/%s", kind, namespace, name) + } + + return nil +} + +func (r *Reconciler) deleteCustomResource(ctx context.Context, existingCR unstructured.Unstructured, namespace string) error { + + kind := existingCR.GetKind() + apiversion := existingCR.GetAPIVersion() + name := existingCR.GetName() + + crShouldBeDeleted := unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": apiversion, + "kind": kind, + }, + } + err := r.Client.Get(ctx, types.NamespacedName{ + Name: name, + Namespace: namespace, + }, &crShouldBeDeleted) + if err != nil && !apierrors.IsNotFound(err) { + return errors.Wrapf(err, "failed to get custom resource -- Kind: %s, NamespacedName: %s/%s", kind, namespace, name) + } + if apierrors.IsNotFound(err) { + klog.V(3).Infof("There is no custom resource: %s from custom resource definition: %s", name, kind) + } else { + if r.CheckLabel(crShouldBeDeleted, map[string]string{constant.OpreqLabel: "true"}) && !r.CheckLabel(crShouldBeDeleted, map[string]string{constant.NotUninstallLabel: "true"}) { + klog.V(3).Infof("Deleting custom resource: %s from custom resource definition: %s", name, kind) + err := r.Delete(ctx, &crShouldBeDeleted) + if err != nil && !apierrors.IsNotFound(err) { + return errors.Wrapf(err, "failed to delete custom resource -- Kind: %s, NamespacedName: %s/%s", kind, namespace, name) + } + err = wait.PollImmediate(constant.DefaultCRDeletePeriod, constant.DefaultCRDeleteTimeout, func() (bool, error) { + if strings.EqualFold(kind, "OperandRequest") { + return true, nil + } + klog.V(3).Infof("Waiting for CR %s to be removed ...", kind) + err := r.Client.Get(ctx, types.NamespacedName{ + Name: name, + Namespace: namespace, + }, &existingCR) + if apierrors.IsNotFound(err) { + return true, nil + } + if err != nil { + return false, errors.Wrapf(err, "failed to get custom resource -- Kind: %s, NamespacedName: %s/%s", kind, namespace, name) + } + return false, nil + }) + if err != nil { + return errors.Wrapf(err, "failed to delete custom resource -- Kind: %s, NamespacedName: %s/%s", kind, namespace, name) + } + klog.V(1).Infof("Finish deleting custom resource -- Kind: %s, NamespacedName: %s/%s", kind, namespace, name) + } + } + return nil +} + +func (r *Reconciler) checkCustomResource(ctx context.Context, requestInstance *operatorv1alpha1.OperandRequest) error { + klog.V(3).Infof("deleting the custom resource from OperandRequest %s/%s", requestInstance.Namespace, requestInstance.Name) + + members := requestInstance.Status.Members + + customeResourceMap := make(map[string]operatorv1alpha1.OperandCRMember) + for _, member := range members { + if len(member.OperandCRList) != 0 { + for _, cr := range member.OperandCRList { + customeResourceMap[member.Name+"/"+cr.Kind+"/"+cr.Name] = cr + } + } + } + for _, req := range requestInstance.Spec.Requests { + for _, opd := range req.Operands { + if opd.Kind != "" { + var name string + if opd.InstanceName == "" { + name = requestInstance.Name + } else { + name = opd.InstanceName + } + delete(customeResourceMap, opd.Name+"/"+opd.Kind+"/"+name) + } + } + } + + var ( + wg sync.WaitGroup + ) + + merr := &util.MultiErr{} + for index, opdMember := range customeResourceMap { + crShouldBeDeleted := unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": opdMember.APIVersion, + "kind": opdMember.Kind, + "metadata": map[string]interface{}{ + "name": opdMember.Name, + }, + }, + } + + var ( + operatorName = strings.Split(index, "/")[0] + opdMember = opdMember + ) + wg.Add(1) + go func() { + defer wg.Done() + if err := r.deleteCustomResource(ctx, crShouldBeDeleted, requestInstance.Namespace); err != nil { + r.Mutex.Lock() + defer r.Mutex.Unlock() + merr.Add(err) + return + } + requestInstance.RemoveMemberCRStatus(operatorName, opdMember.Name, opdMember.Kind, &r.Mutex) + }() + } + wg.Wait() + + if len(merr.Errors) != 0 { + return merr + } + + return nil +} + +func (r *Reconciler) createK8sResource(ctx context.Context, k8sResTemplate unstructured.Unstructured, k8sResConfig *runtime.RawExtension, newLabels, newAnnotations map[string]string, ownerReferences *[]operatorv1alpha1.OwnerReference, optionalFields *[]operatorv1alpha1.OptionalField) error { + kind := k8sResTemplate.GetKind() + name := k8sResTemplate.GetName() + namespace := k8sResTemplate.GetNamespace() + + if k8sResConfig != nil { + k8sResConfigDecoded := make(map[string]interface{}) + k8sResConfigUnmarshalErr := json.Unmarshal(k8sResConfig.Raw, &k8sResConfigDecoded) + if k8sResConfigUnmarshalErr != nil { + klog.Errorf("failed to unmarshal k8s Resource Config: %v", k8sResConfigUnmarshalErr) + } + for k, v := range k8sResConfigDecoded { + k8sResTemplate.Object[k] = v + } + + k8sResConfigBytes, err := json.Marshal(k8sResConfigDecoded) + if err != nil { + return errors.Wrap(err, "failed to marshal k8sResConfigDecoded") + } + + // Caculate the hash number of the new created template + _, templateHash := util.CalculateResHashes(nil, k8sResConfigBytes) + + newAnnotations = util.AddHashAnnotation(&k8sResTemplate, constant.K8sHashedData, templateHash, newAnnotations) + + if kind == "Route" { + if host, found := k8sResConfigDecoded["spec"].(map[string]interface{})["host"].(string); found { + hostHash := util.CalculateHash([]byte(host)) + + // if newAnnotations == nil { + // newAnnotations = make(map[string]string) + // } + // newAnnotations[constant.RouteHash] = hostHash + newAnnotations = util.AddHashAnnotation(&k8sResTemplate, constant.RouteHash, hostHash, newAnnotations) + + } else { + klog.Warningf("spec.host not found in Route %s/%s", namespace, name) + } + } + } + + if err := r.ExecuteOptionalFields(ctx, &k8sResTemplate, optionalFields); err != nil { + return errors.Wrap(err, "failed to execute optional fields") + } + r.EnsureLabel(k8sResTemplate, map[string]string{constant.OpreqLabel: "true"}) + r.EnsureLabel(k8sResTemplate, newLabels) + r.EnsureAnnotation(k8sResTemplate, newAnnotations) + if err := r.setOwnerReferences(ctx, &k8sResTemplate, ownerReferences); err != nil { + return errors.Wrap(err, "failed to set ownerReferences for k8s resource") + } + + // Create the k8s resource + err := r.Create(ctx, &k8sResTemplate) + if err != nil && !apierrors.IsAlreadyExists(err) { + return errors.Wrap(err, "failed to create k8s resource") + } + + klog.V(2).Infof("Finish creating the k8s Resource: -- Kind: %s, NamespacedName: %s/%s", kind, namespace, name) + + return nil +} + +func (r *Reconciler) updateK8sResource(ctx context.Context, existingK8sRes unstructured.Unstructured, k8sResConfig *runtime.RawExtension, newLabels, newAnnotations map[string]string, ownerReferences *[]operatorv1alpha1.OwnerReference, optionalFields *[]operatorv1alpha1.OptionalField) error { + kind := existingK8sRes.GetKind() + apiversion := existingK8sRes.GetAPIVersion() + name := existingK8sRes.GetName() + namespace := existingK8sRes.GetNamespace() + + if kind == "Job" { + if err := r.updateK8sJob(ctx, existingK8sRes, k8sResConfig, newLabels, newAnnotations, ownerReferences, optionalFields); err != nil { + return errors.Wrap(err, "failed to update Job") + } + return nil + } + + if kind == "Route" { + if err := r.updateK8sRoute(ctx, existingK8sRes, k8sResConfig, newLabels, newAnnotations, ownerReferences, optionalFields); err != nil { + return errors.Wrap(err, "failed to update Route") + } + + // update the annotations of the Route host if the host is changed + if k8sResConfig != nil { + k8sResConfigDecoded := make(map[string]interface{}) + if k8sResConfigUnmarshalErr := json.Unmarshal(k8sResConfig.Raw, &k8sResConfigDecoded); k8sResConfigUnmarshalErr != nil { + return errors.Wrap(k8sResConfigUnmarshalErr, "failed to unmarshal k8s Resource Config") + } + + if host, found := k8sResConfigDecoded["spec"].(map[string]interface{})["host"].(string); found { + hostHash := util.CalculateHash([]byte(host)) + + if newAnnotations == nil { + newAnnotations = make(map[string]string) + } + newAnnotations[constant.RouteHash] = hostHash + } else { + klog.Warningf("spec.host not found in Route %s/%s", namespace, name) + } + } + } + + // Update the k8s resource + err := wait.PollImmediate(constant.DefaultCRFetchPeriod, constant.DefaultCRFetchTimeout, func() (bool, error) { + + existingRes := unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": apiversion, + "kind": kind, + }, + } + + err := r.Client.Get(ctx, types.NamespacedName{ + Name: name, + Namespace: namespace, + }, &existingRes) + if err != nil { + return false, errors.Wrapf(err, "failed to get k8s resource -- Kind: %s, NamespacedName: %s/%s", kind, namespace, name) + } + + resourceVersion := existingRes.GetResourceVersion() + + if !r.CheckLabel(existingRes, map[string]string{constant.OpreqLabel: "true"}) && (newLabels == nil || newLabels[constant.OpreqLabel] != "true") { + return true, nil + } + + if k8sResConfig != nil { + + // Convert existing k8s resource to string + existingResRaw, err := json.Marshal(existingRes.Object) + if err != nil { + return false, errors.Wrapf(err, "failed to marshal existing k8s resource -- Kind: %s, NamespacedName: %s/%s", kind, namespace, name) + } + + // Caculate the hash number of the new created template + existingHash, templateHash := util.CalculateResHashes(&existingRes, k8sResConfig.Raw) + + // If the hash number of the existing k8s resource is different from the hash number of template, update the k8s resource + if existingHash != templateHash { + k8sResConfigDecoded := make(map[string]interface{}) + k8sResConfigUnmarshalErr := json.Unmarshal(k8sResConfig.Raw, &k8sResConfigDecoded) + if k8sResConfigUnmarshalErr != nil { + klog.Errorf("failed to unmarshal k8s Resource Config: %v", k8sResConfigUnmarshalErr) + } + for k, v := range k8sResConfigDecoded { + existingRes.Object[k] = v + } + newAnnotations = util.AddHashAnnotation(&existingRes, constant.K8sHashedData, templateHash, newAnnotations) + + } else { + // If the hash number are the same, then do the deep merge + // Merge the existing CR and the CR from the OperandConfig + updatedExistingRes := util.MergeCR(existingResRaw, k8sResConfig.Raw) + // Update the existing k8s resource with the merged CR + existingRes.Object = updatedExistingRes + } + + if err := r.ExecuteOptionalFields(ctx, &existingRes, optionalFields); err != nil { + return false, errors.Wrap(err, "failed to execute optional fields") + } + r.EnsureAnnotation(existingRes, newAnnotations) + r.EnsureLabel(existingRes, newLabels) + if err := r.setOwnerReferences(ctx, &existingRes, ownerReferences); err != nil { + return false, errors.Wrapf(err, "failed to set ownerReferences for k8s resource -- Kind: %s, NamespacedName: %s/%s", kind, namespace, name) + } + + klog.Infof("updating k8s resource with apiversion: %s, kind: %s, %s/%s", apiversion, kind, namespace, name) + + err = r.Update(ctx, &existingRes) + if err != nil { + return false, errors.Wrapf(err, "failed to update k8s resource -- Kind: %s, NamespacedName: %s/%s", kind, namespace, name) + } + + UpdatedK8sRes := unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": apiversion, + "kind": kind, + }, + } + + err = r.Client.Get(ctx, types.NamespacedName{ + Name: name, + Namespace: namespace, + }, &UpdatedK8sRes) + + if err != nil { + return false, errors.Wrapf(err, "failed to get k8s resource -- Kind: %s, NamespacedName: %s/%s", kind, namespace, name) + + } + + if UpdatedK8sRes.GetResourceVersion() != resourceVersion { + klog.Infof("Finish updating the k8s Resource: -- Kind: %s, NamespacedName: %s/%s", kind, namespace, name) + } else { + klog.Infof("No updates on k8s resource with apiversion: %s, kind: %s, %s/%s", apiversion, kind, namespace, name) + } + + } + return true, nil + }) + + if err != nil { + return errors.Wrapf(err, "failed to update k8s resource -- Kind: %s, NamespacedName: %s/%s", kind, namespace, name) + } + + return nil +} + +func (r *Reconciler) updateK8sJob(ctx context.Context, existingK8sRes unstructured.Unstructured, k8sResConfig *runtime.RawExtension, newLabels, newAnnotations map[string]string, ownerReferences *[]operatorv1alpha1.OwnerReference, optionalFields *[]operatorv1alpha1.OptionalField) error { + + kind := existingK8sRes.GetKind() + apiversion := existingK8sRes.GetAPIVersion() + name := existingK8sRes.GetName() + namespace := existingK8sRes.GetNamespace() + + existingRes := unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": apiversion, + "kind": kind, + }, + } + + err := r.Client.Get(ctx, types.NamespacedName{ + Name: name, + Namespace: namespace, + }, &existingRes) + + if err != nil { + return errors.Wrapf(err, "failed to get k8s resource -- Kind: %s, NamespacedName: %s/%s", kind, namespace, name) + } + if !r.CheckLabel(existingRes, map[string]string{constant.OpreqLabel: "true"}) && (newLabels == nil || newLabels[constant.OpreqLabel] != "true") { + return nil + } + + var existingHashedData string + var newHashedData string + if existingRes.GetAnnotations() != nil { + existingHashedData = existingRes.GetAnnotations()[constant.HashedData] + } + + if k8sResConfig != nil { + hashedData := sha256.Sum256(k8sResConfig.Raw) + newHashedData = hex.EncodeToString(hashedData[:7]) + } + + if existingHashedData != newHashedData { + // create a new template of k8s resource + var templatek8sRes unstructured.Unstructured + templatek8sRes.SetAPIVersion(apiversion) + templatek8sRes.SetKind(kind) + templatek8sRes.SetName(name) + templatek8sRes.SetNamespace(namespace) + + if newAnnotations == nil { + newAnnotations = make(map[string]string) + } + newAnnotations[constant.HashedData] = newHashedData + + if err := r.deleteK8sResource(ctx, existingRes, newLabels, namespace); err != nil { + return errors.Wrap(err, "failed to update k8s resource") + } + if err := r.createK8sResource(ctx, templatek8sRes, k8sResConfig, newLabels, newAnnotations, ownerReferences, optionalFields); err != nil { + return errors.Wrap(err, "failed to update k8s resource") + } + } + return nil +} + +// update route resource +func (r *Reconciler) updateK8sRoute(ctx context.Context, existingK8sRes unstructured.Unstructured, k8sResConfig *runtime.RawExtension, newLabels, newAnnotations map[string]string, ownerReferences *[]operatorv1alpha1.OwnerReference, optionalFields *[]operatorv1alpha1.OptionalField) error { + kind := existingK8sRes.GetKind() + apiversion := existingK8sRes.GetAPIVersion() + name := existingK8sRes.GetName() + namespace := existingK8sRes.GetNamespace() + + existingRes := unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": apiversion, + "kind": kind, + }, + } + err := r.Client.Get(ctx, types.NamespacedName{ + Name: name, + Namespace: namespace, + }, &existingRes) + + if err != nil { + return errors.Wrapf(err, "failed to get k8s resource -- Kind: %s, NamespacedName: %s/%s", kind, namespace, name) + } + if !r.CheckLabel(existingRes, map[string]string{constant.OpreqLabel: "true"}) && (newLabels == nil || newLabels[constant.OpreqLabel] != "true") { + return nil + } + + existingAnnos := existingRes.GetAnnotations() + existingHostHash := existingAnnos[constant.RouteHash] + + if k8sResConfig != nil { + k8sResConfigDecoded := make(map[string]interface{}) + k8sResConfigUnmarshalErr := json.Unmarshal(k8sResConfig.Raw, &k8sResConfigDecoded) + if k8sResConfigUnmarshalErr != nil { + klog.Errorf("failed to unmarshal k8s Resource Config: %v", k8sResConfigUnmarshalErr) + } + + // Read the host from the OperandConfig + if newHost, found := k8sResConfigDecoded["spec"].(map[string]interface{})["host"].(string); found { + newHostHash := util.CalculateHash([]byte(newHost)) + + // Only re-create the route if the custom host has been removed + if newHost == "" && existingHostHash != newHostHash { + + // create a new template of k8s resource + var templatek8sRes unstructured.Unstructured + templatek8sRes.SetAPIVersion(apiversion) + templatek8sRes.SetKind(kind) + templatek8sRes.SetName(name) + templatek8sRes.SetNamespace(namespace) + + if err := r.deleteK8sResource(ctx, existingRes, newLabels, namespace); err != nil { + return errors.Wrap(err, "failed to delete Route for recreation") + } + if err := r.createK8sResource(ctx, templatek8sRes, k8sResConfig, newLabels, newAnnotations, ownerReferences, optionalFields); err != nil { + return errors.Wrap(err, "failed to update k8s resource") + } + } + } + } + return nil +} + +// deleteAllK8sResource remove k8s resource base on OperandConfig +func (r *Reconciler) deleteAllK8sResource(ctx context.Context, csc *operatorv1alpha1.OperandConfig, operandName, namespace string) error { + + service := csc.GetService(operandName) + if service == nil { + return nil + } + + var k8sResourceList []operatorv1alpha1.ConfigResource + k8sResourceList = append(k8sResourceList, service.Resources...) + + merr := &util.MultiErr{} + var ( + wg sync.WaitGroup + ) + for _, k8sRes := range k8sResourceList { + k8sResShouldBeDeleted := unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": k8sRes.APIVersion, + "kind": k8sRes.Kind, + "metadata": map[string]interface{}{ + "name": k8sRes.Name, + }, + }, + } + k8sNamespace := namespace + if k8sRes.Namespace != "" { + k8sNamespace = k8sRes.Namespace + } + + wg.Add(1) + go func() { + defer wg.Done() + if err := r.deleteK8sResource(ctx, k8sResShouldBeDeleted, k8sRes.Labels, k8sNamespace); err != nil { + r.Mutex.Lock() + defer r.Mutex.Unlock() + merr.Add(err) + return + } + }() + } + wg.Wait() + + if len(merr.Errors) != 0 { + return merr + } + return nil +} + +func (r *Reconciler) deleteK8sResource(ctx context.Context, existingK8sRes unstructured.Unstructured, newLabels map[string]string, namespace string) error { + + kind := existingK8sRes.GetKind() + apiversion := existingK8sRes.GetAPIVersion() + name := existingK8sRes.GetName() + + k8sResShouldBeDeleted := unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": apiversion, + "kind": kind, + }, + } + err := r.Client.Get(ctx, types.NamespacedName{ + Name: name, + Namespace: namespace, + }, &k8sResShouldBeDeleted) + if err != nil && !apierrors.IsNotFound(err) { + return errors.Wrapf(err, "failed to get k8s resource -- Kind: %s, NamespacedName: %s/%s", kind, namespace, name) + } + if apierrors.IsNotFound(err) { + klog.V(3).Infof("There is no k8s resource: %s from kind: %s", name, kind) + } else { + // If the existing k8s resources has the OpreqLabel and does not have the NotUninstallLabel, delete it + // If the OpreqLabel is difined in OperandConfig resource, delete it + hasOpreqLabel := r.CheckLabel(k8sResShouldBeDeleted, map[string]string{constant.OpreqLabel: "true"}) + hasNotUninstallLabel := r.CheckLabel(k8sResShouldBeDeleted, map[string]string{constant.NotUninstallLabel: "true"}) + opreqLabelInConfig := newLabels != nil && newLabels[constant.OpreqLabel] == "true" + + if (hasOpreqLabel && !hasNotUninstallLabel) || opreqLabelInConfig { + klog.V(3).Infof("Deleting k8s resource: %s from kind: %s", name, kind) + err := r.Delete(ctx, &k8sResShouldBeDeleted, client.PropagationPolicy(metav1.DeletePropagationBackground)) + if err != nil && !apierrors.IsNotFound(err) { + return errors.Wrapf(err, "failed to delete k8s resource -- Kind: %s, NamespacedName: %s/%s", kind, namespace, name) + } + err = wait.PollImmediate(constant.DefaultCRDeletePeriod, constant.DefaultCRDeleteTimeout, func() (bool, error) { + if strings.EqualFold(kind, "OperandRequest") { + return true, nil + } + klog.V(3).Infof("Waiting for resource %s to be removed ...", kind) + err := r.Client.Get(ctx, types.NamespacedName{ + Name: name, + Namespace: namespace, + }, &existingK8sRes) + if apierrors.IsNotFound(err) { + return true, nil + } + if err != nil { + return false, errors.Wrapf(err, "failed to get k8s resource -- Kind: %s, NamespacedName: %s/%s", kind, namespace, name) + } + return false, nil + }) + if err != nil { + return errors.Wrapf(err, "failed to delete k8s resource -- Kind: %s, NamespacedName: %s/%s", kind, namespace, name) + } + klog.V(1).Infof("Finish deleting k8s resource -- Kind: %s, NamespacedName: %s/%s", kind, namespace, name) + } + } + return nil +} + +func (r *Reconciler) checkResAuth(ctx context.Context, verbs []string, k8sResTemplate unstructured.Unstructured) bool { + kind := k8sResTemplate.GetKind() + apiversion := k8sResTemplate.GetAPIVersion() + name := k8sResTemplate.GetName() + namespace := k8sResTemplate.GetNamespace() + + dc := discovery.NewDiscoveryClientForConfigOrDie(r.Config) + if namespaced, err := util.ResourceNamespaced(dc, apiversion, kind); err != nil { + klog.Errorf("Failed to check resource scope for Kind: %s, NamespacedName: %s/%s, %v", kind, namespace, name, err) + } else if !namespaced { + namespace = "" + } + + gvk := schema.FromAPIVersionAndKind(apiversion, kind) + gvr, err := r.ResourceForKind(gvk, namespace) + if err != nil { + klog.Errorf("Failed to get GroupVersionResource from GroupVersionKind, %v", err) + return false + } + + for _, verb := range verbs { + sar := &authorizationv1.SelfSubjectAccessReview{ + Spec: authorizationv1.SelfSubjectAccessReviewSpec{ + ResourceAttributes: &authorizationv1.ResourceAttributes{ + Namespace: namespace, + Verb: verb, + Group: gvr.Group, + Resource: gvr.Resource, + }, + }, + } + if err := r.Create(ctx, sar); err != nil { + klog.Errorf("Failed to check operator permission for Kind: %s, NamespacedName: %s/%s, %v", kind, namespace, name, err) + return false + } + + klog.V(2).Infof("Operator %s permission in namespace %s for Kind: %s, Allowed: %t, Denied: %t, Reason: %s", verb, namespace, kind, sar.Status.Allowed, sar.Status.Denied, sar.Status.Reason) + + if !sar.Status.Allowed { + return false + } + } + return true +} + +func (r *Reconciler) ResourceForKind(gvk schema.GroupVersionKind, namespace string) (*schema.GroupVersionResource, error) { + mapper := meta.NewDefaultRESTMapper([]schema.GroupVersion{gvk.GroupVersion()}) + + if namespace != "" { + mapper.Add(gvk, meta.RESTScopeRoot) + } else { + mapper.Add(gvk, meta.RESTScopeNamespace) + } + + mapping, err := mapper.RESTMapping(gvk.GroupKind(), gvk.Version) + if err != nil { + return nil, err + } + return &mapping.Resource, nil +} + +func (r *Reconciler) setOwnerReferences(ctx context.Context, controlledRes *unstructured.Unstructured, ownerReferences *[]operatorv1alpha1.OwnerReference) error { + if ownerReferences != nil { + for _, owner := range *ownerReferences { + ownerObj := unstructured.Unstructured{} + ownerObj.SetAPIVersion(owner.APIVersion) + ownerObj.SetKind(owner.Kind) + ownerObj.SetName(owner.Name) + + if err := r.Reader.Get(ctx, types.NamespacedName{ + Name: owner.Name, + Namespace: controlledRes.GetNamespace(), + }, &ownerObj); err != nil { + return errors.Wrapf(err, "failed to get owner object -- Kind: %s, NamespacedName: %s/%s", owner.Kind, controlledRes.GetNamespace(), owner.Name) + } + if owner.Controller != nil && *owner.Controller { + if err := controllerutil.SetControllerReference(&ownerObj, controlledRes, r.Scheme); err != nil { + return errors.Wrapf(err, "failed to set controller ownerReference for k8s resource -- Kind: %s, NamespacedName: %s/%s", controlledRes.GetKind(), controlledRes.GetNamespace(), controlledRes.GetName()) + } + } else { + if err := controllerutil.SetOwnerReference(&ownerObj, controlledRes, r.Scheme); err != nil { + return errors.Wrapf(err, "failed to set ownerReference for k8s resource -- Kind: %s, NamespacedName: %s/%s", controlledRes.GetKind(), controlledRes.GetNamespace(), controlledRes.GetName()) + } + } + klog.Infof("Set %s with name %s as Owner for k8s resource -- Kind: %s, NamespacedName: %s/%s", owner.Kind, owner.Name, controlledRes.GetKind(), controlledRes.GetNamespace(), controlledRes.GetName()) + } + } + return nil +} + +func (r *Reconciler) ExecuteOptionalFields(ctx context.Context, resTemplate *unstructured.Unstructured, optionalFields *[]operatorv1alpha1.OptionalField) error { + if optionalFields != nil { + for _, field := range *optionalFields { + // Find the path from resTemplate + if value, err := util.SanitizeObjectString(field.Path, resTemplate.Object); err != nil || value == "" { + klog.Warningf("Skipping execute optional field, not find the path %s in the object -- Kind: %s, NamespacedName: %s/%s: %v", field.Path, resTemplate.GetKind(), resTemplate.GetNamespace(), resTemplate.GetName(), err) + continue + } + // Find the match expressions + if field.MatchExpressions != nil { + if !r.findMatchExpressions(ctx, field.MatchExpressions) { + klog.Infof("Skip operation '%s' for optional fields: %v for %s %s/%s", field.Operation, field.Path, resTemplate.GetKind(), resTemplate.GetNamespace(), resTemplate.GetName()) + continue + } + } + // Do operation + switch field.Operation { + case operatorv1alpha1.OperationRemove: + util.RemoveObjectField(resTemplate.Object, field.Path) + // case "Add": # TODO + default: + klog.Warningf("Invalid operation '%s' in optional fields: %v", field.Operation, field) + } + } + } + return nil +} + +func (r *Reconciler) findMatchExpressions(ctx context.Context, matchExpressions []operatorv1alpha1.MatchExpression) bool { + isMatch := false + for _, matchExpression := range matchExpressions { + if matchExpression.Key == "" || matchExpression.Operator == "" || matchExpression.ObjectRef == nil { + klog.Warningf("Invalid matchExpression: %v", matchExpression) + continue + } + // find value from the object + objRef := &unstructured.Unstructured{} + objRef.SetAPIVersion(matchExpression.ObjectRef.APIVersion) + objRef.SetKind(matchExpression.ObjectRef.Kind) + objRef.SetName(matchExpression.ObjectRef.Name) + if err := r.Reader.Get(ctx, types.NamespacedName{ + Name: matchExpression.ObjectRef.Name, + Namespace: matchExpression.ObjectRef.Namespace, + }, objRef); err != nil { + klog.Warningf("Failed to get the object %v in match expressions: %v", matchExpression.ObjectRef, err) + continue + } + value, _ := util.SanitizeObjectString(matchExpression.Key, objRef.Object) + + switch matchExpression.Operator { + case operatorv1alpha1.OperatorIn: + if util.Contains(matchExpression.Values, value) { + return true + } + case operatorv1alpha1.OperatorNotIn: + if util.Contains(matchExpression.Values, value) { + return false + } else { + isMatch = true + } + case operatorv1alpha1.OperatorExists: + if value != "" { + return true + } + case operatorv1alpha1.OperatorDoesNotExist: + if value != "" { + return false + } else { + isMatch = true + } + default: + klog.Warningf("Invalid operator %s in match expressions: %v", matchExpression.Operator, matchExpression) + } + } + + return isMatch +} + +func (r *Reconciler) ServiceStatusIsReady(ctx context.Context, requestInstance *operatorv1alpha1.OperandRequest) (bool, error) { + requestedServicesSet := make(map[string]struct{}) + for _, req := range requestInstance.Spec.Requests { + registryKey := requestInstance.GetRegistryKey(req) + registryInstance, err := r.GetOperandRegistry(ctx, registryKey) + if err != nil { + klog.Errorf("Failed to get OperandRegistry %s, %v", registryKey, err) + return false, err + } + if registryInstance.Annotations != nil && registryInstance.Annotations[constant.StatusMonitoredServices] != "" { + monitoredServices := strings.Split(registryInstance.Annotations[constant.StatusMonitoredServices], ",") + for _, operand := range req.Operands { + if util.Contains(monitoredServices, operand.Name) { + requestedServicesSet[operand.Name] = struct{}{} + } + } + } + } + + if len(requestedServicesSet) == 0 { + klog.V(2).Infof("No services to be monitored for OperandRequest %s/%s", requestInstance.Namespace, requestInstance.Name) + return true, nil + } + + if len(requestInstance.Status.Services) == 0 { + klog.Infof("Waiting for status.services to be instantiated for OperandRequest %s/%s ...", requestInstance.Namespace, requestInstance.Name) + return false, nil + } + if len(requestedServicesSet) != len(requestInstance.Status.Services) { + klog.Infof("Waiting for status of all requested services to be instantiated for OperandRequest %s/%s ...", requestInstance.Namespace, requestInstance.Name) + return false, nil + } + + serviceStatus := true + // wait for the status of the requested services to be ready + for _, s := range requestInstance.Status.Services { + if _, ok := requestedServicesSet[s.OperatorName]; ok { + if s.Status != "Ready" { + klog.Infof("Waiting for status of service %s to be Ready for OperandRequest %s/%s ...", s.OperatorName, requestInstance.Namespace, requestInstance.Name) + serviceStatus = false + } + } + } + return serviceStatus, nil +} diff --git a/controllers/operandrequestnoolm/reconcile_operator.go b/controllers/operandrequestnoolm/reconcile_operator.go new file mode 100644 index 00000000..96e94a8b --- /dev/null +++ b/controllers/operandrequestnoolm/reconcile_operator.go @@ -0,0 +1,783 @@ +// +// Copyright 2022 IBM Corporation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package operandrequestnoolm + +import ( + "context" + "encoding/json" + "fmt" + "regexp" + "strings" + "sync" + "time" + + gset "github.com/deckarep/golang-set" + olmv1 "github.com/operator-framework/api/pkg/operators/v1" + olmv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1" + "github.com/pkg/errors" + "golang.org/x/mod/semver" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/equality" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/types" + utilerrors "k8s.io/apimachinery/pkg/util/errors" + "k8s.io/klog" + "sigs.k8s.io/controller-runtime/pkg/client" + + operatorv1alpha1 "github.com/IBM/operand-deployment-lifecycle-manager/v4/api/v1alpha1" + "github.com/IBM/operand-deployment-lifecycle-manager/v4/controllers/constant" + "github.com/IBM/operand-deployment-lifecycle-manager/v4/controllers/util" +) + +func (r *Reconciler) reconcileOperator(ctx context.Context, requestInstance *operatorv1alpha1.OperandRequest) error { + klog.V(1).Infof("Reconciling Operators for OperandRequest: %s/%s", requestInstance.GetNamespace(), requestInstance.GetName()) + // It is important to NOT pass the set directly into defer functions. + // The arguments to the deferred function are evaluated when the defer executes + remainingOperands := gset.NewSet() + for _, m := range requestInstance.Status.Members { + remainingOperands.Add(m.Name) + } + // Update request status + defer func() { + requestInstance.FreshMemberStatus(&remainingOperands) + requestInstance.UpdateClusterPhase() + }() + + for _, req := range requestInstance.Spec.Requests { + registryKey := requestInstance.GetRegistryKey(req) + registryInstance, err := r.GetOperandRegistry(ctx, registryKey) + if err != nil { + if apierrors.IsNotFound(err) { + r.Recorder.Eventf(requestInstance, corev1.EventTypeWarning, "NotFound", "NotFound OperandRegistry NamespacedName %s", registryKey.String()) + requestInstance.SetNotFoundOperatorFromRegistryCondition(registryKey.String(), operatorv1alpha1.ResourceTypeOperandRegistry, corev1.ConditionTrue, &r.Mutex) + } else { + requestInstance.SetNoSuitableRegistryCondition(registryKey.String(), err.Error(), operatorv1alpha1.ResourceTypeOperandRegistry, corev1.ConditionTrue, &r.Mutex) + } + t := time.Now() + formatted := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02d", + t.Year(), t.Month(), t.Day(), + t.Hour(), t.Minute(), t.Second()) + mergePatch, _ := json.Marshal(map[string]interface{}{ + "metadata": map[string]interface{}{ + "annotations": map[string]interface{}{ + constant.FindOperandRegistry: formatted, + }, + }, + }) + if patchErr := r.Patch(ctx, requestInstance, client.RawPatch(types.MergePatchType, mergePatch)); patchErr != nil { + return utilerrors.NewAggregate([]error{err, patchErr}) + } + klog.Errorf("Failed to get suitable OperandRegistry %s: %v", registryKey.String(), err) + } + merr := &util.MultiErr{} + + // Get the chunk size + var chunkSize int + if r.StepSize > 0 { + chunkSize = r.StepSize + } else { + chunkSize = 1 + } + + // reconcile subscription in batch + for i := 0; i < len(req.Operands); i += chunkSize { + j := i + chunkSize + if j > len(req.Operands) { + j = len(req.Operands) + } + var ( + wg sync.WaitGroup + ) + for _, operand := range req.Operands[i:j] { + wg.Add(1) + go func(ctx context.Context, requestInstance *operatorv1alpha1.OperandRequest, registryInstance *operatorv1alpha1.OperandRegistry, operand operatorv1alpha1.Operand, registryKey types.NamespacedName, mu *sync.Mutex) { + defer wg.Done() + if err := r.reconcileSubscription(ctx, requestInstance, registryInstance, operand, registryKey, mu); err != nil { + mu.Lock() + defer mu.Unlock() + merr.Add(err) + } + }(ctx, requestInstance, registryInstance, operand, registryKey, &r.Mutex) + } + wg.Wait() + } + + if len(merr.Errors) != 0 { + return merr + } + } + + // Delete specific operators + if err := r.absentOperatorsAndOperands(ctx, requestInstance, &remainingOperands); err != nil { + return err + } + klog.V(1).Infof("Finished reconciling Operators for OperandRequest: %s/%s", requestInstance.GetNamespace(), requestInstance.GetName()) + + return nil +} + +func (r *Reconciler) reconcileSubscription(ctx context.Context, requestInstance *operatorv1alpha1.OperandRequest, registryInstance *operatorv1alpha1.OperandRegistry, operand operatorv1alpha1.Operand, registryKey types.NamespacedName, mu sync.Locker) error { + // Check the requested Operand if exist in specific OperandRegistry + var opt *operatorv1alpha1.Operator + if registryInstance != nil { + var err error + opt, err = r.GetOperandFromRegistry(ctx, registryInstance, operand.Name) + if err != nil { + return err + } + } + if opt == nil { + if registryInstance != nil { + klog.V(1).Infof("Operator %s not found in the OperandRegistry %s/%s", operand.Name, registryInstance.Namespace, registryInstance.Name) + } + requestInstance.SetNotFoundOperatorFromRegistryCondition(operand.Name, operatorv1alpha1.ResourceTypeSub, corev1.ConditionTrue, mu) + requestInstance.SetMemberStatus(operand.Name, operatorv1alpha1.OperatorNotFound, operatorv1alpha1.ServiceNotFound, mu) + return nil + } + if opt.Scope == operatorv1alpha1.ScopePrivate && requestInstance.Namespace != registryInstance.Namespace { + klog.Warningf("Operator %s is private. It can't be requested from namespace %s", operand.Name, requestInstance.Namespace) + requestInstance.SetOutofScopeCondition(operand.Name, operatorv1alpha1.ResourceTypeSub, corev1.ConditionTrue, mu) + return nil + } + + // Check subscription if exist + namespace := r.GetOperatorNamespace(opt.InstallMode, opt.Namespace) + sub, err := r.GetSubscription(ctx, opt.Name, namespace, registryInstance.Namespace, opt.PackageName) + + if opt.UserManaged { + klog.Infof("Skip installing operator %s because it is managed by user", opt.PackageName) + csvList, err := r.GetClusterServiceVersionListFromPackage(ctx, opt.PackageName, namespace) + if err != nil { + return errors.Wrapf(err, "failed to get CSV from package %s/%s", namespace, opt.PackageName) + } + if len(csvList) == 0 { + return errors.New("operator " + opt.Name + " is user managed, but no CSV exists, waiting...") + } + requestInstance.SetMemberStatus(opt.Name, operatorv1alpha1.OperatorUpdating, "", mu) + return nil + } + + if sub == nil && err == nil { + if opt.InstallMode == operatorv1alpha1.InstallModeNoop { + requestInstance.SetNoSuitableRegistryCondition(registryKey.String(), opt.Name+" is in maintenance status", operatorv1alpha1.ResourceTypeOperandRegistry, corev1.ConditionTrue, &r.Mutex) + requestInstance.SetMemberStatus(operand.Name, operatorv1alpha1.OperatorRunning, operatorv1alpha1.ServiceRunning, mu) + } else { + // Subscription does not exist, create a new one + if err = r.createSubscription(ctx, requestInstance, opt, registryKey); err != nil { + requestInstance.SetMemberStatus(opt.Name, operatorv1alpha1.OperatorFailed, "", mu) + return err + } + requestInstance.SetMemberStatus(opt.Name, operatorv1alpha1.OperatorInstalling, "", mu) + } + return nil + } else if err != nil { + return err + } + + // Subscription existing and managed by OperandRequest controller + if _, ok := sub.Labels[constant.OpreqLabel]; ok { + originalSub := sub.DeepCopy() + var isMatchedChannel bool + var isInScope bool + + if sub.Namespace == opt.Namespace { + isInScope = true + } else { + var nsAnnoSlice []string + namespaceReg, _ := regexp.Compile(`^(.*)\.(.*)\.(.*)\/operatorNamespace`) + for anno, ns := range sub.Annotations { + if namespaceReg.MatchString(anno) { + nsAnnoSlice = append(nsAnnoSlice, ns) + } + } + if len(nsAnnoSlice) != 0 && !util.Contains(nsAnnoSlice, sub.Namespace) { + + if r.checkUninstallLabel(sub) { + klog.V(1).Infof("Operator %s has label operator.ibm.com/opreq-do-not-uninstall. Skip the uninstall", opt.Name) + return nil + } + + if err = r.deleteSubscription(ctx, requestInstance, sub); err != nil { + requestInstance.SetMemberStatus(opt.Name, operatorv1alpha1.OperatorFailed, "", mu) + return err + } + requestInstance.SetMemberStatus(opt.Name, operatorv1alpha1.OperatorUpdating, "", mu) + return nil + } + } + + // add annotations to existing Subscriptions for upgrade case + if sub.Annotations == nil { + sub.Annotations = make(map[string]string) + } + sub.Annotations[registryKey.Namespace+"."+registryKey.Name+"/registry"] = "true" + sub.Annotations[registryKey.Namespace+"."+registryKey.Name+"/config"] = "true" + sub.Annotations[requestInstance.Namespace+"."+requestInstance.Name+"."+operand.Name+"/request"] = opt.Channel + sub.Annotations[requestInstance.Namespace+"."+requestInstance.Name+"."+operand.Name+"/operatorNamespace"] = namespace + + if opt.InstallMode == operatorv1alpha1.InstallModeNoop { + isMatchedChannel = true + requestInstance.SetNoSuitableRegistryCondition(registryKey.String(), opt.Name+" is in maintenance status", operatorv1alpha1.ResourceTypeOperandRegistry, corev1.ConditionTrue, &r.Mutex) + requestInstance.SetMemberStatus(operand.Name, operatorv1alpha1.OperatorRunning, operatorv1alpha1.ServiceRunning, mu) + + // check if sub.Spec.Channel and opt.Channel are valid semantic version + // set annotation channel back to previous one if sub.Spec.Channel is lower than opt.Channel + // To avoid upgrade from one maintenance version to another maintenance version like from v3 to v3.23 + subChanel := util.FindSemantic(sub.Spec.Channel) + optChannel := util.FindSemantic(opt.Channel) + if semver.IsValid(subChanel) && semver.IsValid(optChannel) && semver.Compare(subChanel, optChannel) < 0 { + sub.Annotations[requestInstance.Namespace+"."+requestInstance.Name+"."+operand.Name+"/request"] = sub.Spec.Channel + } + } else if opt.SourceNamespace == "" || opt.SourceName == "" { + klog.Errorf("Failed to find catalogsource for operator %s with channel %s", opt.Name, opt.Channel) + requestInstance.SetMemberStatus(operand.Name, operatorv1alpha1.OperatorFailed, "", mu) + } else { + requestInstance.SetNotFoundOperatorFromRegistryCondition(operand.Name, operatorv1alpha1.ResourceTypeSub, corev1.ConditionFalse, mu) + + if minChannel := util.FindMinSemverFromAnnotations(sub.Annotations, sub.Spec.Channel); minChannel != "" { + sub.Spec.Channel = minChannel + } + + channels := []string{opt.Channel} + if channels = append(channels, opt.FallbackChannels...); util.Contains(channels, sub.Spec.Channel) { + isMatchedChannel = true + } + // update the spec iff channel in sub matches channel + if sub.Spec.Channel == opt.Channel { + sub.Spec.CatalogSource = opt.SourceName + sub.Spec.CatalogSourceNamespace = opt.SourceNamespace + sub.Spec.Package = opt.PackageName + + if opt.InstallPlanApproval != "" && sub.Spec.InstallPlanApproval != opt.InstallPlanApproval { + sub.Spec.InstallPlanApproval = opt.InstallPlanApproval + } + if opt.SubscriptionConfig != nil { + sub.Spec.Config = opt.SubscriptionConfig + } + } + + } + if compareSub(sub, originalSub) { + if err = r.updateSubscription(ctx, requestInstance, sub); err != nil { + requestInstance.SetMemberStatus(opt.Name, operatorv1alpha1.OperatorFailed, "", mu) + return err + } + requestInstance.SetMemberStatus(opt.Name, operatorv1alpha1.OperatorUpdating, "", mu) + } + + if !isMatchedChannel || !isInScope { + requestInstance.SetNoConflictOperatorCondition(operand.Name, operatorv1alpha1.ResourceTypeSub, corev1.ConditionFalse, mu) + requestInstance.SetMemberStatus(opt.Name, operatorv1alpha1.OperatorFailed, "", mu) + } else { + requestInstance.SetNoConflictOperatorCondition(operand.Name, operatorv1alpha1.ResourceTypeSub, corev1.ConditionTrue, mu) + } + } else { + // Subscription existing and not managed by OperandRequest controller + klog.V(1).Infof("Subscription %s in namespace %s isn't created by ODLM. Ignore update/delete it.", sub.Name, sub.Namespace) + } + return nil +} + +func (r *Reconciler) createSubscription(ctx context.Context, cr *operatorv1alpha1.OperandRequest, opt *operatorv1alpha1.Operator, key types.NamespacedName) error { + namespace := r.GetOperatorNamespace(opt.InstallMode, opt.Namespace) + klog.V(3).Info("Subscription Namespace: ", namespace) + + co := r.generateClusterObjects(opt, key, types.NamespacedName{Namespace: cr.Namespace, Name: cr.Name}) + + // Create required namespace + ns := co.namespace + klog.V(3).Info("Creating the Namespace for Operator: " + opt.Name) + + // Compare namespace and create namespace + oprNs := util.GetOperatorNamespace() + if ns.Name != oprNs && ns.Name != constant.ClusterOperatorNamespace { + if err := r.Create(ctx, ns); err != nil && !apierrors.IsAlreadyExists(err) { + klog.Warningf("failed to create the namespace %s, please make sure it exists: %s", ns.Name, err) + } + } + + if namespace != constant.ClusterOperatorNamespace { + // Create required operatorgroup + existOG := &olmv1.OperatorGroupList{} + if err := r.Client.List(ctx, existOG, &client.ListOptions{Namespace: co.operatorGroup.Namespace}); err != nil { + return err + } + if len(existOG.Items) == 0 { + og := co.operatorGroup + klog.V(3).Info("Creating the OperatorGroup for Subscription: " + opt.Name) + if err := r.Create(ctx, og); err != nil && !apierrors.IsAlreadyExists(err) { + return err + } + } + } + + // Create subscription + klog.V(2).Info("Creating the Subscription: " + opt.Name) + if co.subscription.Spec.CatalogSource == "" || co.subscription.Spec.CatalogSourceNamespace == "" { + return fmt.Errorf("failed to find catalogsource for subscription %s/%s", co.subscription.Namespace, co.subscription.Name) + } + + sub := co.subscription + cr.SetCreatingCondition(sub.Name, operatorv1alpha1.ResourceTypeSub, corev1.ConditionTrue, &r.Mutex) + + if err := r.Create(ctx, sub); err != nil && !apierrors.IsAlreadyExists(err) { + cr.SetCreatingCondition(sub.Name, operatorv1alpha1.ResourceTypeSub, corev1.ConditionFalse, &r.Mutex) + return err + } + return nil +} + +func (r *Reconciler) updateSubscription(ctx context.Context, cr *operatorv1alpha1.OperandRequest, sub *olmv1alpha1.Subscription) error { + + klog.V(2).Infof("Updating Subscription %s/%s ...", sub.Namespace, sub.Name) + cr.SetUpdatingCondition(sub.Name, operatorv1alpha1.ResourceTypeSub, corev1.ConditionTrue, &r.Mutex) + + if err := r.Update(ctx, sub); err != nil { + cr.SetUpdatingCondition(sub.Name, operatorv1alpha1.ResourceTypeSub, corev1.ConditionFalse, &r.Mutex) + return err + } + return nil +} + +func (r *Reconciler) deleteSubscription(ctx context.Context, cr *operatorv1alpha1.OperandRequest, sub *olmv1alpha1.Subscription) error { + + klog.V(2).Infof("Deleting Subscription %s/%s ...", sub.Namespace, sub.Name) + + csvList, err := r.GetClusterServiceVersionList(ctx, sub) + // If can't get CSV, requeue the request + if err != nil { + return err + } + + if csvList != nil { + klog.Infof("Found %d ClusterServiceVersions for Subscription %s/%s", len(csvList), sub.Namespace, sub.Name) + for _, csv := range csvList { + klog.V(3).Info("Set Deleting Condition in the operandRequest") + cr.SetDeletingCondition(csv.Name, operatorv1alpha1.ResourceTypeCsv, corev1.ConditionTrue, &r.Mutex) + + klog.V(1).Infof("Deleting the ClusterServiceVersion, Namespace: %s, Name: %s", csv.Namespace, csv.Name) + if err := r.Delete(ctx, csv); err != nil { + cr.SetDeletingCondition(csv.Name, operatorv1alpha1.ResourceTypeCsv, corev1.ConditionFalse, &r.Mutex) + return err + } + } + } + + klog.V(2).Infof("Deleting the Subscription, Namespace: %s, Name: %s", sub.Namespace, sub.Name) + cr.SetDeletingCondition(sub.Name, operatorv1alpha1.ResourceTypeSub, corev1.ConditionTrue, &r.Mutex) + + if err := r.Delete(ctx, sub); err != nil { + if apierrors.IsNotFound(err) { + klog.Warningf("Subscription %s was not found in namespace %s", sub.Name, sub.Namespace) + } else { + cr.SetDeletingCondition(sub.Name, operatorv1alpha1.ResourceTypeSub, corev1.ConditionFalse, &r.Mutex) + return err + } + } + + klog.V(1).Infof("Subscription %s/%s is deleted", sub.Namespace, sub.Name) + return nil +} + +func (r *Reconciler) uninstallOperatorsAndOperands(ctx context.Context, operandName string, requestInstance *operatorv1alpha1.OperandRequest, registryInstance *operatorv1alpha1.OperandRegistry, configInstance *operatorv1alpha1.OperandConfig) error { + // No error handling for un-installation step in case Catalog has been deleted + op, _ := r.GetOperandFromRegistry(ctx, registryInstance, operandName) + if op == nil { + klog.Warningf("Operand %s not found", operandName) + return nil + } + + namespace := r.GetOperatorNamespace(op.InstallMode, op.Namespace) + sub, err := r.GetSubscription(ctx, operandName, namespace, registryInstance.Namespace, op.PackageName) + if sub == nil && err == nil { + klog.V(3).Infof("There is no Subscription %s or %s in the namespace %s and %s", operandName, op.PackageName, namespace, registryInstance.Namespace) + return nil + } else if err != nil { + klog.Errorf("Failed to get Subscription %s or %s in the namespace %s and %s", operandName, op.PackageName, namespace, registryInstance.Namespace) + return err + } + + if sub.Labels == nil { + // Subscription existing and not managed by OperandRequest controller + klog.V(2).Infof("Subscription %s in the namespace %s isn't created by ODLM", sub.Name, sub.Namespace) + return nil + } + + if _, ok := sub.Labels[constant.OpreqLabel]; !ok { + if !op.UserManaged { + klog.V(2).Infof("Subscription %s in the namespace %s isn't created by ODLM and isn't user managed", sub.Name, sub.Namespace) + return nil + } + } + + uninstallOperator, uninstallOperand := checkSubAnnotationsForUninstall(requestInstance.ObjectMeta.Name, requestInstance.ObjectMeta.Namespace, op.Name, op.InstallMode, sub) + if !uninstallOperand && !uninstallOperator { + if err = r.updateSubscription(ctx, requestInstance, sub); err != nil { + requestInstance.SetMemberStatus(op.Name, operatorv1alpha1.OperatorFailed, "", &r.Mutex) + return err + } + requestInstance.SetMemberStatus(op.Name, operatorv1alpha1.OperatorUpdating, "", &r.Mutex) + + klog.V(1).Infof("No deletion, subscription %s/%s and its operands are still requested by other OperandRequests", sub.Namespace, sub.Name) + return nil + } + + if deploymentList, err := r.GetDeploymentListFromPackage(ctx, op.PackageName, op.Namespace); err != nil { + // If can't get deployment, requeue the request + return err + } else if deploymentList != nil { + klog.Infof("Found %d Deployment for package %s/%s", len(deploymentList), op.Name, namespace) + if uninstallOperand { + klog.V(2).Infof("Deleting all the Custom Resources for Deployment, Namespace: %s, Name: %s", deploymentList[0].Namespace, deploymentList[0].Name) + if err := r.deleteAllCustomResource(ctx, deploymentList[0], requestInstance, configInstance, operandName, configInstance.Namespace); err != nil { + return err + } + klog.V(2).Infof("Deleting all the k8s Resources for Deployment, Namespace: %s, Name: %s", deploymentList[0].Namespace, deploymentList[0].Name) + if err := r.deleteAllK8sResource(ctx, configInstance, operandName, configInstance.Namespace); err != nil { + return err + } + } + if uninstallOperator { + if r.checkUninstallLabel(sub) { + klog.V(1).Infof("Operator %s has label operator.ibm.com/opreq-do-not-uninstall. Skip the uninstall", op.Name) + return nil + } + + klog.V(3).Info("Set Deleting Condition in the operandRequest") + //TODO replace the resource types set in these setdeletingcondition functions + requestInstance.SetDeletingCondition(deploymentList[0].Name, operatorv1alpha1.ResourceTypeCsv, corev1.ConditionTrue, &r.Mutex) + + for _, deployment := range deploymentList { + klog.V(1).Infof("Deleting the deployment, Namespace: %s, Name: %s", deployment.Namespace, deployment.Name) + if err := r.Delete(ctx, deployment); err != nil { + requestInstance.SetDeletingCondition(deployment.Name, operatorv1alpha1.ResourceTypeCsv, corev1.ConditionFalse, &r.Mutex) + return errors.Wrapf(err, "failed to delete the deployment %s/%s", deployment.Namespace, deployment.Name) + } + } + } + } + + if uninstallOperator { + klog.V(2).Infof("Deleting the Subscription, Namespace: %s, Name: %s", namespace, op.Name) + requestInstance.SetDeletingCondition(op.Name, operatorv1alpha1.ResourceTypeSub, corev1.ConditionTrue, &r.Mutex) + + if err := r.Delete(ctx, sub); err != nil { + if apierrors.IsNotFound(err) { + klog.Warningf("Subscription %s was not found in namespace %s", op.Name, namespace) + } else { + requestInstance.SetDeletingCondition(op.Name, operatorv1alpha1.ResourceTypeSub, corev1.ConditionFalse, &r.Mutex) + return errors.Wrap(err, "failed to delete subscription") + } + } + + klog.V(1).Infof("Subscription %s/%s is deleted", namespace, op.Name) + } else { + if err = r.updateSubscription(ctx, requestInstance, sub); err != nil { + requestInstance.SetMemberStatus(op.Name, operatorv1alpha1.OperatorFailed, "", &r.Mutex) + return err + } + requestInstance.SetMemberStatus(op.Name, operatorv1alpha1.OperatorUpdating, "", &r.Mutex) + klog.V(1).Infof("Subscription %s/%s is not deleted due to the annotation from OperandRequest", namespace, op.Name) + } + + return nil +} + +func (r *Reconciler) uninstallOperands(ctx context.Context, operandName string, requestInstance *operatorv1alpha1.OperandRequest, registryInstance *operatorv1alpha1.OperandRegistry, configInstance *operatorv1alpha1.OperandConfig) error { + // No error handling for un-installation step in case Catalog has been deleted + op, _ := r.GetOperandFromRegistry(ctx, registryInstance, operandName) + if op == nil { + klog.Warningf("Operand %s not found", operandName) + return nil + } + + namespace := r.GetOperatorNamespace(op.InstallMode, op.Namespace) + uninstallOperand := false + operatorStatus, ok := registryInstance.Status.OperatorsStatus[op.Name] + if !ok { + return nil + } + if operatorStatus.ReconcileRequests == nil { + return nil + } + if len(operatorStatus.ReconcileRequests) > 1 { + return nil + } + if operatorStatus.ReconcileRequests[0].Name == requestInstance.Name { + uninstallOperand = true + } + + // get list reconcileRequests + // ignore the name which triggered reconcile + // if list is empty then uninstallOperand = true + + if deploymentList, err := r.GetDeploymentListFromPackage(ctx, op.PackageName, op.Namespace); err != nil { + // If can't get deployment, requeue the request + return err + } else if deploymentList != nil { + klog.Infof("Found %d Deployment for package %s/%s", len(deploymentList), op.Name, namespace) + if uninstallOperand { + klog.V(2).Infof("Deleting all the Custom Resources for Deployment, Namespace: %s, Name: %s", deploymentList[0].Namespace, deploymentList[0].Name) + if err := r.deleteAllCustomResource(ctx, deploymentList[0], requestInstance, configInstance, operandName, configInstance.Namespace); err != nil { + return err + } + klog.V(2).Infof("Deleting all the k8s Resources for Deployment, Namespace: %s, Name: %s", deploymentList[0].Namespace, deploymentList[0].Name) + if err := r.deleteAllK8sResource(ctx, configInstance, operandName, configInstance.Namespace); err != nil { + return err + } + } + } + + return nil +} + +func (r *Reconciler) absentOperatorsAndOperands(ctx context.Context, requestInstance *operatorv1alpha1.OperandRequest, remainingOperands *gset.Set) error { + needDeletedOperands := r.getNeedDeletedOperands(requestInstance) + + var ( + wg sync.WaitGroup + ) + + for _, req := range requestInstance.Spec.Requests { + registryKey := requestInstance.GetRegistryKey(req) + registryInstance, err := r.GetOperandRegistry(ctx, registryKey) + if err != nil { + return err + } + configInstance, err := r.GetOperandConfig(ctx, registryKey) + if err != nil { + if apierrors.IsNotFound(err) { + configInstance = &operatorv1alpha1.OperandConfig{} + } else { + return err + } + } + merr := &util.MultiErr{} + remainingOp := needDeletedOperands.Clone() + for o := range needDeletedOperands.Iter() { + var ( + o = o + ) + wg.Add(1) + go func() { + defer wg.Done() + op, _ := r.GetOperandFromRegistry(ctx, registryInstance, fmt.Sprintf("%v", o)) + if op == nil { + klog.Warningf("Operand %s not found", fmt.Sprintf("%v", o)) + } + if op != nil && !op.UserManaged { + if err := r.uninstallOperatorsAndOperands(ctx, fmt.Sprintf("%v", o), requestInstance, registryInstance, configInstance); err != nil { + r.Mutex.Lock() + defer r.Mutex.Unlock() + merr.Add(err) + return // return here to avoid removing the operand from remainingOperands + } + } else { + if err := r.uninstallOperands(ctx, fmt.Sprintf("%v", o), requestInstance, registryInstance, configInstance); err != nil { + r.Mutex.Lock() + defer r.Mutex.Unlock() + merr.Add(err) + return // return here to avoid removing the operand from remainingOperands + } + } + requestInstance.RemoveServiceStatus(fmt.Sprintf("%v", o), &r.Mutex) + (*remainingOperands).Remove(o) + remainingOp.Remove(o) + }() + } + timeout := util.WaitTimeout(&wg, constant.DefaultSubDeleteTimeout) + if timeout { + merr.Add(fmt.Errorf("timeout for cleaning up subscription %v", strings.Trim(fmt.Sprint(remainingOp.ToSlice()), "[]"))) + } + if len(merr.Errors) != 0 { + return merr + } + + } + return nil +} + +func (r *Reconciler) getNeedDeletedOperands(requestInstance *operatorv1alpha1.OperandRequest) gset.Set { + klog.V(3).Info("Getting the operator need to be delete") + deployedOperands := gset.NewSet() + for _, req := range requestInstance.Status.Members { + deployedOperands.Add(req.Name) + } + + currentOperands := gset.NewSet() + if requestInstance.DeletionTimestamp.IsZero() { + for _, req := range requestInstance.Spec.Requests { + for _, op := range req.Operands { + currentOperands.Add(op.Name) + } + } + } + + needDeleteOperands := deployedOperands.Difference(currentOperands) + return needDeleteOperands +} + +func (r *Reconciler) generateClusterObjects(o *operatorv1alpha1.Operator, registryKey, requestKey types.NamespacedName) *clusterObjects { + klog.V(3).Info("Generating Cluster Objects") + co := &clusterObjects{} + labels := map[string]string{ + constant.OpreqLabel: "true", + } + + klog.V(3).Info("Generating Namespace: ", o.Namespace) + // Namespace Object + co.namespace = &corev1.Namespace{ + TypeMeta: metav1.TypeMeta{ + Kind: "Namespace", + APIVersion: "v1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: o.Namespace, + Labels: labels, + }, + } + + // Operator Group Object + klog.V(3).Info("Generating Operator Group in the Namespace: ", o.Namespace, " with target namespace: ", o.TargetNamespaces) + og := generateOperatorGroup(o.Namespace, o.TargetNamespaces) + co.operatorGroup = og + + // The namespace is 'openshift-operators' when installMode is cluster + namespace := r.GetOperatorNamespace(o.InstallMode, o.Namespace) + + annotations := map[string]string{ + registryKey.Namespace + "." + registryKey.Name + "/registry": "true", + registryKey.Namespace + "." + registryKey.Name + "/config": "true", + requestKey.Namespace + "." + requestKey.Name + "." + o.Name + "/request": o.Channel, + requestKey.Namespace + "." + requestKey.Name + "." + o.Name + "/operatorNamespace": namespace, + } + + // Subscription Object + sub := &olmv1alpha1.Subscription{ + ObjectMeta: metav1.ObjectMeta{ + Name: o.PackageName, + Namespace: namespace, + Labels: labels, + Annotations: annotations, + }, + Spec: &olmv1alpha1.SubscriptionSpec{ + Channel: o.Channel, + Package: o.PackageName, + CatalogSource: o.SourceName, + CatalogSourceNamespace: o.SourceNamespace, + InstallPlanApproval: o.InstallPlanApproval, + StartingCSV: o.StartingCSV, + Config: o.SubscriptionConfig, + }, + } + sub.SetGroupVersionKind(schema.GroupVersionKind{Group: olmv1alpha1.SchemeGroupVersion.Group, Kind: "Subscription", Version: olmv1alpha1.SchemeGroupVersion.Version}) + klog.V(3).Info("Generating Subscription: ", o.PackageName, " in the Namespace: ", namespace) + co.subscription = sub + return co +} + +func generateOperatorGroup(namespace string, targetNamespaces []string) *olmv1.OperatorGroup { + labels := map[string]string{ + constant.OpreqLabel: "true", + } + if targetNamespaces == nil { + targetNamespaces = append(targetNamespaces, namespace) + } + // Operator Group Object + og := &olmv1.OperatorGroup{ + ObjectMeta: metav1.ObjectMeta{ + Name: "operand-deployment-lifecycle-manager-operatorgroup", + Namespace: namespace, + Labels: labels, + }, + Spec: olmv1.OperatorGroupSpec{ + TargetNamespaces: targetNamespaces, + }, + } + og.SetGroupVersionKind(schema.GroupVersionKind{Group: olmv1.SchemeGroupVersion.Group, Kind: "OperatorGroup", Version: olmv1.SchemeGroupVersion.Version}) + + return og +} + +func (r *Reconciler) checkUninstallLabel(sub *olmv1alpha1.Subscription) bool { + subLabels := sub.GetLabels() + return subLabels[constant.NotUninstallLabel] == "true" +} + +func compareSub(sub *olmv1alpha1.Subscription, originalSub *olmv1alpha1.Subscription) (needUpdate bool) { + return !equality.Semantic.DeepEqual(sub.Spec, originalSub.Spec) || !equality.Semantic.DeepEqual(sub.Annotations, originalSub.Annotations) +} + +func CheckSingletonServices(operator string) bool { + singletonServices := []string{"ibm-cert-manager-operator", "ibm-licensing-operator"} + return util.Contains(singletonServices, operator) +} + +// checkSubAnnotationsForUninstall checks the annotations of a Subscription object +// to determine whether the operator and operand should be uninstalled. +// It takes the name of the OperandRequest, the namespace of the OperandRequest, +// the name of the operator, and a pointer to the Subscription object as input. +// It returns two boolean values: uninstallOperator and uninstallOperand. +// If uninstallOperator is true, it means the operator should be uninstalled. +// If uninstallOperand is true, it means the operand should be uninstalled. +func checkSubAnnotationsForUninstall(reqName, reqNs, opName, installMode string, sub *olmv1alpha1.Subscription) (bool, bool) { + uninstallOperator := true + uninstallOperand := true + + delete(sub.Annotations, reqNs+"."+reqName+"."+opName+"/request") + delete(sub.Annotations, reqNs+"."+reqName+"."+opName+"/operatorNamespace") + + var opreqNsSlice []string + var operatorNameSlice []string + namespaceReg, _ := regexp.Compile(`^(.*)\.(.*)\.(.*)\/operatorNamespace`) + channelReg, _ := regexp.Compile(`^(.*)\.(.*)\.(.*)\/request`) + + for key, value := range sub.Annotations { + if namespaceReg.MatchString(key) { + opreqNsSlice = append(opreqNsSlice, value) + } + + if channelReg.MatchString(key) { + // Extract the operator name from the key + keyParts := strings.Split(key, "/") + annoPrefix := strings.Split(keyParts[0], ".") + operatorNameSlice = append(operatorNameSlice, annoPrefix[len(annoPrefix)-1]) + } + } + + // If one of remaining /operatorNamespace annotations' values is the same as subscription's namespace, + // the operator should NOT be uninstalled. + if util.Contains(opreqNsSlice, sub.Namespace) { + uninstallOperator = false + } + + if value, ok := sub.Labels[constant.OpreqLabel]; !ok || value != "true" { + uninstallOperator = false + } + + // When one of following conditions are met, the operand will NOT be uninstalled: + // 1. operator is not uninstalled AND intallMode is no-op. + // 2. operator is uninstalled AND at least one other /operatorNamespace annotation exists. + // 2. remaining /request annotation's values contain the same operator name + if (!uninstallOperator && installMode == operatorv1alpha1.InstallModeNoop) || (uninstallOperator && len(opreqNsSlice) != 0) || util.Contains(operatorNameSlice, opName) { + uninstallOperand = false + } + + return uninstallOperator, uninstallOperand +} diff --git a/controllers/operator/manager.go b/controllers/operator/manager.go index a99b554c..cfbadb4d 100644 --- a/controllers/operator/manager.go +++ b/controllers/operator/manager.go @@ -28,6 +28,7 @@ import ( operatorsv1 "github.com/operator-framework/operator-lifecycle-manager/pkg/package-server/apis/operators/v1" "github.com/pkg/errors" "golang.org/x/mod/semver" + appsv1 "k8s.io/api/apps/v1" authorizationv1 "k8s.io/api/authorization/v1" corev1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" @@ -575,6 +576,47 @@ func (m *ODLMOperator) GetClusterServiceVersionListFromPackage(ctx context.Conte return csvs, nil } +func (m *ODLMOperator) GetDeploymentListFromPackage(ctx context.Context, name, namespace string) ([]*appsv1.Deployment, error) { + packageName := name + deploymentNamespace := namespace + + deploymentList := &appsv1.DeploymentList{} + + opts := []client.ListOption{ + client.InNamespace(deploymentNamespace), + } + + if err := m.Reader.List(ctx, deploymentList, opts...); err != nil { + if apierrors.IsNotFound(err) || len(deploymentList.Items) == 0 { + klog.V(1).Infof("No Deployment found") + return nil, nil + } + return nil, errors.Wrapf(err, "failed to list Deployments") + } + + var deployments []*appsv1.Deployment + // filter deploymentList to find one(s) that contain packageName + for _, v := range deploymentList.Items { + deployment := v + if deployment.Annotations == nil { + continue + } + // if _, ok := deployment.Annotations["operatorframework.io/properties"]; !ok { + // continue + // } + // annotation := fmt.Sprintf("\"packageName\":\"%s\"", packageName) + klog.V(1).Infof("Get Deployment %s with package name %s", deployment.Name, packageName) + if !strings.Contains(deployment.Annotations["packageName"], packageName) { + continue + } + klog.V(1).Infof("Get Deployment %s in the namespace %s", deployment.Name, deploymentNamespace) + deployments = append(deployments, &deployment) + } + + klog.V(1).Infof("Get %v / %v Deployment in the namespace %s", len(deployments), len(deploymentList.Items), deploymentNamespace) + return deployments, nil +} + func (m *ODLMOperator) DeleteRedundantCSV(ctx context.Context, csvName, operatorNs, serviceNs, packageName string) error { // Get the csv by its name and namespace csv := &olmv1alpha1.ClusterServiceVersion{} diff --git a/controllers/util/util.go b/controllers/util/util.go index 86ae4fff..2aea936f 100644 --- a/controllers/util/util.go +++ b/controllers/util/util.go @@ -97,6 +97,15 @@ func GetWatchNamespace() string { return ns } +// GetNoOLM returns boolean NoOLM enabled +func GetNoOLM() string { + enabled, found := os.LookupEnv("NO_OLM") + if !found { + return "false" + } + return enabled +} + // GetInstallScope returns the scope of the installation func GetInstallScope() string { ns, found := os.LookupEnv("INSTALL_SCOPE") diff --git a/main.go b/main.go index 45ba6bb9..0f9b6dc0 100644 --- a/main.go +++ b/main.go @@ -47,6 +47,7 @@ import ( "github.com/IBM/operand-deployment-lifecycle-manager/v4/controllers/operandconfig" "github.com/IBM/operand-deployment-lifecycle-manager/v4/controllers/operandregistry" "github.com/IBM/operand-deployment-lifecycle-manager/v4/controllers/operandrequest" + "github.com/IBM/operand-deployment-lifecycle-manager/v4/controllers/operandrequestnoolm" deploy "github.com/IBM/operand-deployment-lifecycle-manager/v4/controllers/operator" "github.com/IBM/operand-deployment-lifecycle-manager/v4/controllers/operatorchecker" "github.com/IBM/operand-deployment-lifecycle-manager/v4/controllers/operatorconfig" @@ -123,12 +124,23 @@ func main() { klog.Errorf("unable to start manager: %v", err) os.Exit(1) } - if err = (&operandrequest.Reconciler{ - ODLMOperator: deploy.NewODLMOperator(mgr, "OperandRequest"), - StepSize: *stepSize, - }).SetupWithManager(mgr); err != nil { - klog.Errorf("unable to create controller OperandRequest: %v", err) - os.Exit(1) + noolm := util.GetNoOLM() + if noolm == "true" { + if err = (&operandrequestnoolm.Reconciler{ + ODLMOperator: deploy.NewODLMOperator(mgr, "OperandRequest"), + StepSize: *stepSize, + }).SetupWithManager(mgr); err != nil { + klog.Errorf("unable to create controller OperandRequestNoOLM: %v", err) + os.Exit(1) + } + } else { + if err = (&operandrequest.Reconciler{ + ODLMOperator: deploy.NewODLMOperator(mgr, "OperandRequest"), + StepSize: *stepSize, + }).SetupWithManager(mgr); err != nil { + klog.Errorf("unable to create controller OperandRequest: %v", err) + os.Exit(1) + } } if err = (&operandconfig.Reconciler{ ODLMOperator: deploy.NewODLMOperator(mgr, "OperandConfig"), From f36b82740f177f98df899214c41382903f272bfc Mon Sep 17 00:00:00 2001 From: Allen Li <46284272+qpdpQ@users.noreply.github.com> Date: Thu, 30 Jan 2025 22:14:30 -0500 Subject: [PATCH 170/179] Helm chart for ODLM (#1106) * helm init Signed-off-by: Allen Li * resource init Signed-off-by: Allen Li * add olm role and rolebinding Signed-off-by: Allen Li * update namespaces Signed-off-by: Allen Li * add comment Signed-off-by: Allen Li * add comment Signed-off-by: Allen Li * update imagepullsecret Signed-off-by: Allen Li * typo Signed-off-by: Allen Li * remove operandregistry and operadconfig Signed-off-by: Allen Li * update filename and image Signed-off-by: Allen Li * add namespace field in sa, and update watch namespace Signed-off-by: Allen Li * typo in ibm-entitlement-key Signed-off-by: Allen Li * update watchNamespace Signed-off-by: Allen Li * add namespace to rolebinding Signed-off-by: Allen Li --------- Signed-off-by: Allen Li --- helm-cluster-scoped/Chart.yaml | 6 + .../templates/cluster-rbac.yaml | 2 + .../templates/cluster-webhook.yaml | 1 + helm-cluster-scoped/templates/crd.yaml | 3973 +++++++++++++++++ helm-cluster-scoped/values.yaml | 12 + helm/Chart.yaml | 6 + helm/templates/operator-deployment.yaml | 258 ++ helm/templates/rbac.yaml | 221 + helm/values.yaml | 12 + 9 files changed, 4491 insertions(+) create mode 100644 helm-cluster-scoped/Chart.yaml create mode 100644 helm-cluster-scoped/templates/cluster-rbac.yaml create mode 100644 helm-cluster-scoped/templates/cluster-webhook.yaml create mode 100644 helm-cluster-scoped/templates/crd.yaml create mode 100644 helm-cluster-scoped/values.yaml create mode 100644 helm/Chart.yaml create mode 100644 helm/templates/operator-deployment.yaml create mode 100644 helm/templates/rbac.yaml create mode 100644 helm/values.yaml diff --git a/helm-cluster-scoped/Chart.yaml b/helm-cluster-scoped/Chart.yaml new file mode 100644 index 00000000..ceaf57ef --- /dev/null +++ b/helm-cluster-scoped/Chart.yaml @@ -0,0 +1,6 @@ +apiVersion: v2 +name: ibm-odlm +description: A Helm chart for ibm-odlm +type: application +version: 4.3.9 +appVersion: 4.3.9 \ No newline at end of file diff --git a/helm-cluster-scoped/templates/cluster-rbac.yaml b/helm-cluster-scoped/templates/cluster-rbac.yaml new file mode 100644 index 00000000..a0d98524 --- /dev/null +++ b/helm-cluster-scoped/templates/cluster-rbac.yaml @@ -0,0 +1,2 @@ +### no cluster rbac for ODLM +# if it is v3 -> v4 upgrade we need to add permission to cleanup certmanager, auditlogging and licensing CR \ No newline at end of file diff --git a/helm-cluster-scoped/templates/cluster-webhook.yaml b/helm-cluster-scoped/templates/cluster-webhook.yaml new file mode 100644 index 00000000..6bb71452 --- /dev/null +++ b/helm-cluster-scoped/templates/cluster-webhook.yaml @@ -0,0 +1 @@ +### no webhook for ODLM \ No newline at end of file diff --git a/helm-cluster-scoped/templates/crd.yaml b/helm-cluster-scoped/templates/crd.yaml new file mode 100644 index 00000000..9e137995 --- /dev/null +++ b/helm-cluster-scoped/templates/crd.yaml @@ -0,0 +1,3973 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + creationTimestamp: null + # labels: + # app.kubernetes.io/instance: operand-deployment-lifecycle-manager + # app.kubernetes.io/managed-by: operand-deployment-lifecycle-manager + # app.kubernetes.io/name: operand-deployment-lifecycle-manager + name: operandbindinfos.operator.ibm.com +spec: + group: operator.ibm.com + names: + kind: OperandBindInfo + listKind: OperandBindInfoList + plural: operandbindinfos + shortNames: + - opbi + singular: operandbindinfo + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + - description: Current Phase + jsonPath: .status.phase + name: Phase + type: string + - jsonPath: .metadata.creationTimestamp + name: Created At + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: OperandBindInfo is the Schema for the operandbindinfoes API. + Documentation For additional details regarding install parameters check + https://ibm.biz/icpfs39install. License By installing this product you accept + the license terms https://ibm.biz/icpfs39license + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: OperandBindInfoSpec defines the desired state of OperandBindInfo. + properties: + bindings: + additionalProperties: + description: |- + Bindable is a Kubernetes resources to be shared from one namespace to another. + List of supported resources are Secrets, Configmaps, Services, and Routes. + Secrets and Configmaps will be copied such that a new Secret/Configmap with + exactly the same data will be created in the target namespace. + Services and Routes data will be copied into a configmap in the target + namespace. + properties: + configmap: + description: The configmap identifies an existing configmap + object. if it exists, the ODLM will share to the namespace + of the OperandRequest. + type: string + route: + description: |- + Route data will be shared by copying it into a configmap which is then + created in the target namespace + properties: + data: + additionalProperties: + type: string + description: |- + Data is a key-value pair where the value is a YAML path to a value in the + OpenShift Route, e.g. .spec.host or .spec.tls.termination + type: object + name: + description: Name is the name of the OpenShift Route resource + type: string + type: object + secret: + description: The secret identifies an existing secret. if it + exists, the ODLM will share to the namespace of the OperandRequest. + type: string + service: + description: |- + Service data will be shared by copying it into a configmap which is then + created in the target namespace + properties: + data: + additionalProperties: + type: string + description: |- + Data is a key-value pair where the value is a YAML path to a value in the + Kubernetes Service, e.g. .spec.ports[0]port + type: object + name: + description: Name is the name of the Kubernetes Service + resource + type: string + type: object + type: object + description: The bindings section is used to specify information about + the access/configuration data that is to be shared. + type: object + description: + type: string + operand: + description: |- + The deployed service identifies itself with its operand. + This must match the name in the OperandRegistry in the current namespace. + type: string + registry: + description: The registry identifies the name of the name of the OperandRegistry + CR from which this operand deployment is being requested. + type: string + registryNamespace: + description: |- + Specifies the namespace in which the OperandRegistry reside. + The default is the current namespace in which the request is defined. + type: string + required: + - operand + - registry + type: object + x-kubernetes-preserve-unknown-fields: true + status: + description: OperandBindInfoStatus defines the observed state of OperandBindInfo. + properties: + phase: + description: Phase describes the overall phase of OperandBindInfo. + type: string + requestNamespaces: + description: RequestNamespaces defines the namespaces of OperandRequest. + items: + type: string + type: array + type: object + x-kubernetes-preserve-unknown-fields: true + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: null + storedVersions: null + +--- + +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + creationTimestamp: null + # labels: + # app.kubernetes.io/instance: operand-deployment-lifecycle-manager + # app.kubernetes.io/managed-by: operand-deployment-lifecycle-manager + # app.kubernetes.io/name: operand-deployment-lifecycle-manager + name: operandconfigs.operator.ibm.com +spec: + group: operator.ibm.com + names: + kind: OperandConfig + listKind: OperandConfigList + plural: operandconfigs + shortNames: + - opcon + singular: operandconfig + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + - description: Current Phase + jsonPath: .status.phase + name: Phase + type: string + - jsonPath: .metadata.creationTimestamp + name: Created At + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: OperandConfig is the Schema for the operandconfigs API. Documentation + For additional details regarding install parameters check https://ibm.biz/icpfs39install. + License By installing this product you accept the license terms https://ibm.biz/icpfs39license + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: OperandConfigSpec defines the desired state of OperandConfig. + properties: + services: + description: Services is a list of configuration of service. + items: + description: ConfigService defines the configuration of the service. + properties: + name: + description: Name is the subscription name. + type: string + resources: + description: Resources is used to specify the kubernetes resources + that are needed for the service. + items: + description: ConfigResource defines the resource needed for + the service + properties: + annotations: + additionalProperties: + type: string + description: Annotations are the annotations used in the + resource. + type: object + apiVersion: + description: APIVersion defines the versioned schema of + this representation of an object. + type: string + data: + description: Data is the configuration map of kubernetes + resource. + nullable: true + type: object + x-kubernetes-preserve-unknown-fields: true + force: + default: true + description: Force is used to determine whether the existing + kubernetes resource should be overwritten. + type: boolean + kind: + description: Kind identifies the kind of the kubernetes + resource. + type: string + labels: + additionalProperties: + type: string + description: Labels are the labels used in the resource. + type: object + name: + description: Name is the resource name. + type: string + namespace: + description: Namespace is the namespace of the resource. + type: string + optionalFields: + description: OptionalFields is the list of fields that + could be updated additionally. + items: + description: OptionalField defines the optional field + for the resource. + properties: + matchExpressions: + description: MatchExpressions is the match expression + of the field. + items: + description: MatchExpression defines the match + expression of the field. + properties: + key: + description: Key is the key of the field. + type: string + objectRef: + description: ObjectRef is the reference of + the object. + properties: + apiVersion: + description: APIVersion is the version + of the object. + type: string + kind: + description: Kind is the kind of the object. + type: string + name: + description: Name is the name of the object. + type: string + namespace: + description: Namespace is the namespace + of the object. + type: string + required: + - apiVersion + - kind + - name + type: object + operator: + description: Operator is the operator of the + field. + type: string + values: + description: Values is the values of the field. + items: + type: string + type: array + required: + - key + - operator + type: object + x-kubernetes-preserve-unknown-fields: true + type: array + operation: + description: Operation is the operation of the field. + type: string + path: + description: Path is the json path of the field. + type: string + valueFrom: + description: ValueFrom is the field value from the + object + properties: + objectRef: + description: ObjectRef is the reference of the + object. + properties: + apiVersion: + description: APIVersion is the version of + the object. + type: string + kind: + description: Kind is the kind of the object. + type: string + name: + description: Name is the name of the object. + type: string + namespace: + description: Namespace is the namespace + of the object. + type: string + required: + - apiVersion + - kind + - name + type: object + path: + description: Path is the json path of the field. + type: string + required: + - path + type: object + required: + - operation + - path + type: object + x-kubernetes-preserve-unknown-fields: true + type: array + ownerReferences: + description: OwnerReferences is the list of owner references. + items: + properties: + apiVersion: + description: API version of the referent. + type: string + blockOwnerDeletion: + description: |- + If true, AND if the owner has the "foregroundDeletion" finalizer, then + the owner cannot be deleted from the key-value store until this + reference is removed. + Defaults to false. + type: boolean + controller: + description: |- + If true, this reference points to the managing controller. + Default is false. + type: boolean + kind: + description: Kind of the referent. + type: string + name: + description: Name of the referent. + type: string + required: + - apiVersion + - kind + - name + type: object + type: array + required: + - apiVersion + - kind + - name + type: object + x-kubernetes-preserve-unknown-fields: true + type: array + spec: + additionalProperties: + type: object + x-kubernetes-preserve-unknown-fields: true + description: Spec is the configuration map of custom resource. + type: object + state: + description: State is a flag to enable or disable service. + type: string + required: + - name + type: object + type: array + type: object + x-kubernetes-preserve-unknown-fields: true + status: + description: OperandConfigStatus defines the observed state of OperandConfig. + properties: + phase: + description: Phase describes the overall phase of operands in the + OperandConfig. + type: string + serviceStatus: + additionalProperties: + description: CrStatus defines the status of the custom resource. + properties: + customResourceStatus: + additionalProperties: + description: ServicePhase defines the service status. + type: string + type: object + type: object + description: ServiceStatus defines all the status of a operator. + type: object + type: object + x-kubernetes-preserve-unknown-fields: true + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: null + storedVersions: null + +--- + +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + creationTimestamp: null + # labels: + # app.kubernetes.io/instance: operand-deployment-lifecycle-manager + # app.kubernetes.io/managed-by: operand-deployment-lifecycle-manager + # app.kubernetes.io/name: operand-deployment-lifecycle-manager + name: operandregistries.operator.ibm.com +spec: + group: operator.ibm.com + names: + kind: OperandRegistry + listKind: OperandRegistryList + plural: operandregistries + shortNames: + - opreg + singular: operandregistry + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + - description: Current Phase + jsonPath: .status.phase + name: Phase + type: string + - jsonPath: .metadata.creationTimestamp + name: Created At + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: OperandRegistry is the Schema for the operandregistries API. + Documentation For additional details regarding install parameters check + https://ibm.biz/icpfs39install. License By installing this product you accept + the license terms https://ibm.biz/icpfs39license + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: OperandRegistrySpec defines the desired state of OperandRegistry. + properties: + operators: + description: Operators is a list of operator OLM definition. + items: + description: Operator defines the desired state of Operators. + properties: + channel: + description: Name of the channel to track. + type: string + description: + description: Description of a common service. + type: string + fallbackChannels: + description: List of channels to fallback when the main channel + is not available. + items: + type: string + type: array + installMode: + description: |- + The install mode of an operator, either namespace or cluster. + Valid values are: + - "namespace" (default): operator is deployed in namespace of OperandRegistry; + - "cluster": operator is deployed in "openshift-operators" namespace; + - "no-op": operator is not supported to be fresh deployed; + type: string + installPlanApproval: + description: |- + Approval mode for emitted InstallPlans. + Valid values are: + - "Automatic" (default): operator will be installed automatically; + - "Manual": operator installation will be pending until users approve it; + type: string + name: + description: A unique name for the operator whose operand may + be deployed. + type: string + namespace: + description: |- + The namespace in which operator should be deployed when InstallMode is empty or set to "namespace". + If the namespace is not set, the operator namespace is the same as OperandRegistry Namespace + type: string + operatorConfig: + description: OperatorConfig is the name of the OperatorConfig + type: string + packageName: + description: Name of the package that defines the applications. + type: string + scope: + description: |- + A scope indicator, either public or private. + Valid values are: + - "private" (default): deployment only request from the containing names; + - "public": deployment can be requested from other namespaces; + enum: + - public + - private + type: string + sourceName: + description: Name of a CatalogSource that defines where and + how to find the channel. + type: string + sourceNamespace: + description: The Kubernetes namespace where the CatalogSource + used is located. + type: string + startingCSV: + description: StartingCSV of the installation. + type: string + subscriptionConfig: + description: SubscriptionConfig is used to override operator + configuration. + properties: + env: + description: |- + Env is a list of environment variables to set in the container. + Cannot be updated. + items: + description: EnvVar represents an environment variable + present in a Container. + properties: + name: + description: Name of the environment variable. Must + be a C_IDENTIFIER. + type: string + value: + description: |- + Variable references $(VAR_NAME) are expanded + using the previously defined environment variables in the container and + any service environment variables. If a variable cannot be resolved, + the reference in the input string will be unchanged. Double $$ are reduced + to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. + "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". + Escaped references will never be expanded, regardless of whether the variable + exists or not. + Defaults to "". + type: string + valueFrom: + description: Source for the environment variable's + value. Cannot be used if value is not empty. + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + properties: + key: + description: The key to select. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the ConfigMap + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + description: |- + Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['']`, `metadata.annotations['']`, + spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs. + properties: + apiVersion: + description: Version of the schema the FieldPath + is written in terms of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to select in + the specified API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + description: |- + Selects a resource of the container: only resources limits and requests + (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported. + properties: + containerName: + description: 'Container name: required for + volumes, optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format of + the exposed resources, defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + description: Selects a key of a secret in the + pod's namespace + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or + its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + envFrom: + description: |- + EnvFrom is a list of sources to populate environment variables in the container. + The keys defined within a source must be a C_IDENTIFIER. All invalid keys + will be reported as an event when the container is starting. When a key exists in multiple + sources, the value associated with the last source will take precedence. + Values defined by an Env with a duplicate key will take precedence. + Immutable. + items: + description: EnvFromSource represents the source of a + set of ConfigMaps + properties: + configMapRef: + description: The ConfigMap to select from + properties: + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the ConfigMap must + be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + description: An optional identifier to prepend to + each key in the ConfigMap. Must be a C_IDENTIFIER. + type: string + secretRef: + description: The Secret to select from + properties: + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret must be + defined + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + nodeSelector: + additionalProperties: + type: string + description: |- + NodeSelector is a selector which must be true for the pod to fit on a node. + Selector which must match a node's labels for the pod to be scheduled on that node. + More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ + type: object + resources: + description: |- + Resources represents compute resources required by this container. + Immutable. + More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/ + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + selector: + description: |- + Selector is the label selector for pods to be configured. + Existing ReplicaSets whose pods are + selected by this will be the ones affected by this deployment. + It must match the pod template's labels. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + tolerations: + description: Tolerations are the pod's tolerations. + items: + description: |- + The pod this Toleration is attached to tolerates any taint that matches + the triple using the matching operator . + properties: + effect: + description: |- + Effect indicates the taint effect to match. Empty means match all taint effects. + When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. + type: string + key: + description: |- + Key is the taint key that the toleration applies to. Empty means match all taint keys. + If the key is empty, operator must be Exists; this combination means to match all values and all keys. + type: string + operator: + description: |- + Operator represents a key's relationship to the value. + Valid operators are Exists and Equal. Defaults to Equal. + Exists is equivalent to wildcard for value, so that a pod can + tolerate all taints of a particular category. + type: string + tolerationSeconds: + description: |- + TolerationSeconds represents the period of time the toleration (which must be + of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, + it is not set, which means tolerate the taint forever (do not evict). Zero and + negative values will be treated as 0 (evict immediately) by the system. + format: int64 + type: integer + value: + description: |- + Value is the taint value the toleration matches to. + If the operator is Exists, the value should be empty, otherwise just a regular string. + type: string + type: object + type: array + volumeMounts: + description: List of VolumeMounts to set in the container. + items: + description: VolumeMount describes a mounting of a Volume + within a container. + properties: + mountPath: + description: |- + Path within the container at which the volume should be mounted. Must + not contain ':'. + type: string + mountPropagation: + description: |- + mountPropagation determines how mounts are propagated from the host + to container and the other way around. + When not set, MountPropagationNone is used. + This field is beta in 1.10. + type: string + name: + description: This must match the Name of a Volume. + type: string + readOnly: + description: |- + Mounted read-only if true, read-write otherwise (false or unspecified). + Defaults to false. + type: boolean + subPath: + description: |- + Path within the volume from which the container's volume should be mounted. + Defaults to "" (volume's root). + type: string + subPathExpr: + description: |- + Expanded path within the volume from which the container's volume should be mounted. + Behaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment. + Defaults to "" (volume's root). + SubPathExpr and SubPath are mutually exclusive. + type: string + required: + - mountPath + - name + type: object + type: array + volumes: + description: List of Volumes to set in the podSpec. + items: + description: Volume represents a named volume in a pod + that may be accessed by any container in the pod. + properties: + awsElasticBlockStore: + description: |- + awsElasticBlockStore represents an AWS Disk resource that is attached to a + kubelet's host machine and then exposed to the pod. + More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore + properties: + fsType: + description: |- + fsType is the filesystem type of the volume that you want to mount. + Tip: Ensure that the filesystem type is supported by the host operating system. + Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore + TODO: how do we prevent errors in the filesystem from compromising the machine + type: string + partition: + description: |- + partition is the partition in the volume that you want to mount. + If omitted, the default is to mount by volume name. + Examples: For volume /dev/sda1, you specify the partition as "1". + Similarly, the volume partition for /dev/sda is "0" (or you can leave the property empty). + format: int32 + type: integer + readOnly: + description: |- + readOnly value true will force the readOnly setting in VolumeMounts. + More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore + type: boolean + volumeID: + description: |- + volumeID is unique ID of the persistent disk resource in AWS (Amazon EBS volume). + More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore + type: string + required: + - volumeID + type: object + azureDisk: + description: azureDisk represents an Azure Data Disk + mount on the host and bind mount to the pod. + properties: + cachingMode: + description: 'cachingMode is the Host Caching + mode: None, Read Only, Read Write.' + type: string + diskName: + description: diskName is the Name of the data + disk in the blob storage + type: string + diskURI: + description: diskURI is the URI of data disk in + the blob storage + type: string + fsType: + description: |- + fsType is Filesystem type to mount. + Must be a filesystem type supported by the host operating system. + Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + type: string + kind: + description: 'kind expected values are Shared: + multiple blob disks per storage account Dedicated: + single blob disk per storage account Managed: + azure managed data disk (only in managed availability + set). defaults to shared' + type: string + readOnly: + description: |- + readOnly Defaults to false (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. + type: boolean + required: + - diskName + - diskURI + type: object + azureFile: + description: azureFile represents an Azure File Service + mount on the host and bind mount to the pod. + properties: + readOnly: + description: |- + readOnly defaults to false (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. + type: boolean + secretName: + description: secretName is the name of secret + that contains Azure Storage Account Name and + Key + type: string + shareName: + description: shareName is the azure share Name + type: string + required: + - secretName + - shareName + type: object + cephfs: + description: cephFS represents a Ceph FS mount on + the host that shares a pod's lifetime + properties: + monitors: + description: |- + monitors is Required: Monitors is a collection of Ceph monitors + More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it + items: + type: string + type: array + path: + description: 'path is Optional: Used as the mounted + root, rather than the full Ceph tree, default + is /' + type: string + readOnly: + description: |- + readOnly is Optional: Defaults to false (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. + More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it + type: boolean + secretFile: + description: |- + secretFile is Optional: SecretFile is the path to key ring for User, default is /etc/ceph/user.secret + More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it + type: string + secretRef: + description: |- + secretRef is Optional: SecretRef is reference to the authentication secret for User, default is empty. + More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it + properties: + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + type: object + x-kubernetes-map-type: atomic + user: + description: |- + user is optional: User is the rados user name, default is admin + More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it + type: string + required: + - monitors + type: object + cinder: + description: |- + cinder represents a cinder volume attached and mounted on kubelets host machine. + More info: https://examples.k8s.io/mysql-cinder-pd/README.md + properties: + fsType: + description: |- + fsType is the filesystem type to mount. + Must be a filesystem type supported by the host operating system. + Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + More info: https://examples.k8s.io/mysql-cinder-pd/README.md + type: string + readOnly: + description: |- + readOnly defaults to false (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. + More info: https://examples.k8s.io/mysql-cinder-pd/README.md + type: boolean + secretRef: + description: |- + secretRef is optional: points to a secret object containing parameters used to connect + to OpenStack. + properties: + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + type: object + x-kubernetes-map-type: atomic + volumeID: + description: |- + volumeID used to identify the volume in cinder. + More info: https://examples.k8s.io/mysql-cinder-pd/README.md + type: string + required: + - volumeID + type: object + configMap: + description: configMap represents a configMap that + should populate this volume + properties: + defaultMode: + description: |- + defaultMode is optional: mode bits used to set permissions on created files by default. + Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. + Defaults to 0644. + Directories within the path are not affected by this setting. + This might be in conflict with other options that affect the file + mode, like fsGroup, and the result can be other mode bits set. + format: int32 + type: integer + items: + description: |- + items if unspecified, each key-value pair in the Data field of the referenced + ConfigMap will be projected into the volume as a file whose name is the + key and content is the value. If specified, the listed keys will be + projected into the specified paths, and unlisted keys will not be + present. If a key is specified which is not present in the ConfigMap, + the volume setup will error unless it is marked optional. Paths must be + relative and may not contain the '..' path or start with '..'. + items: + description: Maps a string key to a path within + a volume. + properties: + key: + description: key is the key to project. + type: string + mode: + description: |- + mode is Optional: mode bits used to set permissions on this file. + Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. + If not specified, the volume defaultMode will be used. + This might be in conflict with other options that affect the file + mode, like fsGroup, and the result can be other mode bits set. + format: int32 + type: integer + path: + description: |- + path is the relative path of the file to map the key to. + May not be an absolute path. + May not contain the path element '..'. + May not start with the string '..'. + type: string + required: + - key + - path + type: object + type: array + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: optional specify whether the ConfigMap + or its keys must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + csi: + description: csi (Container Storage Interface) represents + ephemeral storage that is handled by certain external + CSI drivers (Beta feature). + properties: + driver: + description: |- + driver is the name of the CSI driver that handles this volume. + Consult with your admin for the correct name as registered in the cluster. + type: string + fsType: + description: |- + fsType to mount. Ex. "ext4", "xfs", "ntfs". + If not provided, the empty value is passed to the associated CSI driver + which will determine the default filesystem to apply. + type: string + nodePublishSecretRef: + description: |- + nodePublishSecretRef is a reference to the secret object containing + sensitive information to pass to the CSI driver to complete the CSI + NodePublishVolume and NodeUnpublishVolume calls. + This field is optional, and may be empty if no secret is required. If the + secret object contains more than one secret, all secret references are passed. + properties: + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + type: object + x-kubernetes-map-type: atomic + readOnly: + description: |- + readOnly specifies a read-only configuration for the volume. + Defaults to false (read/write). + type: boolean + volumeAttributes: + additionalProperties: + type: string + description: |- + volumeAttributes stores driver-specific properties that are passed to the CSI + driver. Consult your driver's documentation for supported values. + type: object + required: + - driver + type: object + downwardAPI: + description: downwardAPI represents downward API about + the pod that should populate this volume + properties: + defaultMode: + description: |- + Optional: mode bits to use on created files by default. Must be a + Optional: mode bits used to set permissions on created files by default. + Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. + Defaults to 0644. + Directories within the path are not affected by this setting. + This might be in conflict with other options that affect the file + mode, like fsGroup, and the result can be other mode bits set. + format: int32 + type: integer + items: + description: Items is a list of downward API volume + file + items: + description: DownwardAPIVolumeFile represents + information to create the file containing + the pod field + properties: + fieldRef: + description: 'Required: Selects a field + of the pod: only annotations, labels, + name and namespace are supported.' + properties: + apiVersion: + description: Version of the schema the + FieldPath is written in terms of, + defaults to "v1". + type: string + fieldPath: + description: Path of the field to select + in the specified API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + description: |- + Optional: mode bits used to set permissions on this file, must be an octal value + between 0000 and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. + If not specified, the volume defaultMode will be used. + This might be in conflict with other options that affect the file + mode, like fsGroup, and the result can be other mode bits set. + format: int32 + type: integer + path: + description: 'Required: Path is the relative + path name of the file to be created. Must + not be absolute or contain the ''..'' + path. Must be utf-8 encoded. The first + item of the relative path must not start + with ''..''' + type: string + resourceFieldRef: + description: |- + Selects a resource of the container: only resources limits and requests + (limits.cpu, limits.memory, requests.cpu and requests.memory) are currently supported. + properties: + containerName: + description: 'Container name: required + for volumes, optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format + of the exposed resources, defaults + to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to + select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + type: object + emptyDir: + description: |- + emptyDir represents a temporary directory that shares a pod's lifetime. + More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir + properties: + medium: + description: |- + medium represents what type of storage medium should back this directory. + The default is "" which means to use the node's default medium. + Must be an empty string (default) or Memory. + More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + description: |- + sizeLimit is the total amount of local storage required for this EmptyDir volume. + The size limit is also applicable for memory medium. + The maximum usage on memory medium EmptyDir would be the minimum value between + the SizeLimit specified here and the sum of memory limits of all containers in a pod. + The default is nil which means that the limit is undefined. + More info: http://kubernetes.io/docs/user-guide/volumes#emptydir + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + ephemeral: + description: |- + ephemeral represents a volume that is handled by a cluster storage driver. + The volume's lifecycle is tied to the pod that defines it - it will be created before the pod starts, + and deleted when the pod is removed. + + + Use this if: + a) the volume is only needed while the pod runs, + b) features of normal volumes like restoring from snapshot or capacity + tracking are needed, + c) the storage driver is specified through a storage class, and + d) the storage driver supports dynamic volume provisioning through + a PersistentVolumeClaim (see EphemeralVolumeSource for more + information on the connection between this volume type + and PersistentVolumeClaim). + + + Use PersistentVolumeClaim or one of the vendor-specific + APIs for volumes that persist for longer than the lifecycle + of an individual pod. + + + Use CSI for light-weight local ephemeral volumes if the CSI driver is meant to + be used that way - see the documentation of the driver for + more information. + + + A pod can use both types of ephemeral volumes and + persistent volumes at the same time. + properties: + volumeClaimTemplate: + description: |- + Will be used to create a stand-alone PVC to provision the volume. + The pod in which this EphemeralVolumeSource is embedded will be the + owner of the PVC, i.e. the PVC will be deleted together with the + pod. The name of the PVC will be `-` where + `` is the name from the `PodSpec.Volumes` array + entry. Pod validation will reject the pod if the concatenated name + is not valid for a PVC (for example, too long). + + + An existing PVC with that name that is not owned by the pod + will *not* be used for the pod to avoid using an unrelated + volume by mistake. Starting the pod is then blocked until + the unrelated PVC is removed. If such a pre-created PVC is + meant to be used by the pod, the PVC has to updated with an + owner reference to the pod once the pod exists. Normally + this should not be necessary, but it may be useful when + manually reconstructing a broken cluster. + + + This field is read-only and no changes will be made by Kubernetes + to the PVC after it has been created. + + + Required, must not be nil. + properties: + metadata: + description: |- + May contain labels and annotations that will be copied into the PVC + when creating it. No other fields are allowed and will be rejected during + validation. + type: object + spec: + description: |- + The specification for the PersistentVolumeClaim. The entire content is + copied unchanged into the PVC that gets created from this + template. The same fields as in a PersistentVolumeClaim + are also valid here. + properties: + accessModes: + description: |- + accessModes contains the desired access modes the volume should have. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1 + items: + type: string + type: array + dataSource: + description: |- + dataSource field can be used to specify either: + * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) + * An existing PVC (PersistentVolumeClaim) + If the provisioner or an external controller can support the specified data source, + it will create a new volume based on the contents of the specified data source. + If the AnyVolumeDataSource feature gate is enabled, this field will always have + the same contents as the DataSourceRef field. + properties: + apiGroup: + description: |- + APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in the core API group. + For any other third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource + being referenced + type: string + name: + description: Name is the name of resource + being referenced + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + description: |- + dataSourceRef specifies the object from which to populate the volume with data, if a non-empty + volume is desired. This may be any local object from a non-empty API group (non + core object) or a PersistentVolumeClaim object. + When this field is specified, volume binding will only succeed if the type of + the specified object matches some installed volume populator or dynamic + provisioner. + This field will replace the functionality of the DataSource field and as such + if both fields are non-empty, they must have the same value. For backwards + compatibility, both fields (DataSource and DataSourceRef) will be set to the same + value automatically if one of them is empty and the other is non-empty. + There are two important differences between DataSource and DataSourceRef: + * While DataSource only allows two specific types of objects, DataSourceRef + allows any non-core object, as well as PersistentVolumeClaim objects. + * While DataSource ignores disallowed values (dropping them), DataSourceRef + preserves all values, and generates an error if a disallowed value is + specified. + (Beta) Using this field requires the AnyVolumeDataSource feature gate to be enabled. + properties: + apiGroup: + description: |- + APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in the core API group. + For any other third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource + being referenced + type: string + name: + description: Name is the name of resource + being referenced + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + resources: + description: |- + resources represents the minimum resources the volume should have. + If RecoverVolumeExpansionFailure feature is enabled users are allowed to specify resource requirements + that are lower than previous value but must still be higher than capacity recorded in the + status field of the claim. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + selector: + description: selector is a label query + over volumes to consider for binding. + properties: + matchExpressions: + description: matchExpressions is a + list of label selector requirements. + The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + description: |- + storageClassName is the name of the StorageClass required by the claim. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1 + type: string + volumeMode: + description: |- + volumeMode defines what type of volume is required by the claim. + Value of Filesystem is implied when not included in claim spec. + type: string + volumeName: + description: volumeName is the binding + reference to the PersistentVolume backing + this claim. + type: string + type: object + required: + - spec + type: object + type: object + fc: + description: fc represents a Fibre Channel resource + that is attached to a kubelet's host machine and + then exposed to the pod. + properties: + fsType: + description: |- + fsType is the filesystem type to mount. + Must be a filesystem type supported by the host operating system. + Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + TODO: how do we prevent errors in the filesystem from compromising the machine + type: string + lun: + description: 'lun is Optional: FC target lun number' + format: int32 + type: integer + readOnly: + description: |- + readOnly is Optional: Defaults to false (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. + type: boolean + targetWWNs: + description: 'targetWWNs is Optional: FC target + worldwide names (WWNs)' + items: + type: string + type: array + wwids: + description: |- + wwids Optional: FC volume world wide identifiers (wwids) + Either wwids or combination of targetWWNs and lun must be set, but not both simultaneously. + items: + type: string + type: array + type: object + flexVolume: + description: |- + flexVolume represents a generic volume resource that is + provisioned/attached using an exec based plugin. + properties: + driver: + description: driver is the name of the driver + to use for this volume. + type: string + fsType: + description: |- + fsType is the filesystem type to mount. + Must be a filesystem type supported by the host operating system. + Ex. "ext4", "xfs", "ntfs". The default filesystem depends on FlexVolume script. + type: string + options: + additionalProperties: + type: string + description: 'options is Optional: this field + holds extra command options if any.' + type: object + readOnly: + description: |- + readOnly is Optional: defaults to false (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. + type: boolean + secretRef: + description: |- + secretRef is Optional: secretRef is reference to the secret object containing + sensitive information to pass to the plugin scripts. This may be + empty if no secret object is specified. If the secret object + contains more than one secret, all secrets are passed to the plugin + scripts. + properties: + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + type: object + x-kubernetes-map-type: atomic + required: + - driver + type: object + flocker: + description: flocker represents a Flocker volume attached + to a kubelet's host machine. This depends on the + Flocker control service being running + properties: + datasetName: + description: |- + datasetName is Name of the dataset stored as metadata -> name on the dataset for Flocker + should be considered as deprecated + type: string + datasetUUID: + description: datasetUUID is the UUID of the dataset. + This is unique identifier of a Flocker dataset + type: string + type: object + gcePersistentDisk: + description: |- + gcePersistentDisk represents a GCE Disk resource that is attached to a + kubelet's host machine and then exposed to the pod. + More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk + properties: + fsType: + description: |- + fsType is filesystem type of the volume that you want to mount. + Tip: Ensure that the filesystem type is supported by the host operating system. + Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk + TODO: how do we prevent errors in the filesystem from compromising the machine + type: string + partition: + description: |- + partition is the partition in the volume that you want to mount. + If omitted, the default is to mount by volume name. + Examples: For volume /dev/sda1, you specify the partition as "1". + Similarly, the volume partition for /dev/sda is "0" (or you can leave the property empty). + More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk + format: int32 + type: integer + pdName: + description: |- + pdName is unique name of the PD resource in GCE. Used to identify the disk in GCE. + More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk + type: string + readOnly: + description: |- + readOnly here will force the ReadOnly setting in VolumeMounts. + Defaults to false. + More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk + type: boolean + required: + - pdName + type: object + gitRepo: + description: |- + gitRepo represents a git repository at a particular revision. + DEPRECATED: GitRepo is deprecated. To provision a container with a git repo, mount an + EmptyDir into an InitContainer that clones the repo using git, then mount the EmptyDir + into the Pod's container. + properties: + directory: + description: |- + directory is the target directory name. + Must not contain or start with '..'. If '.' is supplied, the volume directory will be the + git repository. Otherwise, if specified, the volume will contain the git repository in + the subdirectory with the given name. + type: string + repository: + description: repository is the URL + type: string + revision: + description: revision is the commit hash for the + specified revision. + type: string + required: + - repository + type: object + glusterfs: + description: |- + glusterfs represents a Glusterfs mount on the host that shares a pod's lifetime. + More info: https://examples.k8s.io/volumes/glusterfs/README.md + properties: + endpoints: + description: |- + endpoints is the endpoint name that details Glusterfs topology. + More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod + type: string + path: + description: |- + path is the Glusterfs volume path. + More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod + type: string + readOnly: + description: |- + readOnly here will force the Glusterfs volume to be mounted with read-only permissions. + Defaults to false. + More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod + type: boolean + required: + - endpoints + - path + type: object + hostPath: + description: |- + hostPath represents a pre-existing file or directory on the host + machine that is directly exposed to the container. This is generally + used for system agents or other privileged things that are allowed + to see the host machine. Most containers will NOT need this. + More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath + --- + TODO(jonesdl) We need to restrict who can use host directory mounts and who can/can not + mount host directories as read/write. + properties: + path: + description: |- + path of the directory on the host. + If the path is a symlink, it will follow the link to the real path. + More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath + type: string + type: + description: |- + type for HostPath Volume + Defaults to "" + More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath + type: string + required: + - path + type: object + iscsi: + description: |- + iscsi represents an ISCSI Disk resource that is attached to a + kubelet's host machine and then exposed to the pod. + More info: https://examples.k8s.io/volumes/iscsi/README.md + properties: + chapAuthDiscovery: + description: chapAuthDiscovery defines whether + support iSCSI Discovery CHAP authentication + type: boolean + chapAuthSession: + description: chapAuthSession defines whether support + iSCSI Session CHAP authentication + type: boolean + fsType: + description: |- + fsType is the filesystem type of the volume that you want to mount. + Tip: Ensure that the filesystem type is supported by the host operating system. + Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + More info: https://kubernetes.io/docs/concepts/storage/volumes#iscsi + TODO: how do we prevent errors in the filesystem from compromising the machine + type: string + initiatorName: + description: |- + initiatorName is the custom iSCSI Initiator Name. + If initiatorName is specified with iscsiInterface simultaneously, new iSCSI interface + : will be created for the connection. + type: string + iqn: + description: iqn is the target iSCSI Qualified + Name. + type: string + iscsiInterface: + description: |- + iscsiInterface is the interface Name that uses an iSCSI transport. + Defaults to 'default' (tcp). + type: string + lun: + description: lun represents iSCSI Target Lun number. + format: int32 + type: integer + portals: + description: |- + portals is the iSCSI Target Portal List. The portal is either an IP or ip_addr:port if the port + is other than default (typically TCP ports 860 and 3260). + items: + type: string + type: array + readOnly: + description: |- + readOnly here will force the ReadOnly setting in VolumeMounts. + Defaults to false. + type: boolean + secretRef: + description: secretRef is the CHAP Secret for + iSCSI target and initiator authentication + properties: + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + type: object + x-kubernetes-map-type: atomic + targetPortal: + description: |- + targetPortal is iSCSI Target Portal. The Portal is either an IP or ip_addr:port if the port + is other than default (typically TCP ports 860 and 3260). + type: string + required: + - iqn + - lun + - targetPortal + type: object + name: + description: |- + name of the volume. + Must be a DNS_LABEL and unique within the pod. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + nfs: + description: |- + nfs represents an NFS mount on the host that shares a pod's lifetime + More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs + properties: + path: + description: |- + path that is exported by the NFS server. + More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs + type: string + readOnly: + description: |- + readOnly here will force the NFS export to be mounted with read-only permissions. + Defaults to false. + More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs + type: boolean + server: + description: |- + server is the hostname or IP address of the NFS server. + More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs + type: string + required: + - path + - server + type: object + persistentVolumeClaim: + description: |- + persistentVolumeClaimVolumeSource represents a reference to a + PersistentVolumeClaim in the same namespace. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims + properties: + claimName: + description: |- + claimName is the name of a PersistentVolumeClaim in the same namespace as the pod using this volume. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims + type: string + readOnly: + description: |- + readOnly Will force the ReadOnly setting in VolumeMounts. + Default false. + type: boolean + required: + - claimName + type: object + photonPersistentDisk: + description: photonPersistentDisk represents a PhotonController + persistent disk attached and mounted on kubelets + host machine + properties: + fsType: + description: |- + fsType is the filesystem type to mount. + Must be a filesystem type supported by the host operating system. + Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + type: string + pdID: + description: pdID is the ID that identifies Photon + Controller persistent disk + type: string + required: + - pdID + type: object + portworxVolume: + description: portworxVolume represents a portworx + volume attached and mounted on kubelets host machine + properties: + fsType: + description: |- + fSType represents the filesystem type to mount + Must be a filesystem type supported by the host operating system. + Ex. "ext4", "xfs". Implicitly inferred to be "ext4" if unspecified. + type: string + readOnly: + description: |- + readOnly defaults to false (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. + type: boolean + volumeID: + description: volumeID uniquely identifies a Portworx + volume + type: string + required: + - volumeID + type: object + projected: + description: projected items for all in one resources + secrets, configmaps, and downward API + properties: + defaultMode: + description: |- + defaultMode are the mode bits used to set permissions on created files by default. + Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. + Directories within the path are not affected by this setting. + This might be in conflict with other options that affect the file + mode, like fsGroup, and the result can be other mode bits set. + format: int32 + type: integer + sources: + description: sources is the list of volume projections + items: + description: Projection that may be projected + along with other supported volume types + properties: + configMap: + description: configMap information about + the configMap data to project + properties: + items: + description: |- + items if unspecified, each key-value pair in the Data field of the referenced + ConfigMap will be projected into the volume as a file whose name is the + key and content is the value. If specified, the listed keys will be + projected into the specified paths, and unlisted keys will not be + present. If a key is specified which is not present in the ConfigMap, + the volume setup will error unless it is marked optional. Paths must be + relative and may not contain the '..' path or start with '..'. + items: + description: Maps a string key to + a path within a volume. + properties: + key: + description: key is the key to + project. + type: string + mode: + description: |- + mode is Optional: mode bits used to set permissions on this file. + Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. + If not specified, the volume defaultMode will be used. + This might be in conflict with other options that affect the file + mode, like fsGroup, and the result can be other mode bits set. + format: int32 + type: integer + path: + description: |- + path is the relative path of the file to map the key to. + May not be an absolute path. + May not contain the path element '..'. + May not start with the string '..'. + type: string + required: + - key + - path + type: object + type: array + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: optional specify whether + the ConfigMap or its keys must be + defined + type: boolean + type: object + x-kubernetes-map-type: atomic + downwardAPI: + description: downwardAPI information about + the downwardAPI data to project + properties: + items: + description: Items is a list of DownwardAPIVolume + file + items: + description: DownwardAPIVolumeFile + represents information to create + the file containing the pod field + properties: + fieldRef: + description: 'Required: Selects + a field of the pod: only annotations, + labels, name and namespace are + supported.' + properties: + apiVersion: + description: Version of the + schema the FieldPath is + written in terms of, defaults + to "v1". + type: string + fieldPath: + description: Path of the field + to select in the specified + API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + description: |- + Optional: mode bits used to set permissions on this file, must be an octal value + between 0000 and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. + If not specified, the volume defaultMode will be used. + This might be in conflict with other options that affect the file + mode, like fsGroup, and the result can be other mode bits set. + format: int32 + type: integer + path: + description: 'Required: Path is the + relative path name of the file + to be created. Must not be absolute + or contain the ''..'' path. + Must be utf-8 encoded. The first + item of the relative path must + not start with ''..''' + type: string + resourceFieldRef: + description: |- + Selects a resource of the container: only resources limits and requests + (limits.cpu, limits.memory, requests.cpu and requests.memory) are currently supported. + properties: + containerName: + description: 'Container name: + required for volumes, optional + for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the + output format of the exposed + resources, defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource + to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + type: object + secret: + description: secret information about the + secret data to project + properties: + items: + description: |- + items if unspecified, each key-value pair in the Data field of the referenced + Secret will be projected into the volume as a file whose name is the + key and content is the value. If specified, the listed keys will be + projected into the specified paths, and unlisted keys will not be + present. If a key is specified which is not present in the Secret, + the volume setup will error unless it is marked optional. Paths must be + relative and may not contain the '..' path or start with '..'. + items: + description: Maps a string key to + a path within a volume. + properties: + key: + description: key is the key to + project. + type: string + mode: + description: |- + mode is Optional: mode bits used to set permissions on this file. + Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. + If not specified, the volume defaultMode will be used. + This might be in conflict with other options that affect the file + mode, like fsGroup, and the result can be other mode bits set. + format: int32 + type: integer + path: + description: |- + path is the relative path of the file to map the key to. + May not be an absolute path. + May not contain the path element '..'. + May not start with the string '..'. + type: string + required: + - key + - path + type: object + type: array + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: optional field specify + whether the Secret or its key must + be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + serviceAccountToken: + description: serviceAccountToken is information + about the serviceAccountToken data to + project + properties: + audience: + description: |- + audience is the intended audience of the token. A recipient of a token + must identify itself with an identifier specified in the audience of the + token, and otherwise should reject the token. The audience defaults to the + identifier of the apiserver. + type: string + expirationSeconds: + description: |- + expirationSeconds is the requested duration of validity of the service + account token. As the token approaches expiration, the kubelet volume + plugin will proactively rotate the service account token. The kubelet will + start trying to rotate the token if the token is older than 80 percent of + its time to live or if the token is older than 24 hours.Defaults to 1 hour + and must be at least 10 minutes. + format: int64 + type: integer + path: + description: |- + path is the path relative to the mount point of the file to project the + token into. + type: string + required: + - path + type: object + type: object + type: array + type: object + quobyte: + description: quobyte represents a Quobyte mount on + the host that shares a pod's lifetime + properties: + group: + description: |- + group to map volume access to + Default is no group + type: string + readOnly: + description: |- + readOnly here will force the Quobyte volume to be mounted with read-only permissions. + Defaults to false. + type: boolean + registry: + description: |- + registry represents a single or multiple Quobyte Registry services + specified as a string as host:port pair (multiple entries are separated with commas) + which acts as the central registry for volumes + type: string + tenant: + description: |- + tenant owning the given Quobyte volume in the Backend + Used with dynamically provisioned Quobyte volumes, value is set by the plugin + type: string + user: + description: |- + user to map volume access to + Defaults to serivceaccount user + type: string + volume: + description: volume is a string that references + an already created Quobyte volume by name. + type: string + required: + - registry + - volume + type: object + rbd: + description: |- + rbd represents a Rados Block Device mount on the host that shares a pod's lifetime. + More info: https://examples.k8s.io/volumes/rbd/README.md + properties: + fsType: + description: |- + fsType is the filesystem type of the volume that you want to mount. + Tip: Ensure that the filesystem type is supported by the host operating system. + Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + More info: https://kubernetes.io/docs/concepts/storage/volumes#rbd + TODO: how do we prevent errors in the filesystem from compromising the machine + type: string + image: + description: |- + image is the rados image name. + More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it + type: string + keyring: + description: |- + keyring is the path to key ring for RBDUser. + Default is /etc/ceph/keyring. + More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it + type: string + monitors: + description: |- + monitors is a collection of Ceph monitors. + More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it + items: + type: string + type: array + pool: + description: |- + pool is the rados pool name. + Default is rbd. + More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it + type: string + readOnly: + description: |- + readOnly here will force the ReadOnly setting in VolumeMounts. + Defaults to false. + More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it + type: boolean + secretRef: + description: |- + secretRef is name of the authentication secret for RBDUser. If provided + overrides keyring. + Default is nil. + More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it + properties: + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + type: object + x-kubernetes-map-type: atomic + user: + description: |- + user is the rados user name. + Default is admin. + More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it + type: string + required: + - image + - monitors + type: object + scaleIO: + description: scaleIO represents a ScaleIO persistent + volume attached and mounted on Kubernetes nodes. + properties: + fsType: + description: |- + fsType is the filesystem type to mount. + Must be a filesystem type supported by the host operating system. + Ex. "ext4", "xfs", "ntfs". + Default is "xfs". + type: string + gateway: + description: gateway is the host address of the + ScaleIO API Gateway. + type: string + protectionDomain: + description: protectionDomain is the name of the + ScaleIO Protection Domain for the configured + storage. + type: string + readOnly: + description: |- + readOnly Defaults to false (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. + type: boolean + secretRef: + description: |- + secretRef references to the secret for ScaleIO user and other + sensitive information. If this is not provided, Login operation will fail. + properties: + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + type: object + x-kubernetes-map-type: atomic + sslEnabled: + description: sslEnabled Flag enable/disable SSL + communication with Gateway, default false + type: boolean + storageMode: + description: |- + storageMode indicates whether the storage for a volume should be ThickProvisioned or ThinProvisioned. + Default is ThinProvisioned. + type: string + storagePool: + description: storagePool is the ScaleIO Storage + Pool associated with the protection domain. + type: string + system: + description: system is the name of the storage + system as configured in ScaleIO. + type: string + volumeName: + description: |- + volumeName is the name of a volume already created in the ScaleIO system + that is associated with this volume source. + type: string + required: + - gateway + - secretRef + - system + type: object + secret: + description: |- + secret represents a secret that should populate this volume. + More info: https://kubernetes.io/docs/concepts/storage/volumes#secret + properties: + defaultMode: + description: |- + defaultMode is Optional: mode bits used to set permissions on created files by default. + Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, JSON requires decimal values + for mode bits. Defaults to 0644. + Directories within the path are not affected by this setting. + This might be in conflict with other options that affect the file + mode, like fsGroup, and the result can be other mode bits set. + format: int32 + type: integer + items: + description: |- + items If unspecified, each key-value pair in the Data field of the referenced + Secret will be projected into the volume as a file whose name is the + key and content is the value. If specified, the listed keys will be + projected into the specified paths, and unlisted keys will not be + present. If a key is specified which is not present in the Secret, + the volume setup will error unless it is marked optional. Paths must be + relative and may not contain the '..' path or start with '..'. + items: + description: Maps a string key to a path within + a volume. + properties: + key: + description: key is the key to project. + type: string + mode: + description: |- + mode is Optional: mode bits used to set permissions on this file. + Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. + If not specified, the volume defaultMode will be used. + This might be in conflict with other options that affect the file + mode, like fsGroup, and the result can be other mode bits set. + format: int32 + type: integer + path: + description: |- + path is the relative path of the file to map the key to. + May not be an absolute path. + May not contain the path element '..'. + May not start with the string '..'. + type: string + required: + - key + - path + type: object + type: array + optional: + description: optional field specify whether the + Secret or its keys must be defined + type: boolean + secretName: + description: |- + secretName is the name of the secret in the pod's namespace to use. + More info: https://kubernetes.io/docs/concepts/storage/volumes#secret + type: string + type: object + storageos: + description: storageOS represents a StorageOS volume + attached and mounted on Kubernetes nodes. + properties: + fsType: + description: |- + fsType is the filesystem type to mount. + Must be a filesystem type supported by the host operating system. + Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + type: string + readOnly: + description: |- + readOnly defaults to false (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. + type: boolean + secretRef: + description: |- + secretRef specifies the secret to use for obtaining the StorageOS API + credentials. If not specified, default values will be attempted. + properties: + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + type: object + x-kubernetes-map-type: atomic + volumeName: + description: |- + volumeName is the human-readable name of the StorageOS volume. Volume + names are only unique within a namespace. + type: string + volumeNamespace: + description: |- + volumeNamespace specifies the scope of the volume within StorageOS. If no + namespace is specified then the Pod's namespace will be used. This allows the + Kubernetes name scoping to be mirrored within StorageOS for tighter integration. + Set VolumeName to any name to override the default behaviour. + Set to "default" if you are not using namespaces within StorageOS. + Namespaces that do not pre-exist within StorageOS will be created. + type: string + type: object + vsphereVolume: + description: vsphereVolume represents a vSphere volume + attached and mounted on kubelets host machine + properties: + fsType: + description: |- + fsType is filesystem type to mount. + Must be a filesystem type supported by the host operating system. + Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + type: string + storagePolicyID: + description: storagePolicyID is the storage Policy + Based Management (SPBM) profile ID associated + with the StoragePolicyName. + type: string + storagePolicyName: + description: storagePolicyName is the storage + Policy Based Management (SPBM) profile name. + type: string + volumePath: + description: volumePath is the path that identifies + vSphere volume vmdk + type: string + required: + - volumePath + type: object + required: + - name + type: object + type: array + type: object + targetNamespaces: + description: The target namespace of the OperatorGroups. + items: + type: string + type: array + userManaged: + description: UserManaged is a flag to indicate whether operator + is managed by user + type: boolean + required: + - channel + - name + - packageName + type: object + x-kubernetes-preserve-unknown-fields: true + type: array + type: object + x-kubernetes-preserve-unknown-fields: true + status: + description: OperandRegistryStatus defines the observed state of OperandRegistry. + properties: + conditions: + description: Conditions represents the current state of the Request + Service. + items: + description: |- + Condition represents the current state of the Request Service. + A condition might not show up if it is not happening. + properties: + lastTransitionTime: + description: Last time the condition transitioned from one status + to another. + type: string + lastUpdateTime: + description: The last time this condition was updated. + type: string + message: + description: A human readable message indicating details about + the transition. + type: string + reason: + description: The reason for the condition's last transition. + type: string + status: + description: Status of the condition, one of True, False, Unknown. + type: string + type: + description: Type of condition. + type: string + required: + - status + - type + type: object + type: array + operatorsStatus: + additionalProperties: + description: OperatorStatus defines operators status and the number + of reconcile request. + properties: + phase: + description: Phase is the state of operator. + type: string + reconcileRequests: + description: ReconcileRequests stores the namespace/name of + all the requests. + items: + description: ReconcileRequest records the information of the + operandRequest. + properties: + name: + description: Name defines the name of request. + type: string + namespace: + description: Namespace defines the namespace of request. + type: string + required: + - name + - namespace + type: object + type: array + type: object + description: OperatorsStatus defines operators status and the number + of reconcile request. + type: object + phase: + description: Phase describes the overall phase of operators in the + OperandRegistry. + type: string + type: object + x-kubernetes-preserve-unknown-fields: true + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: null + storedVersions: null + +--- + +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + creationTimestamp: null + # labels: + # app.kubernetes.io/instance: operand-deployment-lifecycle-manager + # app.kubernetes.io/managed-by: operand-deployment-lifecycle-manager + # app.kubernetes.io/name: operand-deployment-lifecycle-manager + name: operandrequests.operator.ibm.com +spec: + group: operator.ibm.com + names: + kind: OperandRequest + listKind: OperandRequestList + plural: operandrequests + shortNames: + - opreq + singular: operandrequest + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + - description: Current Phase + jsonPath: .status.phase + name: Phase + type: string + - jsonPath: .metadata.creationTimestamp + name: Created At + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: OperandRequest is the Schema for the operandrequests API. Documentation + For additional details regarding install parameters check https://ibm.biz/icpfs39install. + License By installing this product you accept the license terms https://ibm.biz/icpfs39license + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: The OperandRequestSpec identifies one or more specific operands + (from a specific Registry) that should actually be installed. + properties: + requests: + description: Requests defines a list of operands installation. + items: + description: Request identifies a operand detail. + properties: + description: + description: Description is an optional description for the + request. + type: string + operands: + description: Operands defines a list of the OperandRegistry + entry for the operand to be deployed. + items: + description: Operand defines the name and binding information + for one operator. + properties: + apiVersion: + description: APIVersion defines the versioned schema of + this representation of an object. + type: string + bindings: + additionalProperties: + description: |- + Bindable is a Kubernetes resources to be shared from one namespace to another. + List of supported resources are Secrets, Configmaps, Services, and Routes. + Secrets and Configmaps will be copied such that a new Secret/Configmap with + exactly the same data will be created in the target namespace. + Services and Routes data will be copied into a configmap in the target + namespace. + properties: + configmap: + description: The configmap identifies an existing + configmap object. if it exists, the ODLM will + share to the namespace of the OperandRequest. + type: string + route: + description: |- + Route data will be shared by copying it into a configmap which is then + created in the target namespace + properties: + data: + additionalProperties: + type: string + description: |- + Data is a key-value pair where the value is a YAML path to a value in the + OpenShift Route, e.g. .spec.host or .spec.tls.termination + type: object + name: + description: Name is the name of the OpenShift + Route resource + type: string + type: object + secret: + description: The secret identifies an existing secret. + if it exists, the ODLM will share to the namespace + of the OperandRequest. + type: string + service: + description: |- + Service data will be shared by copying it into a configmap which is then + created in the target namespace + properties: + data: + additionalProperties: + type: string + description: |- + Data is a key-value pair where the value is a YAML path to a value in the + Kubernetes Service, e.g. .spec.ports[0]port + type: object + name: + description: Name is the name of the Kubernetes + Service resource + type: string + type: object + type: object + description: The bindings section is used to specify names + of secret and/or configmap. + type: object + instanceName: + description: |- + InstanceName is used when users want to deploy multiple custom resources. + It is the name of the custom resource. + type: string + kind: + description: |- + Kind is used when users want to deploy multiple custom resources. + Kind identifies the kind of the custom resource. + type: string + name: + description: Name of the operand to be deployed. + type: string + spec: + description: |- + Spec is used when users want to deploy multiple custom resources. + It is the configuration map of custom resource. + nullable: true + type: object + x-kubernetes-preserve-unknown-fields: true + required: + - name + type: object + type: array + registry: + description: Specifies the name in which the OperandRegistry + reside. + type: string + registryNamespace: + description: |- + Specifies the namespace in which the OperandRegistry reside. + The default is the current namespace in which the request is defined. + type: string + required: + - operands + - registry + type: object + type: array + required: + - requests + type: object + x-kubernetes-preserve-unknown-fields: true + status: + description: OperandRequestStatus defines the observed state of OperandRequest. + properties: + conditions: + description: Conditions represents the current state of the Request + Service. + items: + description: |- + Condition represents the current state of the Request Service. + A condition might not show up if it is not happening. + properties: + lastTransitionTime: + description: Last time the condition transitioned from one status + to another. + type: string + lastUpdateTime: + description: The last time this condition was updated. + type: string + message: + description: A human readable message indicating details about + the transition. + type: string + reason: + description: The reason for the condition's last transition. + type: string + status: + description: Status of the condition, one of True, False, Unknown. + type: string + type: + description: Type of condition. + type: string + required: + - status + - type + type: object + type: array + members: + description: Members represnets the current operand status of the + set. + items: + description: MemberStatus shows if the Operator is ready. + properties: + name: + description: The member name are the same as the subscription + name. + type: string + operandCRList: + description: OperandCRList shows the list of custom resource + created by OperandRequest. + items: + description: OperandCRMember defines a custom resource created + by OperandRequest. + properties: + apiVersion: + description: APIVersion is the APIVersion of the custom + resource. + type: string + kind: + description: Kind is the kind of the custom resource. + type: string + name: + description: Name is the name of the custom resource. + type: string + type: object + type: array + phase: + description: The operand phase include None, Creating, Running, + Failed. + properties: + operandPhase: + description: OperandPhase shows the deploy phase of the + operator instance. + type: string + operatorPhase: + description: OperatorPhase shows the deploy phase of the + operator. + type: string + type: object + required: + - name + type: object + type: array + phase: + description: Phase is the cluster running phase. + type: string + services: + description: Services reflect the status of operands beyond whether + they have been created + items: + properties: + namespace: + type: string + operatorName: + type: string + resources: + description: LastUpdateTime string `json:"lastTransitionTime,omitempty"` + items: + properties: + apiVersion: + type: string + kind: + type: string + managedResources: + description: Message string `json:"message,omitempty"` + items: + properties: + apiVersion: + type: string + kind: + type: string + namespace: + type: string + objectName: + type: string + status: + description: Type string `json:"type,omitempty"` + type: string + type: object + type: array + namespace: + type: string + objectName: + type: string + status: + type: string + type: object + type: array + status: + description: Type string `json:"type,omitempty"` + type: string + type: object + type: array + type: object + x-kubernetes-preserve-unknown-fields: true + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: null + storedVersions: null + +--- + + +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + creationTimestamp: null + # labels: + # app.kubernetes.io/instance: operand-deployment-lifecycle-manager + # app.kubernetes.io/managed-by: operand-deployment-lifecycle-manager + # app.kubernetes.io/name: operand-deployment-lifecycle-manager + name: operatorconfigs.operator.ibm.com +spec: + group: operator.ibm.com + names: + kind: OperatorConfig + listKind: OperatorConfigList + plural: operatorconfigs + singular: operatorconfig + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + - description: Current Phase + jsonPath: .status.phase + name: Phase + type: string + - jsonPath: .metadata.creationTimestamp + name: Created At + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: OperatorConfig is the Schema for the operatorconfigs API. Documentation + For additional details regarding install parameters check https://ibm.biz/icpfs39install. + License By installing this product you accept the license terms https://ibm.biz/icpfs39license + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: OperatorConfigSpec defines the desired state of OperatorConfig + properties: + foo: + description: Foo is an example field of OperatorConfig. Edit operatorconfig_types.go + to remove/update + type: string + services: + description: Services is a list of services to be configured, specifically + their operators + items: + description: ServiceOperatorConfig defines the configuration of + the service. + properties: + affinity: + description: If specified, the pod's scheduling constraints + properties: + nodeAffinity: + description: Describes node affinity scheduling rules for + the pod. + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node matches the corresponding matchExpressions; the + node(s) with the highest sum are the most preferred. + items: + description: |- + An empty preferred scheduling term matches all objects with implicit weight 0 + (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op). + properties: + preference: + description: A node selector term, associated + with the corresponding weight. + properties: + matchExpressions: + description: A list of node selector requirements + by node's labels. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the + selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchFields: + description: A list of node selector requirements + by node's fields. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the + selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + type: object + x-kubernetes-map-type: atomic + weight: + description: Weight associated with matching the + corresponding nodeSelectorTerm, in the range + 1-100. + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to an update), the system + may or may not try to eventually evict the pod from its node. + properties: + nodeSelectorTerms: + description: Required. A list of node selector terms. + The terms are ORed. + items: + description: |- + A null or empty node selector term matches no objects. The requirements of + them are ANDed. + The TopologySelectorTerm type implements a subset of the NodeSelectorTerm. + properties: + matchExpressions: + description: A list of node selector requirements + by node's labels. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the + selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchFields: + description: A list of node selector requirements + by node's fields. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the + selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + type: object + x-kubernetes-map-type: atomic + type: array + required: + - nodeSelectorTerms + type: object + x-kubernetes-map-type: atomic + type: object + podAffinity: + description: Describes pod affinity scheduling rules (e.g. + co-locate this pod in the same node, zone, etc. as some + other pod(s)). + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the + node(s) with the highest sum are the most preferred. + items: + description: The weights of all of the matched WeightedPodAffinityTerm + fields are added per-node to find the most preferred + node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity term, associated + with the corresponding weight. + properties: + labelSelector: + description: A label query over a set of resources, + in this case pods. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The + requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The + requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + weight: + description: |- + weight associated with matching the corresponding podAffinityTerm, + in the range 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to a pod label update), the + system may or may not try to eventually evict the pod from its node. + When there are multiple elements, the lists of nodes corresponding to each + podAffinityTerm are intersected, i.e. all terms must be satisfied. + items: + description: |- + Defines a set of pods (namely those matching the labelSelector + relative to the given namespace(s)) that this pod should be + co-located (affinity) or not co-located (anti-affinity) with, + where co-located is defined as running on a node whose value of + the label with key matches that of any node on which + a pod of the set of pods is running + properties: + labelSelector: + description: A label query over a set of resources, + in this case pods. + properties: + matchExpressions: + description: matchExpressions is a list of + label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list of + label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + type: array + type: object + podAntiAffinity: + description: Describes pod anti-affinity scheduling rules + (e.g. avoid putting this pod in the same node, zone, etc. + as some other pod(s)). + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the anti-affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling anti-affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the + node(s) with the highest sum are the most preferred. + items: + description: The weights of all of the matched WeightedPodAffinityTerm + fields are added per-node to find the most preferred + node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity term, associated + with the corresponding weight. + properties: + labelSelector: + description: A label query over a set of resources, + in this case pods. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The + requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The + requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + weight: + description: |- + weight associated with matching the corresponding podAffinityTerm, + in the range 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the anti-affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the anti-affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to a pod label update), the + system may or may not try to eventually evict the pod from its node. + When there are multiple elements, the lists of nodes corresponding to each + podAffinityTerm are intersected, i.e. all terms must be satisfied. + items: + description: |- + Defines a set of pods (namely those matching the labelSelector + relative to the given namespace(s)) that this pod should be + co-located (affinity) or not co-located (anti-affinity) with, + where co-located is defined as running on a node whose value of + the label with key matches that of any node on which + a pod of the set of pods is running + properties: + labelSelector: + description: A label query over a set of resources, + in this case pods. + properties: + matchExpressions: + description: matchExpressions is a list of + label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list of + label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + type: array + type: object + type: object + name: + description: Name is the operator name as requested in the OperandRequest. + type: string + replicas: + description: |- + Number of desired pods. This is a pointer to distinguish between explicit + zero and not specified. Defaults to 1. + format: int32 + type: integer + topologySpreadConstraints: + description: |- + TopologySpreadConstraints describes how a group of pods ought to spread across topology + domains. Scheduler will schedule pods in a way which abides by the constraints. + All topologySpreadConstraints are ANDed. + items: + description: TopologySpreadConstraint specifies how to spread + matching pods among the given topology. + properties: + labelSelector: + description: |- + LabelSelector is used to find matching pods. + Pods that match this label selector are counted to determine the number of pods + in their corresponding topology domain. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + maxSkew: + description: |- + MaxSkew describes the degree to which pods may be unevenly distributed. + When `whenUnsatisfiable=DoNotSchedule`, it is the maximum permitted difference + between the number of matching pods in the target topology and the global minimum. + The global minimum is the minimum number of matching pods in an eligible domain + or zero if the number of eligible domains is less than MinDomains. + For example, in a 3-zone cluster, MaxSkew is set to 1, and pods with the same + labelSelector spread as 2/2/1: + In this case, the global minimum is 1. + | zone1 | zone2 | zone3 | + | P P | P P | P | + - if MaxSkew is 1, incoming pod can only be scheduled to zone3 to become 2/2/2; + scheduling it onto zone1(zone2) would make the ActualSkew(3-1) on zone1(zone2) + violate MaxSkew(1). + - if MaxSkew is 2, incoming pod can be scheduled onto any zone. + When `whenUnsatisfiable=ScheduleAnyway`, it is used to give higher precedence + to topologies that satisfy it. + It's a required field. Default value is 1 and 0 is not allowed. + format: int32 + type: integer + minDomains: + description: |- + MinDomains indicates a minimum number of eligible domains. + When the number of eligible domains with matching topology keys is less than minDomains, + Pod Topology Spread treats "global minimum" as 0, and then the calculation of Skew is performed. + And when the number of eligible domains with matching topology keys equals or greater than minDomains, + this value has no effect on scheduling. + As a result, when the number of eligible domains is less than minDomains, + scheduler won't schedule more than maxSkew Pods to those domains. + If value is nil, the constraint behaves as if MinDomains is equal to 1. + Valid values are integers greater than 0. + When value is not nil, WhenUnsatisfiable must be DoNotSchedule. + + + For example, in a 3-zone cluster, MaxSkew is set to 2, MinDomains is set to 5 and pods with the same + labelSelector spread as 2/2/2: + | zone1 | zone2 | zone3 | + | P P | P P | P P | + The number of domains is less than 5(MinDomains), so "global minimum" is treated as 0. + In this situation, new pod with the same labelSelector cannot be scheduled, + because computed skew will be 3(3 - 0) if new Pod is scheduled to any of the three zones, + it will violate MaxSkew. + + + This is an alpha field and requires enabling MinDomainsInPodTopologySpread feature gate. + format: int32 + type: integer + topologyKey: + description: |- + TopologyKey is the key of node labels. Nodes that have a label with this key + and identical values are considered to be in the same topology. + We consider each as a "bucket", and try to put balanced number + of pods into each bucket. + We define a domain as a particular instance of a topology. + Also, we define an eligible domain as a domain whose nodes match the node selector. + e.g. If TopologyKey is "kubernetes.io/hostname", each Node is a domain of that topology. + And, if TopologyKey is "topology.kubernetes.io/zone", each zone is a domain of that topology. + It's a required field. + type: string + whenUnsatisfiable: + description: |- + WhenUnsatisfiable indicates how to deal with a pod if it doesn't satisfy + the spread constraint. + - DoNotSchedule (default) tells the scheduler not to schedule it. + - ScheduleAnyway tells the scheduler to schedule the pod in any location, + but giving higher precedence to topologies that would help reduce the + skew. + A constraint is considered "Unsatisfiable" for an incoming pod + if and only if every possible node assignment for that pod would violate + "MaxSkew" on some topology. + For example, in a 3-zone cluster, MaxSkew is set to 1, and pods with the same + labelSelector spread as 3/1/1: + | zone1 | zone2 | zone3 | + | P P P | P | P | + If WhenUnsatisfiable is set to DoNotSchedule, incoming pod can only be scheduled + to zone2(zone3) to become 3/2/1(3/1/2) as ActualSkew(2-1) on zone2(zone3) satisfies + MaxSkew(1). In other words, the cluster can still be imbalanced, but scheduler + won't make it *more* imbalanced. + It's a required field. + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array + x-kubernetes-list-map-keys: + - topologyKey + - whenUnsatisfiable + x-kubernetes-list-type: map + required: + - name + type: object + type: array + x-kubernetes-preserve-unknown-fields: true + type: object + x-kubernetes-preserve-unknown-fields: true + status: + description: OperatorConfigStatus defines the observed state of OperatorConfig + type: object + x-kubernetes-preserve-unknown-fields: true + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: null + storedVersions: null diff --git a/helm-cluster-scoped/values.yaml b/helm-cluster-scoped/values.yaml new file mode 100644 index 00000000..e036eac8 --- /dev/null +++ b/helm-cluster-scoped/values.yaml @@ -0,0 +1,12 @@ +imagePullPrefix: icr.io +imagePullSecret: ibm-entitlement-key + +# Note there are no leading or trailing /'s +imageRegistryNamespaceOperator: cpopen +imageRegistryNamespaceOperand: cpopen/cpfs + +# other configuration you think you might need for your operator +# following are examples, not required: +operatorNamespace: ibm-common-services +servicesNamespace: service +operatorImage: odlm \ No newline at end of file diff --git a/helm/Chart.yaml b/helm/Chart.yaml new file mode 100644 index 00000000..ceaf57ef --- /dev/null +++ b/helm/Chart.yaml @@ -0,0 +1,6 @@ +apiVersion: v2 +name: ibm-odlm +description: A Helm chart for ibm-odlm +type: application +version: 4.3.9 +appVersion: 4.3.9 \ No newline at end of file diff --git a/helm/templates/operator-deployment.yaml b/helm/templates/operator-deployment.yaml new file mode 100644 index 00000000..5bb0b4c0 --- /dev/null +++ b/helm/templates/operator-deployment.yaml @@ -0,0 +1,258 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app.kubernetes.io/managed-by: Helm + productName: IBM_Cloud_Platform_Common_Services + name: operand-deployment-lifecycle-manager + namespace: {{ .Values.operatorNamespace }} +spec: + progressDeadlineSeconds: 600 + replicas: 1 + revisionHistoryLimit: 1 + selector: + matchLabels: + name: operand-deployment-lifecycle-manager + strategy: + rollingUpdate: + maxSurge: 25% + maxUnavailable: 25% + type: RollingUpdate + template: + metadata: + annotations: + alm-examples: |- + [ + { + "apiVersion": "operator.ibm.com/v1alpha1", + "kind": "OperandBindInfo", + "metadata": { + "labels": { + "app.kubernetes.io/instance": "operand-deployment-lifecycle-manager", + "app.kubernetes.io/managed-by": "operand-deployment-lifecycle-manager", + "app.kubernetes.io/name": "operand-deployment-lifecycle-manager" + }, + "name": "example-service" + }, + "spec": { + "bindings": { + "public": { + "configmap": "mongodb-configmap", + "secret": "mongodb-secret" + } + }, + "description": "Binding information that should be accessible to MongoDB adopters", + "operand": "mongodb-atlas-kubernetes", + "registry": "example-service" + } + }, + { + "apiVersion": "operator.ibm.com/v1alpha1", + "kind": "OperandConfig", + "metadata": { + "labels": { + "app.kubernetes.io/instance": "operand-deployment-lifecycle-manager", + "app.kubernetes.io/managed-by": "operand-deployment-lifecycle-manager", + "app.kubernetes.io/name": "operand-deployment-lifecycle-manager" + }, + "name": "example-service" + }, + "spec": { + "services": [ + { + "name": "jaeger", + "spec": { + "jaeger": { + "strategy": "allinone" + } + } + }, + { + "name": "mongodb-atlas-kubernetes", + "spec": { + "atlasDeployment": { + "deploymentSpec": { + "name": "test-deployment" + }, + "projectRef": { + "name": "my-project" + } + } + } + } + ] + } + }, + { + "apiVersion": "operator.ibm.com/v1alpha1", + "kind": "OperandRegistry", + "metadata": { + "labels": { + "app.kubernetes.io/instance": "operand-deployment-lifecycle-manager", + "app.kubernetes.io/managed-by": "operand-deployment-lifecycle-manager", + "app.kubernetes.io/name": "operand-deployment-lifecycle-manager" + }, + "name": "example-service" + }, + "spec": { + "operators": [ + { + "channel": "stable", + "installMode": "cluster", + "name": "jaeger", + "namespace": "default", + "packageName": "jaeger", + "sourceName": "community-operators", + "sourceNamespace": "openshift-marketplace" + }, + { + "channel": "stable", + "name": "mongodb-atlas-kubernetes", + "namespace": "default", + "packageName": "mongodb-atlas-kubernetes", + "sourceName": "community-operators", + "sourceNamespace": "openshift-marketplace" + } + ] + } + }, + { + "apiVersion": "operator.ibm.com/v1alpha1", + "kind": "OperandRequest", + "metadata": { + "labels": { + "app.kubernetes.io/instance": "operand-deployment-lifecycle-manager", + "app.kubernetes.io/managed-by": "operand-deployment-lifecycle-manager", + "app.kubernetes.io/name": "operand-deployment-lifecycle-manager" + }, + "name": "example-service" + }, + "spec": { + "requests": [ + { + "operands": [ + { + "name": "jaeger" + }, + { + "name": "mongodb-atlas-kubernetes" + } + ], + "registry": "example-service" + } + ] + } + } + ] + capabilities: Seamless Upgrades + categories: Developer Tools, Monitoring, Logging & Tracing, Security + certified: "false" + containerImage: icr.io/cpopen/odlm@sha256:3076710c9891bfb573ea4744398d02977702e8cf24e9f5151f9607c4dc2f95db + createdAt: "2024-09-28T19:55:35Z" + description: The Operand Deployment Lifecycle Manager provides a Kubernetes + CRD-based API to manage the lifecycle of operands. + nss.operator.ibm.com/managed-operators: ibm-odlm + # olm.operatorGroup: common-service + # olm.operatorNamespace: cs-op + # olm.skipRange: '>=1.2.0 <4.3.8' + # olm.targetNamespaces: cs-op + operatorframework.io/properties: '{"properties":[{"type":"olm.gvk","value":{"group":"operator.ibm.com","kind":"OperandBindInfo","version":"v1alpha1"}},{"type":"olm.gvk","value":{"group":"operator.ibm.com","kind":"OperandConfig","version":"v1alpha1"}},{"type":"olm.gvk","value":{"group":"operator.ibm.com","kind":"OperandRegistry","version":"v1alpha1"}},{"type":"olm.gvk","value":{"group":"operator.ibm.com","kind":"OperandRequest","version":"v1alpha1"}},{"type":"olm.gvk","value":{"group":"operator.ibm.com","kind":"OperatorConfig","version":"v1alpha1"}},{"type":"olm.package","value":{"packageName":"ibm-odlm","version":"4.3.8"}}]}' + operators.openshift.io/infrastructure-features: '["disconnected"]' + operators.operatorframework.io/builder: operator-sdk-v1.32.0 + operators.operatorframework.io/project_layout: go.kubebuilder.io/v3 + productID: 068a62892a1e4db39641342e592daa25 + productMetric: FREE + productName: IBM Cloud Platform Common Services + repository: https://github.com/IBM/operand-deployment-lifecycle-manager + support: IBM + creationTimestamp: null + labels: + app.kubernetes.io/managed-by: Helm + intent: projected + name: operand-deployment-lifecycle-manager + productName: IBM_Cloud_Platform_Common_Services + spec: + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: kubernetes.io/arch + operator: In + values: + - amd64 + - ppc64le + - s390x + containers: + - args: + - -v=1 + command: + - /manager + env: + - name: OPERATOR_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: WATCH_NAMESPACE + valueFrom: + configMapKeyRef: + key: namespaces + name: namespace-scope + optional: true + - name: OPERATOR_CONDITION_NAME + value: operand-deployment-lifecycle-manager.v4.3.9 + - name: NO_OLM + value: "true" + image: {{ .Values.imagePullPrefix}}/{{ .Values.imageRegistryNamespaceOperator}}/{{ .Values.operatorImage }}:latest + imagePullPolicy: IfNotPresent + livenessProbe: + failureThreshold: 10 + httpGet: + path: /readyz + port: 8081 + scheme: HTTP + initialDelaySeconds: 120 + periodSeconds: 60 + successThreshold: 1 + timeoutSeconds: 10 + name: manager + readinessProbe: + failureThreshold: 10 + httpGet: + path: /healthz + port: 8081 + scheme: HTTP + initialDelaySeconds: 5 + periodSeconds: 20 + successThreshold: 1 + timeoutSeconds: 3 + resources: + limits: + cpu: 500m + memory: 512Mi + requests: + cpu: 200m + ephemeral-storage: 256Mi + memory: 200Mi + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + privileged: false + readOnlyRootFilesystem: true + runAsNonRoot: true + seccompProfile: + type: RuntimeDefault + terminationMessagePath: /dev/termination-log + terminationMessagePolicy: File + imagePullSecrets: + - name: {{ .Values.imagePullSecret }} + dnsPolicy: ClusterFirst + restartPolicy: Always + schedulerName: default-scheduler + securityContext: {} + serviceAccount: operand-deployment-lifecycle-manager + serviceAccountName: operand-deployment-lifecycle-manager + terminationGracePeriodSeconds: 10 diff --git a/helm/templates/rbac.yaml b/helm/templates/rbac.yaml new file mode 100644 index 00000000..d599bdf7 --- /dev/null +++ b/helm/templates/rbac.yaml @@ -0,0 +1,221 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: operand-deployment-lifecycle-manager + namespace: {{ .Values.operatorNamespace }} +rules: +- apiGroups: + - "" + resources: + - configmaps + - namespaces + - secrets + - services + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - '*' + resources: + - '*' + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - k8s.keycloak.org + resources: + - keycloakrealmimports + - keycloaks + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - operator.ibm.com + resources: + - operandbindinfos + - operandbindinfos/finalizers + - operandbindinfos/status + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - operator.ibm.com + resources: + - operandconfigs + - operandconfigs/finalizers + - operandconfigs/status + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - operator.ibm.com + resources: + - operandregistries + - operandregistries/finalizers + - operandregistries/status + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - operator.ibm.com + resources: + - operandrequests + - operandrequests/finalizers + - operandrequests/status + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - operator.ibm.com + resources: + - operatorconfigs + - operatorconfigs/finalizers + - operatorconfigs/status + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - operators.coreos.com + resources: + - clusterserviceversions + - subscriptions + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - operators.coreos.com + resources: + - installplans + - operatorgroups + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - packages.operators.coreos.com + resources: + - packagemanifests + verbs: + - get + - list + - patch + - update + - watch +- apiGroups: + - route.openshift.io + resources: + - routes + verbs: + - create + - delete + - get + - list + - patch + - update + - watch + +--- + +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: operand-deployment-lifecycle-manager +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: operand-deployment-lifecycle-manager +subjects: +- kind: ServiceAccount + name: operand-deployment-lifecycle-manager + namespace: {{ .Values.operatorNamespace }} +--- + +apiVersion: v1 +kind: ServiceAccount +metadata: + name: operand-deployment-lifecycle-manager + namespace: {{ .Values.operatorNamespace }} + +--- +### role only for olm +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: operand-deployment-lifecycle-manager.v4.3.9 + namespace: {{ .Values.operatorNamespace }} +rules: +- apiGroups: + - operators.coreos.com + resourceNames: + - operand-deployment-lifecycle-manager.v4.3.9 + resources: + - operatorconditions + verbs: + - get + - update + - patch + +--- +### rolebinding only for olm +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: operand-deployment-lifecycle-manager.v4.3.9 + namespace: {{ .Values.operatorNamespace }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: operand-deployment-lifecycle-manager.v4.3.9 +subjects: +- kind: ServiceAccount + name: operand-deployment-lifecycle-manager + namespace: {{ .Values.operatorNamespace }} diff --git a/helm/values.yaml b/helm/values.yaml new file mode 100644 index 00000000..5dbe421c --- /dev/null +++ b/helm/values.yaml @@ -0,0 +1,12 @@ +imagePullPrefix: icr.io +imagePullSecret: ibm-entitlement-key + +# Note there are no leading or trailing /'s +imageRegistryNamespaceOperator: cpopen +imageRegistryNamespaceOperand: cpopen/cpfs + +# other configuration you think you might need for your operator +# following are examples, not required: +operatorNamespace: ibm-common-services +servicesNamespace: service +operatorImage: odlm \ No newline at end of file From 76c2305170791f47d08079a892502a715a2235a4 Mon Sep 17 00:00:00 2001 From: Allen Li <46284272+qpdpQ@users.noreply.github.com> Date: Mon, 3 Feb 2025 15:47:08 -0500 Subject: [PATCH 171/179] update image tag and chart name (#1109) * update image tag Signed-off-by: Allen Li * add operatorVersion to values Signed-off-by: Allen Li --------- Signed-off-by: Allen Li --- helm-cluster-scoped/Chart.yaml | 2 +- helm-cluster-scoped/values.yaml | 2 +- helm/templates/operator-deployment.yaml | 2 +- helm/values.yaml | 1 + 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/helm-cluster-scoped/Chart.yaml b/helm-cluster-scoped/Chart.yaml index ceaf57ef..64e8b190 100644 --- a/helm-cluster-scoped/Chart.yaml +++ b/helm-cluster-scoped/Chart.yaml @@ -1,5 +1,5 @@ apiVersion: v2 -name: ibm-odlm +name: ibm-odlm-cluster-scoped description: A Helm chart for ibm-odlm type: application version: 4.3.9 diff --git a/helm-cluster-scoped/values.yaml b/helm-cluster-scoped/values.yaml index e036eac8..5dbe421c 100644 --- a/helm-cluster-scoped/values.yaml +++ b/helm-cluster-scoped/values.yaml @@ -9,4 +9,4 @@ imageRegistryNamespaceOperand: cpopen/cpfs # following are examples, not required: operatorNamespace: ibm-common-services servicesNamespace: service -operatorImage: odlm \ No newline at end of file +operatorImage: odlm \ No newline at end of file diff --git a/helm/templates/operator-deployment.yaml b/helm/templates/operator-deployment.yaml index 5bb0b4c0..e0c5846f 100644 --- a/helm/templates/operator-deployment.yaml +++ b/helm/templates/operator-deployment.yaml @@ -204,7 +204,7 @@ spec: value: operand-deployment-lifecycle-manager.v4.3.9 - name: NO_OLM value: "true" - image: {{ .Values.imagePullPrefix}}/{{ .Values.imageRegistryNamespaceOperator}}/{{ .Values.operatorImage }}:latest + image: {{ .Values.imagePullPrefix}}/{{ .Values.imageRegistryNamespaceOperator}}/{{ .Values.operatorImage }}:{{ .Values.operatorVersion }} imagePullPolicy: IfNotPresent livenessProbe: failureThreshold: 10 diff --git a/helm/values.yaml b/helm/values.yaml index 5dbe421c..b9ef354d 100644 --- a/helm/values.yaml +++ b/helm/values.yaml @@ -4,6 +4,7 @@ imagePullSecret: ibm-entitlement-key # Note there are no leading or trailing /'s imageRegistryNamespaceOperator: cpopen imageRegistryNamespaceOperand: cpopen/cpfs +operatorVersion: 4.3.9 # other configuration you think you might need for your operator # following are examples, not required: From c8d43d0247fdabb289bcd96b57146bd8320a06b3 Mon Sep 17 00:00:00 2001 From: Ben Luzarraga <31223504+bluzarraga@users.noreply.github.com> Date: Mon, 3 Feb 2025 21:37:49 -0600 Subject: [PATCH 172/179] refactor no olm controller code to handle cleanup on operandrequest deletion (#1108) * refactor no olm controller code to handle deletion Signed-off-by: Ben Luzarraga * cleanup Signed-off-by: Ben Luzarraga * update build params for testing Signed-off-by: Ben Luzarraga * update controller to watch configmap changes Signed-off-by: Ben Luzarraga * add watched by odlm label Signed-off-by: Ben Luzarraga * add debugging statements Signed-off-by: Ben Luzarraga * more debugging logs Signed-off-by: Ben Luzarraga * more debug statements Signed-off-by: Ben Luzarraga * remove user managed condition Signed-off-by: Ben Luzarraga * debug statements Signed-off-by: Ben Luzarraga * disable, edit debugging statements Signed-off-by: Ben Luzarraga --------- Signed-off-by: Ben Luzarraga --- Makefile | 2 +- api/v1alpha1/operandrequest_types.go | 2 + .../operandrequestnoolm_controller.go | 60 +-- .../operandrequestnoolm/reconcile_operand.go | 65 --- .../operandrequestnoolm/reconcile_operator.go | 441 +++++++----------- controllers/operator/manager.go | 84 ++++ 6 files changed, 267 insertions(+), 387 deletions(-) diff --git a/Makefile b/Makefile index e0c488cb..3e1f49b9 100644 --- a/Makefile +++ b/Makefile @@ -89,7 +89,7 @@ OPERATOR_VERSION ?= 4.3.9 # Kind cluster name KIND_CLUSTER_NAME ?= "odlm" # Operator image tag for test -OPERATOR_TEST_TAG ?= nolm-controller3 +OPERATOR_TEST_TAG ?= nolm-controller-cleanup # Options for 'bundle-build' ifneq ($(origin CHANNELS), undefined) diff --git a/api/v1alpha1/operandrequest_types.go b/api/v1alpha1/operandrequest_types.go index 717e49ac..0ddc839d 100644 --- a/api/v1alpha1/operandrequest_types.go +++ b/api/v1alpha1/operandrequest_types.go @@ -131,6 +131,8 @@ const ( ResourceTypeCsv ResourceType = "csv" ResourceTypeOperator ResourceType = "operator" ResourceTypeOperand ResourceType = "operands" + ResourceTypeConfigmap ResourceType = "configmap" + ResourceTypeDeployment ResourceType = "deployment" ) // Condition represents the current state of the Request Service. diff --git a/controllers/operandrequestnoolm/operandrequestnoolm_controller.go b/controllers/operandrequestnoolm/operandrequestnoolm_controller.go index 86b7d1ad..99a9c294 100644 --- a/controllers/operandrequestnoolm/operandrequestnoolm_controller.go +++ b/controllers/operandrequestnoolm/operandrequestnoolm_controller.go @@ -26,8 +26,6 @@ import ( "time" gset "github.com/deckarep/golang-set" - olmv1 "github.com/operator-framework/api/pkg/operators/v1" - olmv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1" "github.com/pkg/errors" authorizationv1 "k8s.io/api/authorization/v1" corev1 "k8s.io/api/core/v1" @@ -56,9 +54,8 @@ type Reconciler struct { Mutex sync.Mutex } type clusterObjects struct { - namespace *corev1.Namespace - operatorGroup *olmv1.OperatorGroup - subscription *olmv1alpha1.Subscription + namespace *corev1.Namespace + configmap *corev1.ConfigMap } //+kubebuilder:rbac:groups=operator.ibm.com,resources=certmanagers;auditloggings,verbs=get;delete @@ -114,13 +111,13 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctrl.Re // Remove finalizer when DeletionTimestamp none zero if !requestInstance.ObjectMeta.DeletionTimestamp.IsZero() { - //TODO determine if necessary - // Check and clean up the subscriptions - // err := r.checkFinalizer(ctx, requestInstance) - // if err != nil { - // klog.Errorf("failed to clean up the subscriptions for OperandRequest %s: %v", req.NamespacedName.String(), err) - // return ctrl.Result{}, err - // } + //Checkfinalizers calls the delete function, not necessarily subscription based + //Check and clean up the operands + err := r.checkFinalizer(ctx, requestInstance) + if err != nil { + klog.Errorf("failed to clean up the operands for OperandRequest %s: %v", req.NamespacedName.String(), err) + return ctrl.Result{}, err + } originalReq := requestInstance.DeepCopy() // Update finalizer to allow delete CR @@ -163,12 +160,13 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctrl.Re return ctrl.Result{Requeue: true}, err } - // TODO remove this section + //Many of the cleanup functions are run through reconcileoperator as of 1.31.25 + //technically nothing is done to the operator deployment as of this writing (1.31.25) // Reconcile Operators - // if err := r.reconcileOperator(ctx, requestInstance); err != nil { - // klog.Errorf("failed to reconcile Operators for OperandRequest %s: %v", req.NamespacedName.String(), err) - // return ctrl.Result{}, err - // } + if err := r.reconcileOperator(ctx, requestInstance); err != nil { + klog.Errorf("failed to reconcile Operators for OperandRequest %s: %v", req.NamespacedName.String(), err) + return ctrl.Result{}, err + } // Reconcile Operands if merr := r.reconcileOperand(ctx, requestInstance); len(merr.Errors) != 0 { @@ -176,6 +174,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctrl.Re return ctrl.Result{}, merr } + //TODO update this block to check deployments and their operands instead // Check if all csv deploy succeed if requestInstance.Status.Phase != operatorv1alpha1.ClusterPhaseRunning { klog.V(2).Info("Waiting for all operators and operands to be deployed successfully ...") @@ -244,22 +243,10 @@ func (r *Reconciler) checkFinalizer(ctx context.Context, requestInstance *operat klog.V(1).Infof("Deleting OperandRequest %s in the namespace %s", requestInstance.Name, requestInstance.Namespace) remainingOperands := gset.NewSet() for _, m := range requestInstance.Status.Members { + klog.V(3).Infof("Operand %s added to deletion list", m.Name) remainingOperands.Add(m.Name) } - // TODO: update to check OperandRequest status to see if member is user managed or not - // existingSub := &olmv1alpha1.SubscriptionList{} - - // opts := []client.ListOption{ - // client.MatchingLabels(map[string]string{constant.OpreqLabel: "true"}), - // } - - // if err := r.Client.List(ctx, existingSub, opts...); err != nil { - // return err - // } - // if len(existingSub.Items) == 0 { - // return nil - // } - // Delete all the subscriptions that created by current request + // Delete all the operands and configmaps that created by current request if err := r.absentOperatorsAndOperands(ctx, requestInstance, &remainingOperands); err != nil { return err } @@ -395,14 +382,15 @@ func (r *Reconciler) SetupWithManager(mgr ctrl.Manager) error { return ctrl.NewControllerManagedBy(mgr). WithOptions(options). For(&operatorv1alpha1.OperandRequest{}, builder.WithPredicates(predicate.GenerationChangedPredicate{})). - Watches(&source.Kind{Type: &olmv1alpha1.Subscription{}}, handler.EnqueueRequestsFromMapFunc(r.getSubToRequestMapper()), builder.WithPredicates(predicate.Funcs{ + Watches(&source.Kind{Type: &corev1.ConfigMap{}}, handler.EnqueueRequestsFromMapFunc(r.getReferenceToRequestMapper()), builder.WithPredicates(predicate.Funcs{ UpdateFunc: func(e event.UpdateEvent) bool { - oldObject := e.ObjectOld.(*olmv1alpha1.Subscription) - newObject := e.ObjectNew.(*olmv1alpha1.Subscription) + oldObject := e.ObjectOld.(*corev1.ConfigMap) + newObject := e.ObjectNew.(*corev1.ConfigMap) if oldObject.Labels != nil && oldObject.Labels[constant.OpreqLabel] == "true" { - statusToggle := (oldObject.Status.InstalledCSV != "" && newObject.Status.InstalledCSV != "" && oldObject.Status.InstalledCSV != newObject.Status.InstalledCSV) + // statusToggle := (oldObject.Status.InstalledCSV != "" && newObject.Status.InstalledCSV != "" && oldObject.Status.InstalledCSV != newObject.Status.InstalledCSV) metadataToggle := !reflect.DeepEqual(oldObject.Annotations, newObject.Annotations) - return statusToggle || metadataToggle + // return statusToggle || metadataToggle + return metadataToggle } return false }, diff --git a/controllers/operandrequestnoolm/reconcile_operand.go b/controllers/operandrequestnoolm/reconcile_operand.go index 2fe2a9bf..3ac4cdf2 100644 --- a/controllers/operandrequestnoolm/reconcile_operand.go +++ b/controllers/operandrequestnoolm/reconcile_operand.go @@ -97,55 +97,8 @@ func (r *Reconciler) reconcileOperand(ctx context.Context, requestInstance *oper // Looking for the CSV namespace := r.GetOperatorNamespace(opdRegistry.InstallMode, opdRegistry.Namespace) - //TODO remove this section - // sub, err := r.GetSubscription(ctx, operatorName, namespace, registryInstance.Namespace, opdRegistry.PackageName) - // if err != nil { - // merr.Add(errors.Wrapf(err, "failed to get the Subscription %s in the namespace %s and %s", operatorName, namespace, registryInstance.Namespace)) - // return merr - // } - - // if !opdRegistry.UserManaged { - // if sub == nil { - // klog.Warningf("There is no Subscription %s or %s in the namespace %s and %s", operatorName, opdRegistry.PackageName, namespace, registryInstance.Namespace) - // continue - // } - - // if _, ok := sub.Labels[constant.OpreqLabel]; !ok { - // // Subscription existing and not managed by OperandRequest controller - // klog.Warningf("Subscription %s in the namespace %s isn't created by ODLM", sub.Name, sub.Namespace) - // } - - // // It the installplan is not created yet, ODLM will try later - // if sub.Status.Install == nil || sub.Status.InstallPlanRef.Name == "" { - // klog.Warningf("The Installplan for Subscription %s is not ready. Will check it again", sub.Name) - // requestInstance.SetMemberStatus(operand.Name, operatorv1alpha1.OperatorInstalling, "", &r.Mutex) - // continue - // } - - // // If the installplan is deleted after is completed, ODLM won't block the CR update. - // ipName := sub.Status.InstallPlanRef.Name - // ipNamespace := sub.Namespace - // ip := &olmv1alpha1.InstallPlan{} - // ipKey := types.NamespacedName{ - // Name: ipName, - // Namespace: ipNamespace, - // } - // if err := r.Client.Get(ctx, ipKey, ip); err != nil { - // if !apierrors.IsNotFound(err) { - // merr.Add(errors.Wrapf(err, "failed to get Installplan")) - // } - // } else if ip.Status.Phase == olmv1alpha1.InstallPlanPhaseFailed { - // klog.Errorf("installplan %s/%s is failed", ipNamespace, ipName) - // requestInstance.SetMemberStatus(operand.Name, operatorv1alpha1.OperatorFailed, "", &r.Mutex) - // continue - // } - - // } - - //var csv *olmv1alpha1.ClusterServiceVersion var deployment *appsv1.Deployment - //TODO need to translate this if block to look for deployments and not CSVs deploymentList, err := r.GetDeploymentListFromPackage(ctx, opdRegistry.PackageName, opdRegistry.Namespace) if err != nil { merr.Add(err) @@ -154,7 +107,6 @@ func (r *Reconciler) reconcileOperand(ctx context.Context, requestInstance *oper } deployment = deploymentList[0] - //TODO change this block to deal with an empty list of deployments instead of csvs if deployment == nil { klog.Warningf("Deployment for %s in the namespace %s is not ready yet, retry", operatorName, namespace) requestInstance.SetMemberStatus(operand.Name, operatorv1alpha1.OperatorInstalling, "", &r.Mutex) @@ -169,19 +121,6 @@ func (r *Reconciler) reconcileOperand(ctx context.Context, requestInstance *oper // continue // } - //TODO git rid of this section - // if !opdRegistry.UserManaged { - // // find the OperandRequest which has the same operator's channel or fallback channels as existing subscription. - // // ODLM will only reconcile Operand based on OperandConfig for this OperandRequest - // channels := []string{opdRegistry.Channel} - // if channels = append(channels, opdRegistry.FallbackChannels...); !util.Contains(channels, sub.Spec.Channel) { - // klog.Infof("Subscription %s in the namespace %s is NOT managed by %s/%s, Skip reconciling Operands", sub.Name, sub.Namespace, requestInstance.Namespace, requestInstance.Name) - // requestInstance.SetMemberStatus(operand.Name, operatorv1alpha1.OperatorFailed, "", &r.Mutex) - // continue - // } - // } - - //TODO update to deployment name klog.V(3).Info("Generating customresource base on Deployment: ", deployment.GetName()) requestInstance.SetMemberStatus(operand.Name, operatorv1alpha1.OperatorRunning, "", &r.Mutex) @@ -195,7 +134,6 @@ func (r *Reconciler) reconcileOperand(ctx context.Context, requestInstance *oper klog.V(2).Infof("There is no service: %s from the OperandConfig instance: %s/%s, Skip reconciling Operands", operand.Name, registryKey.Namespace, req.Registry) continue } - //TODO pass through deployment values here err = r.reconcileCRwithConfig(ctx, opdConfig, configInstance.Name, configInstance.Namespace, deployment, requestInstance, operand.Name, deployment.Namespace, &r.Mutex) if err != nil { merr.Add(err) @@ -263,7 +201,6 @@ func (r *Reconciler) reconcileCRwithConfig(ctx context.Context, service *operato } } - //TODO change this to deployment, make sure GetAnnotations works for deployments the same way almExamples := deployment.GetAnnotations()["alm-examples"] // Convert CR template string to slice @@ -320,7 +257,6 @@ func (r *Reconciler) reconcileCRwithConfig(ctx context.Context, service *operato } if !foundInConfig { - //TODO change to deployment klog.Warningf("%v in the alm-example doesn't exist in the OperandConfig for %v", crFromALM.GetKind(), deployment.GetName()) continue } @@ -365,7 +301,6 @@ func (r *Reconciler) reconcileCRwithConfig(ctx context.Context, service *operato for cr, found := range foundMap { if !found { - //TODO change to deployment klog.Warningf("Custom resource %v doesn't exist in the alm-example of %v", cr, deployment.GetName()) } } diff --git a/controllers/operandrequestnoolm/reconcile_operator.go b/controllers/operandrequestnoolm/reconcile_operator.go index 96e94a8b..6bd6d296 100644 --- a/controllers/operandrequestnoolm/reconcile_operator.go +++ b/controllers/operandrequestnoolm/reconcile_operator.go @@ -26,10 +26,6 @@ import ( "time" gset "github.com/deckarep/golang-set" - olmv1 "github.com/operator-framework/api/pkg/operators/v1" - olmv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1" - "github.com/pkg/errors" - "golang.org/x/mod/semver" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/equality" apierrors "k8s.io/apimachinery/pkg/api/errors" @@ -95,7 +91,7 @@ func (r *Reconciler) reconcileOperator(ctx context.Context, requestInstance *ope chunkSize = 1 } - // reconcile subscription in batch + // reconcile tracking configmaps in batch for i := 0; i < len(req.Operands); i += chunkSize { j := i + chunkSize if j > len(req.Operands) { @@ -108,7 +104,7 @@ func (r *Reconciler) reconcileOperator(ctx context.Context, requestInstance *ope wg.Add(1) go func(ctx context.Context, requestInstance *operatorv1alpha1.OperandRequest, registryInstance *operatorv1alpha1.OperandRegistry, operand operatorv1alpha1.Operand, registryKey types.NamespacedName, mu *sync.Mutex) { defer wg.Done() - if err := r.reconcileSubscription(ctx, requestInstance, registryInstance, operand, registryKey, mu); err != nil { + if err := r.reconcileOpReqCM(ctx, requestInstance, registryInstance, operand, registryKey, mu); err != nil { mu.Lock() defer mu.Unlock() merr.Add(err) @@ -132,12 +128,13 @@ func (r *Reconciler) reconcileOperator(ctx context.Context, requestInstance *ope return nil } -func (r *Reconciler) reconcileSubscription(ctx context.Context, requestInstance *operatorv1alpha1.OperandRequest, registryInstance *operatorv1alpha1.OperandRegistry, operand operatorv1alpha1.Operand, registryKey types.NamespacedName, mu sync.Locker) error { +// In No olm installs, we create empty configmaps that house the annotations ODLM looks for when cleaning up operators once an opreq is deleted +func (r *Reconciler) reconcileOpReqCM(ctx context.Context, requestInstance *operatorv1alpha1.OperandRequest, registryInstance *operatorv1alpha1.OperandRegistry, operand operatorv1alpha1.Operand, registryKey types.NamespacedName, mu sync.Locker) error { // Check the requested Operand if exist in specific OperandRegistry var opt *operatorv1alpha1.Operator if registryInstance != nil { var err error - opt, err = r.GetOperandFromRegistry(ctx, registryInstance, operand.Name) + opt, err = r.GetOperandFromRegistryNoOLM(ctx, registryInstance, operand.Name) if err != nil { return err } @@ -156,30 +153,17 @@ func (r *Reconciler) reconcileSubscription(ctx context.Context, requestInstance return nil } - // Check subscription if exist + // Check configmap if exist namespace := r.GetOperatorNamespace(opt.InstallMode, opt.Namespace) - sub, err := r.GetSubscription(ctx, opt.Name, namespace, registryInstance.Namespace, opt.PackageName) + cm, err := r.GetOpReqCM(ctx, opt.Name, namespace, registryInstance.Namespace, opt.PackageName) - if opt.UserManaged { - klog.Infof("Skip installing operator %s because it is managed by user", opt.PackageName) - csvList, err := r.GetClusterServiceVersionListFromPackage(ctx, opt.PackageName, namespace) - if err != nil { - return errors.Wrapf(err, "failed to get CSV from package %s/%s", namespace, opt.PackageName) - } - if len(csvList) == 0 { - return errors.New("operator " + opt.Name + " is user managed, but no CSV exists, waiting...") - } - requestInstance.SetMemberStatus(opt.Name, operatorv1alpha1.OperatorUpdating, "", mu) - return nil - } - - if sub == nil && err == nil { + if cm == nil && err == nil { if opt.InstallMode == operatorv1alpha1.InstallModeNoop { requestInstance.SetNoSuitableRegistryCondition(registryKey.String(), opt.Name+" is in maintenance status", operatorv1alpha1.ResourceTypeOperandRegistry, corev1.ConditionTrue, &r.Mutex) requestInstance.SetMemberStatus(operand.Name, operatorv1alpha1.OperatorRunning, operatorv1alpha1.ServiceRunning, mu) } else { - // Subscription does not exist, create a new one - if err = r.createSubscription(ctx, requestInstance, opt, registryKey); err != nil { + // CM does not exist, create a new one + if err = r.createOpReqCM(ctx, requestInstance, opt, registryKey); err != nil { requestInstance.SetMemberStatus(opt.Name, operatorv1alpha1.OperatorFailed, "", mu) return err } @@ -190,30 +174,27 @@ func (r *Reconciler) reconcileSubscription(ctx context.Context, requestInstance return err } - // Subscription existing and managed by OperandRequest controller - if _, ok := sub.Labels[constant.OpreqLabel]; ok { - originalSub := sub.DeepCopy() - var isMatchedChannel bool + // Operator existing and managed by OperandRequest controller + if _, ok := cm.Labels[constant.OpreqLabel]; ok { + originalCM := cm.DeepCopy() var isInScope bool - if sub.Namespace == opt.Namespace { + if cm.Namespace == opt.Namespace { isInScope = true } else { var nsAnnoSlice []string namespaceReg, _ := regexp.Compile(`^(.*)\.(.*)\.(.*)\/operatorNamespace`) - for anno, ns := range sub.Annotations { + for anno, ns := range cm.Annotations { if namespaceReg.MatchString(anno) { nsAnnoSlice = append(nsAnnoSlice, ns) } } - if len(nsAnnoSlice) != 0 && !util.Contains(nsAnnoSlice, sub.Namespace) { - - if r.checkUninstallLabel(sub) { + if len(nsAnnoSlice) != 0 && !util.Contains(nsAnnoSlice, cm.Namespace) { + if r.checkUninstallLabel(cm) { klog.V(1).Infof("Operator %s has label operator.ibm.com/opreq-do-not-uninstall. Skip the uninstall", opt.Name) return nil } - - if err = r.deleteSubscription(ctx, requestInstance, sub); err != nil { + if err = r.deleteOpReqCM(ctx, requestInstance, cm); err != nil { requestInstance.SetMemberStatus(opt.Name, operatorv1alpha1.OperatorFailed, "", mu) return err } @@ -222,81 +203,47 @@ func (r *Reconciler) reconcileSubscription(ctx context.Context, requestInstance } } - // add annotations to existing Subscriptions for upgrade case - if sub.Annotations == nil { - sub.Annotations = make(map[string]string) + // add annotations to existing tracking configmap for upgrade case + if cm.Annotations == nil { + cm.Annotations = make(map[string]string) } - sub.Annotations[registryKey.Namespace+"."+registryKey.Name+"/registry"] = "true" - sub.Annotations[registryKey.Namespace+"."+registryKey.Name+"/config"] = "true" - sub.Annotations[requestInstance.Namespace+"."+requestInstance.Name+"."+operand.Name+"/request"] = opt.Channel - sub.Annotations[requestInstance.Namespace+"."+requestInstance.Name+"."+operand.Name+"/operatorNamespace"] = namespace + cm.Annotations[registryKey.Namespace+"."+registryKey.Name+"/registry"] = "true" + cm.Annotations[registryKey.Namespace+"."+registryKey.Name+"/config"] = "true" + cm.Annotations[requestInstance.Namespace+"."+requestInstance.Name+"."+operand.Name+"/request"] = opt.Channel + cm.Annotations[requestInstance.Namespace+"."+requestInstance.Name+"."+operand.Name+"/operatorNamespace"] = namespace + cm.Annotations["packageName"] = opt.PackageName + cm.Labels["operator.ibm.com/watched-by-odlm"] = "true" if opt.InstallMode == operatorv1alpha1.InstallModeNoop { - isMatchedChannel = true requestInstance.SetNoSuitableRegistryCondition(registryKey.String(), opt.Name+" is in maintenance status", operatorv1alpha1.ResourceTypeOperandRegistry, corev1.ConditionTrue, &r.Mutex) requestInstance.SetMemberStatus(operand.Name, operatorv1alpha1.OperatorRunning, operatorv1alpha1.ServiceRunning, mu) - - // check if sub.Spec.Channel and opt.Channel are valid semantic version - // set annotation channel back to previous one if sub.Spec.Channel is lower than opt.Channel - // To avoid upgrade from one maintenance version to another maintenance version like from v3 to v3.23 - subChanel := util.FindSemantic(sub.Spec.Channel) - optChannel := util.FindSemantic(opt.Channel) - if semver.IsValid(subChanel) && semver.IsValid(optChannel) && semver.Compare(subChanel, optChannel) < 0 { - sub.Annotations[requestInstance.Namespace+"."+requestInstance.Name+"."+operand.Name+"/request"] = sub.Spec.Channel - } - } else if opt.SourceNamespace == "" || opt.SourceName == "" { - klog.Errorf("Failed to find catalogsource for operator %s with channel %s", opt.Name, opt.Channel) - requestInstance.SetMemberStatus(operand.Name, operatorv1alpha1.OperatorFailed, "", mu) } else { - requestInstance.SetNotFoundOperatorFromRegistryCondition(operand.Name, operatorv1alpha1.ResourceTypeSub, corev1.ConditionFalse, mu) - - if minChannel := util.FindMinSemverFromAnnotations(sub.Annotations, sub.Spec.Channel); minChannel != "" { - sub.Spec.Channel = minChannel - } - - channels := []string{opt.Channel} - if channels = append(channels, opt.FallbackChannels...); util.Contains(channels, sub.Spec.Channel) { - isMatchedChannel = true - } - // update the spec iff channel in sub matches channel - if sub.Spec.Channel == opt.Channel { - sub.Spec.CatalogSource = opt.SourceName - sub.Spec.CatalogSourceNamespace = opt.SourceNamespace - sub.Spec.Package = opt.PackageName - - if opt.InstallPlanApproval != "" && sub.Spec.InstallPlanApproval != opt.InstallPlanApproval { - sub.Spec.InstallPlanApproval = opt.InstallPlanApproval - } - if opt.SubscriptionConfig != nil { - sub.Spec.Config = opt.SubscriptionConfig - } - } - + requestInstance.SetNotFoundOperatorFromRegistryCondition(operand.Name, operatorv1alpha1.ResourceTypeConfigmap, corev1.ConditionFalse, mu) } - if compareSub(sub, originalSub) { - if err = r.updateSubscription(ctx, requestInstance, sub); err != nil { + if compareOpReqCM(cm, originalCM) { + if err = r.updateOpReqCM(ctx, requestInstance, cm); err != nil { requestInstance.SetMemberStatus(opt.Name, operatorv1alpha1.OperatorFailed, "", mu) return err } requestInstance.SetMemberStatus(opt.Name, operatorv1alpha1.OperatorUpdating, "", mu) } - if !isMatchedChannel || !isInScope { + if !isInScope { requestInstance.SetNoConflictOperatorCondition(operand.Name, operatorv1alpha1.ResourceTypeSub, corev1.ConditionFalse, mu) requestInstance.SetMemberStatus(opt.Name, operatorv1alpha1.OperatorFailed, "", mu) } else { requestInstance.SetNoConflictOperatorCondition(operand.Name, operatorv1alpha1.ResourceTypeSub, corev1.ConditionTrue, mu) } } else { - // Subscription existing and not managed by OperandRequest controller - klog.V(1).Infof("Subscription %s in namespace %s isn't created by ODLM. Ignore update/delete it.", sub.Name, sub.Namespace) + // Operator existing and not managed by OperandRequest controller + klog.V(1).Infof("Configmap %s in namespace %s isn't created by ODLM. Ignore update/delete it.", cm.Name, cm.Namespace) } return nil } -func (r *Reconciler) createSubscription(ctx context.Context, cr *operatorv1alpha1.OperandRequest, opt *operatorv1alpha1.Operator, key types.NamespacedName) error { +func (r *Reconciler) createOpReqCM(ctx context.Context, cr *operatorv1alpha1.OperandRequest, opt *operatorv1alpha1.Operator, key types.NamespacedName) error { namespace := r.GetOperatorNamespace(opt.InstallMode, opt.Namespace) - klog.V(3).Info("Subscription Namespace: ", namespace) + klog.V(3).Info("Cofigmap Namespace: ", namespace) co := r.generateClusterObjects(opt, key, types.NamespacedName{Namespace: cr.Namespace, Name: cr.Name}) @@ -312,188 +259,139 @@ func (r *Reconciler) createSubscription(ctx context.Context, cr *operatorv1alpha } } - if namespace != constant.ClusterOperatorNamespace { - // Create required operatorgroup - existOG := &olmv1.OperatorGroupList{} - if err := r.Client.List(ctx, existOG, &client.ListOptions{Namespace: co.operatorGroup.Namespace}); err != nil { - return err - } - if len(existOG.Items) == 0 { - og := co.operatorGroup - klog.V(3).Info("Creating the OperatorGroup for Subscription: " + opt.Name) - if err := r.Create(ctx, og); err != nil && !apierrors.IsAlreadyExists(err) { - return err - } - } - } - - // Create subscription - klog.V(2).Info("Creating the Subscription: " + opt.Name) - if co.subscription.Spec.CatalogSource == "" || co.subscription.Spec.CatalogSourceNamespace == "" { - return fmt.Errorf("failed to find catalogsource for subscription %s/%s", co.subscription.Namespace, co.subscription.Name) - } + // Create CM + klog.V(2).Info("Creating the Configmap: " + opt.Name) - sub := co.subscription - cr.SetCreatingCondition(sub.Name, operatorv1alpha1.ResourceTypeSub, corev1.ConditionTrue, &r.Mutex) + cm := co.configmap + cr.SetCreatingCondition(cm.Name, operatorv1alpha1.ResourceTypeConfigmap, corev1.ConditionTrue, &r.Mutex) - if err := r.Create(ctx, sub); err != nil && !apierrors.IsAlreadyExists(err) { - cr.SetCreatingCondition(sub.Name, operatorv1alpha1.ResourceTypeSub, corev1.ConditionFalse, &r.Mutex) + if err := r.Create(ctx, cm); err != nil && !apierrors.IsAlreadyExists(err) { + cr.SetCreatingCondition(cm.Name, operatorv1alpha1.ResourceTypeConfigmap, corev1.ConditionFalse, &r.Mutex) return err } return nil } -func (r *Reconciler) updateSubscription(ctx context.Context, cr *operatorv1alpha1.OperandRequest, sub *olmv1alpha1.Subscription) error { +func (r *Reconciler) deleteOpReqCM(ctx context.Context, cr *operatorv1alpha1.OperandRequest, cm *corev1.ConfigMap) error { - klog.V(2).Infof("Updating Subscription %s/%s ...", sub.Namespace, sub.Name) - cr.SetUpdatingCondition(sub.Name, operatorv1alpha1.ResourceTypeSub, corev1.ConditionTrue, &r.Mutex) + klog.V(2).Infof("Deleting Subscription %s/%s ...", cm.Namespace, cm.Name) - if err := r.Update(ctx, sub); err != nil { - cr.SetUpdatingCondition(sub.Name, operatorv1alpha1.ResourceTypeSub, corev1.ConditionFalse, &r.Mutex) - return err + klog.V(2).Infof("Deleting the Configmap, Namespace: %s, Name: %s", cm.Namespace, cm.Name) + cr.SetDeletingCondition(cm.Name, operatorv1alpha1.ResourceTypeConfigmap, corev1.ConditionTrue, &r.Mutex) + + if err := r.Delete(ctx, cm); err != nil { + if apierrors.IsNotFound(err) { + klog.Warningf("Configmap %s was not found in namespace %s", cm.Name, cm.Namespace) + } else { + cr.SetDeletingCondition(cm.Name, operatorv1alpha1.ResourceTypeConfigmap, corev1.ConditionFalse, &r.Mutex) + return err + } } + + klog.V(1).Infof("Configmap %s/%s is deleted", cm.Namespace, cm.Name) return nil } -func (r *Reconciler) deleteSubscription(ctx context.Context, cr *operatorv1alpha1.OperandRequest, sub *olmv1alpha1.Subscription) error { +func (r *Reconciler) updateOpReqCM(ctx context.Context, cr *operatorv1alpha1.OperandRequest, cm *corev1.ConfigMap) error { - klog.V(2).Infof("Deleting Subscription %s/%s ...", sub.Namespace, sub.Name) + klog.V(2).Infof("Updating Configmap %s/%s ...", cm.Namespace, cm.Name) + cr.SetUpdatingCondition(cm.Name, operatorv1alpha1.ResourceTypeSub, corev1.ConditionTrue, &r.Mutex) - csvList, err := r.GetClusterServiceVersionList(ctx, sub) - // If can't get CSV, requeue the request - if err != nil { + if err := r.Update(ctx, cm); err != nil { + cr.SetUpdatingCondition(cm.Name, operatorv1alpha1.ResourceTypeSub, corev1.ConditionFalse, &r.Mutex) return err } - - if csvList != nil { - klog.Infof("Found %d ClusterServiceVersions for Subscription %s/%s", len(csvList), sub.Namespace, sub.Name) - for _, csv := range csvList { - klog.V(3).Info("Set Deleting Condition in the operandRequest") - cr.SetDeletingCondition(csv.Name, operatorv1alpha1.ResourceTypeCsv, corev1.ConditionTrue, &r.Mutex) - - klog.V(1).Infof("Deleting the ClusterServiceVersion, Namespace: %s, Name: %s", csv.Namespace, csv.Name) - if err := r.Delete(ctx, csv); err != nil { - cr.SetDeletingCondition(csv.Name, operatorv1alpha1.ResourceTypeCsv, corev1.ConditionFalse, &r.Mutex) - return err - } - } - } - - klog.V(2).Infof("Deleting the Subscription, Namespace: %s, Name: %s", sub.Namespace, sub.Name) - cr.SetDeletingCondition(sub.Name, operatorv1alpha1.ResourceTypeSub, corev1.ConditionTrue, &r.Mutex) - - if err := r.Delete(ctx, sub); err != nil { - if apierrors.IsNotFound(err) { - klog.Warningf("Subscription %s was not found in namespace %s", sub.Name, sub.Namespace) - } else { - cr.SetDeletingCondition(sub.Name, operatorv1alpha1.ResourceTypeSub, corev1.ConditionFalse, &r.Mutex) - return err - } - } - - klog.V(1).Infof("Subscription %s/%s is deleted", sub.Namespace, sub.Name) return nil } func (r *Reconciler) uninstallOperatorsAndOperands(ctx context.Context, operandName string, requestInstance *operatorv1alpha1.OperandRequest, registryInstance *operatorv1alpha1.OperandRegistry, configInstance *operatorv1alpha1.OperandConfig) error { // No error handling for un-installation step in case Catalog has been deleted - op, _ := r.GetOperandFromRegistry(ctx, registryInstance, operandName) + op, _ := r.GetOperandFromRegistryNoOLM(ctx, registryInstance, operandName) + // klog.V(1).Info("op to check in uninstallOperatorsAndOperands: ", op.Name, " o: ", fmt.Sprintf("%v", operandName)) if op == nil { klog.Warningf("Operand %s not found", operandName) return nil } namespace := r.GetOperatorNamespace(op.InstallMode, op.Namespace) - sub, err := r.GetSubscription(ctx, operandName, namespace, registryInstance.Namespace, op.PackageName) - if sub == nil && err == nil { - klog.V(3).Infof("There is no Subscription %s or %s in the namespace %s and %s", operandName, op.PackageName, namespace, registryInstance.Namespace) + + //Assuing we can still use op as a parameter, we should be able to get the deployment with ease + deploy, err := r.GetDeployment(ctx, operandName, namespace, registryInstance.Namespace, op.PackageName) + // klog.V(1).Info("deployment in uninstallOperatorsAndOperands: ", deploy.Name) + if deploy == nil && err == nil { + klog.V(3).Infof("There is no Deployment called %s or using package name %s in the namespace %s and %s", operandName, op.PackageName, namespace, registryInstance.Namespace) return nil } else if err != nil { - klog.Errorf("Failed to get Subscription %s or %s in the namespace %s and %s", operandName, op.PackageName, namespace, registryInstance.Namespace) + klog.Errorf("Failed to get Deployment called %s or using package name %s in the namespace %s and %s", operandName, op.PackageName, namespace, registryInstance.Namespace) return err } - if sub.Labels == nil { + if deploy.Labels == nil { // Subscription existing and not managed by OperandRequest controller - klog.V(2).Infof("Subscription %s in the namespace %s isn't created by ODLM", sub.Name, sub.Namespace) + klog.V(2).Infof("Deployment %s in the namespace %s isn't created by ODLM", deploy.Name, deploy.Namespace) return nil } - if _, ok := sub.Labels[constant.OpreqLabel]; !ok { - if !op.UserManaged { - klog.V(2).Infof("Subscription %s in the namespace %s isn't created by ODLM and isn't user managed", sub.Name, sub.Namespace) - return nil - } - } - - uninstallOperator, uninstallOperand := checkSubAnnotationsForUninstall(requestInstance.ObjectMeta.Name, requestInstance.ObjectMeta.Namespace, op.Name, op.InstallMode, sub) - if !uninstallOperand && !uninstallOperator { - if err = r.updateSubscription(ctx, requestInstance, sub); err != nil { - requestInstance.SetMemberStatus(op.Name, operatorv1alpha1.OperatorFailed, "", &r.Mutex) - return err - } - requestInstance.SetMemberStatus(op.Name, operatorv1alpha1.OperatorUpdating, "", &r.Mutex) - - klog.V(1).Infof("No deletion, subscription %s/%s and its operands are still requested by other OperandRequests", sub.Namespace, sub.Name) - return nil - } - - if deploymentList, err := r.GetDeploymentListFromPackage(ctx, op.PackageName, op.Namespace); err != nil { - // If can't get deployment, requeue the request - return err - } else if deploymentList != nil { - klog.Infof("Found %d Deployment for package %s/%s", len(deploymentList), op.Name, namespace) - if uninstallOperand { - klog.V(2).Infof("Deleting all the Custom Resources for Deployment, Namespace: %s, Name: %s", deploymentList[0].Namespace, deploymentList[0].Name) - if err := r.deleteAllCustomResource(ctx, deploymentList[0], requestInstance, configInstance, operandName, configInstance.Namespace); err != nil { + // if _, ok := deploy.Labels[constant.OpreqLabel]; !ok { + // if !op.UserManaged { + // klog.V(2).Infof("Deployment %s in the namespace %s isn't created by ODLM and isn't user managed", deploy.Name, deploy.Namespace) + // return nil + // } + // } + + cm, err := r.GetOpReqCM(ctx, op.Name, deploy.Namespace, registryInstance.Namespace, op.PackageName) + // klog.V(1).Info("Configmap tracking operand: ", cm.Name) + if cm != nil && err == nil { + uninstallOperator, uninstallOperand := checkOpReqCMAnnotationsForUninstall(requestInstance.ObjectMeta.Name, requestInstance.ObjectMeta.Namespace, op.Name, op.InstallMode, cm) + // klog.V(1).Info("uinstall operator: ", uninstallOperator, " uninstall operand: ", uninstallOperand) + if !uninstallOperand && !uninstallOperator { + if err = r.updateOpReqCM(ctx, requestInstance, cm); err != nil { + requestInstance.SetMemberStatus(op.Name, operatorv1alpha1.OperatorFailed, "", &r.Mutex) return err } - klog.V(2).Infof("Deleting all the k8s Resources for Deployment, Namespace: %s, Name: %s", deploymentList[0].Namespace, deploymentList[0].Name) - if err := r.deleteAllK8sResource(ctx, configInstance, operandName, configInstance.Namespace); err != nil { - return err - } - } - if uninstallOperator { - if r.checkUninstallLabel(sub) { - klog.V(1).Infof("Operator %s has label operator.ibm.com/opreq-do-not-uninstall. Skip the uninstall", op.Name) - return nil - } - - klog.V(3).Info("Set Deleting Condition in the operandRequest") - //TODO replace the resource types set in these setdeletingcondition functions - requestInstance.SetDeletingCondition(deploymentList[0].Name, operatorv1alpha1.ResourceTypeCsv, corev1.ConditionTrue, &r.Mutex) - - for _, deployment := range deploymentList { - klog.V(1).Infof("Deleting the deployment, Namespace: %s, Name: %s", deployment.Namespace, deployment.Name) - if err := r.Delete(ctx, deployment); err != nil { - requestInstance.SetDeletingCondition(deployment.Name, operatorv1alpha1.ResourceTypeCsv, corev1.ConditionFalse, &r.Mutex) - return errors.Wrapf(err, "failed to delete the deployment %s/%s", deployment.Namespace, deployment.Name) - } - } - } - } - - if uninstallOperator { - klog.V(2).Infof("Deleting the Subscription, Namespace: %s, Name: %s", namespace, op.Name) - requestInstance.SetDeletingCondition(op.Name, operatorv1alpha1.ResourceTypeSub, corev1.ConditionTrue, &r.Mutex) + requestInstance.SetMemberStatus(op.Name, operatorv1alpha1.OperatorUpdating, "", &r.Mutex) - if err := r.Delete(ctx, sub); err != nil { - if apierrors.IsNotFound(err) { - klog.Warningf("Subscription %s was not found in namespace %s", op.Name, namespace) - } else { - requestInstance.SetDeletingCondition(op.Name, operatorv1alpha1.ResourceTypeSub, corev1.ConditionFalse, &r.Mutex) - return errors.Wrap(err, "failed to delete subscription") - } + klog.V(1).Infof("No deletion, operator %s/%s and its operands are still requested by other OperandRequests", cm.Namespace, cm.Name) + return nil } - - klog.V(1).Infof("Subscription %s/%s is deleted", namespace, op.Name) - } else { - if err = r.updateSubscription(ctx, requestInstance, sub); err != nil { - requestInstance.SetMemberStatus(op.Name, operatorv1alpha1.OperatorFailed, "", &r.Mutex) + if deploymentList, err := r.GetDeploymentListFromPackage(ctx, op.PackageName, op.Namespace); err != nil { + // If can't get deployment, requeue the request return err + } else if deploymentList != nil { + klog.Infof("Found %d Deployment for package %s/%s", len(deploymentList), op.Name, namespace) + if uninstallOperand { + klog.V(1).Infof("Deleting all the Custom Resources for Deployment, Namespace: %s, Name: %s", deploymentList[0].Namespace, deploymentList[0].Name) + if err := r.deleteAllCustomResource(ctx, deploymentList[0], requestInstance, configInstance, operandName, configInstance.Namespace); err != nil { + return err + } + klog.V(1).Infof("Deleting all the k8s Resources for Deployment, Namespace: %s, Name: %s", deploymentList[0].Namespace, deploymentList[0].Name) + if err := r.deleteAllK8sResource(ctx, configInstance, operandName, configInstance.Namespace); err != nil { + return err + } + } + //TODO should odlm delete deployments or should that be handled by helm? + // if uninstallOperator { + // if r.checkUninstallLabel(cm) { + // klog.V(1).Infof("Operator %s has label operator.ibm.com/opreq-do-not-uninstall. Skip the uninstall", op.Name) + // return nil + // } + + // klog.V(3).Info("Set Deleting Condition in the operandRequest") + // //TODO replace the resource types set in these setdeletingcondition functions + // requestInstance.SetDeletingCondition(deploymentList[0].Name, operatorv1alpha1.ResourceTypeDeployment, corev1.ConditionTrue, &r.Mutex) + + // for _, deployment := range deploymentList { + // klog.V(1).Infof("Deleting the deployment, Namespace: %s, Name: %s", deployment.Namespace, deployment.Name) + // if err := r.Delete(ctx, deployment); err != nil { + // requestInstance.SetDeletingCondition(deployment.Name, operatorv1alpha1.ResourceTypeDeployment, corev1.ConditionFalse, &r.Mutex) + // return errors.Wrapf(err, "failed to delete the deployment %s/%s", deployment.Namespace, deployment.Name) + // } + // } + // } } - requestInstance.SetMemberStatus(op.Name, operatorv1alpha1.OperatorUpdating, "", &r.Mutex) - klog.V(1).Infof("Subscription %s/%s is not deleted due to the annotation from OperandRequest", namespace, op.Name) + } else if err != nil { + klog.Errorf("Failed to get Configmap called %s or using package name %s in the namespace %s and %s", operandName, op.PackageName, namespace, registryInstance.Namespace) + return err } return nil @@ -501,7 +399,7 @@ func (r *Reconciler) uninstallOperatorsAndOperands(ctx context.Context, operandN func (r *Reconciler) uninstallOperands(ctx context.Context, operandName string, requestInstance *operatorv1alpha1.OperandRequest, registryInstance *operatorv1alpha1.OperandRegistry, configInstance *operatorv1alpha1.OperandConfig) error { // No error handling for un-installation step in case Catalog has been deleted - op, _ := r.GetOperandFromRegistry(ctx, registryInstance, operandName) + op, _ := r.GetOperandFromRegistryNoOLM(ctx, registryInstance, operandName) if op == nil { klog.Warningf("Operand %s not found", operandName) return nil @@ -577,11 +475,14 @@ func (r *Reconciler) absentOperatorsAndOperands(ctx context.Context, requestInst wg.Add(1) go func() { defer wg.Done() - op, _ := r.GetOperandFromRegistry(ctx, registryInstance, fmt.Sprintf("%v", o)) + op, _ := r.GetOperandFromRegistryNoOLM(ctx, registryInstance, fmt.Sprintf("%v", o)) + // klog.V(1).Info("op to check in absentOperatorsandOperands: ", op.Name, " o: ", fmt.Sprintf("%v", o)) if op == nil { klog.Warningf("Operand %s not found", fmt.Sprintf("%v", o)) } if op != nil && !op.UserManaged { + //TODO do we need to uninstall operators and operands? Should the user uninstall operators with helm uninstall going forward? + //The below function currently does not delete operators if err := r.uninstallOperatorsAndOperands(ctx, fmt.Sprintf("%v", o), requestInstance, registryInstance, configInstance); err != nil { r.Mutex.Lock() defer r.Mutex.Unlock() @@ -599,6 +500,7 @@ func (r *Reconciler) absentOperatorsAndOperands(ctx context.Context, requestInst requestInstance.RemoveServiceStatus(fmt.Sprintf("%v", o), &r.Mutex) (*remainingOperands).Remove(o) remainingOp.Remove(o) + // klog.V(1).Info("op removed: ", op.Name, " o: ", fmt.Sprintf("%v", o)) }() } timeout := util.WaitTimeout(&wg, constant.DefaultSubDeleteTimeout) @@ -624,6 +526,7 @@ func (r *Reconciler) getNeedDeletedOperands(requestInstance *operatorv1alpha1.Op if requestInstance.DeletionTimestamp.IsZero() { for _, req := range requestInstance.Spec.Requests { for _, op := range req.Operands { + // klog.V(1).Info("Add current operand in getNeedDeletedOperands ", op.Name) currentOperands.Add(op.Name) } } @@ -637,7 +540,8 @@ func (r *Reconciler) generateClusterObjects(o *operatorv1alpha1.Operator, regist klog.V(3).Info("Generating Cluster Objects") co := &clusterObjects{} labels := map[string]string{ - constant.OpreqLabel: "true", + constant.OpreqLabel: "true", + "operator.ibm.com/watched-by-odlm": "true", } klog.V(3).Info("Generating Namespace: ", o.Namespace) @@ -653,11 +557,6 @@ func (r *Reconciler) generateClusterObjects(o *operatorv1alpha1.Operator, regist }, } - // Operator Group Object - klog.V(3).Info("Generating Operator Group in the Namespace: ", o.Namespace, " with target namespace: ", o.TargetNamespaces) - og := generateOperatorGroup(o.Namespace, o.TargetNamespaces) - co.operatorGroup = og - // The namespace is 'openshift-operators' when installMode is cluster namespace := r.GetOperatorNamespace(o.InstallMode, o.Namespace) @@ -666,62 +565,33 @@ func (r *Reconciler) generateClusterObjects(o *operatorv1alpha1.Operator, regist registryKey.Namespace + "." + registryKey.Name + "/config": "true", requestKey.Namespace + "." + requestKey.Name + "." + o.Name + "/request": o.Channel, requestKey.Namespace + "." + requestKey.Name + "." + o.Name + "/operatorNamespace": namespace, + "packageName": o.PackageName, } - // Subscription Object - sub := &olmv1alpha1.Subscription{ + //CM object + cm := &corev1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{ Name: o.PackageName, Namespace: namespace, Labels: labels, Annotations: annotations, }, - Spec: &olmv1alpha1.SubscriptionSpec{ - Channel: o.Channel, - Package: o.PackageName, - CatalogSource: o.SourceName, - CatalogSourceNamespace: o.SourceNamespace, - InstallPlanApproval: o.InstallPlanApproval, - StartingCSV: o.StartingCSV, - Config: o.SubscriptionConfig, - }, + Data: map[string]string{}, } - sub.SetGroupVersionKind(schema.GroupVersionKind{Group: olmv1alpha1.SchemeGroupVersion.Group, Kind: "Subscription", Version: olmv1alpha1.SchemeGroupVersion.Version}) - klog.V(3).Info("Generating Subscription: ", o.PackageName, " in the Namespace: ", namespace) - co.subscription = sub - return co -} -func generateOperatorGroup(namespace string, targetNamespaces []string) *olmv1.OperatorGroup { - labels := map[string]string{ - constant.OpreqLabel: "true", - } - if targetNamespaces == nil { - targetNamespaces = append(targetNamespaces, namespace) - } - // Operator Group Object - og := &olmv1.OperatorGroup{ - ObjectMeta: metav1.ObjectMeta{ - Name: "operand-deployment-lifecycle-manager-operatorgroup", - Namespace: namespace, - Labels: labels, - }, - Spec: olmv1.OperatorGroupSpec{ - TargetNamespaces: targetNamespaces, - }, - } - og.SetGroupVersionKind(schema.GroupVersionKind{Group: olmv1.SchemeGroupVersion.Group, Kind: "OperatorGroup", Version: olmv1.SchemeGroupVersion.Version}) - - return og + cm.SetGroupVersionKind(schema.GroupVersionKind{Group: corev1.SchemeGroupVersion.Group, Kind: "Configmap", Version: corev1.SchemeGroupVersion.Version}) + klog.V(2).Info("Generating tracking Configmap: ", o.PackageName, " in the Namespace: ", namespace) + co.configmap = cm + return co } -func (r *Reconciler) checkUninstallLabel(sub *olmv1alpha1.Subscription) bool { - subLabels := sub.GetLabels() - return subLabels[constant.NotUninstallLabel] == "true" +func (r *Reconciler) checkUninstallLabel(cm *corev1.ConfigMap) bool { + cmLabels := cm.GetLabels() + return cmLabels[constant.NotUninstallLabel] == "true" } -func compareSub(sub *olmv1alpha1.Subscription, originalSub *olmv1alpha1.Subscription) (needUpdate bool) { - return !equality.Semantic.DeepEqual(sub.Spec, originalSub.Spec) || !equality.Semantic.DeepEqual(sub.Annotations, originalSub.Annotations) +func compareOpReqCM(cm *corev1.ConfigMap, originalCM *corev1.ConfigMap) (needUpdate bool) { + return !equality.Semantic.DeepEqual(cm.Annotations, originalCM.Annotations) } func CheckSingletonServices(operator string) bool { @@ -729,26 +599,27 @@ func CheckSingletonServices(operator string) bool { return util.Contains(singletonServices, operator) } -// checkSubAnnotationsForUninstall checks the annotations of a Subscription object +// checkOpReqCMAnnotationsForUninstall checks the annotations of a tracking configmap object // to determine whether the operator and operand should be uninstalled. // It takes the name of the OperandRequest, the namespace of the OperandRequest, -// the name of the operator, and a pointer to the Subscription object as input. +// the name of the operator, and a pointer to the configmap object as input. // It returns two boolean values: uninstallOperator and uninstallOperand. // If uninstallOperator is true, it means the operator should be uninstalled. // If uninstallOperand is true, it means the operand should be uninstalled. -func checkSubAnnotationsForUninstall(reqName, reqNs, opName, installMode string, sub *olmv1alpha1.Subscription) (bool, bool) { +func checkOpReqCMAnnotationsForUninstall(reqName, reqNs, opName, installMode string, cm *corev1.ConfigMap) (bool, bool) { uninstallOperator := true uninstallOperand := true - delete(sub.Annotations, reqNs+"."+reqName+"."+opName+"/request") - delete(sub.Annotations, reqNs+"."+reqName+"."+opName+"/operatorNamespace") + klog.V(2).Info("Checking tracking configmap for uninstall for operand: ", opName) + delete(cm.Annotations, reqNs+"."+reqName+"."+opName+"/request") + delete(cm.Annotations, reqNs+"."+reqName+"."+opName+"/operatorNamespace") var opreqNsSlice []string var operatorNameSlice []string namespaceReg, _ := regexp.Compile(`^(.*)\.(.*)\.(.*)\/operatorNamespace`) channelReg, _ := regexp.Compile(`^(.*)\.(.*)\.(.*)\/request`) - for key, value := range sub.Annotations { + for key, value := range cm.Annotations { if namespaceReg.MatchString(key) { opreqNsSlice = append(opreqNsSlice, value) } @@ -763,11 +634,11 @@ func checkSubAnnotationsForUninstall(reqName, reqNs, opName, installMode string, // If one of remaining /operatorNamespace annotations' values is the same as subscription's namespace, // the operator should NOT be uninstalled. - if util.Contains(opreqNsSlice, sub.Namespace) { + if util.Contains(opreqNsSlice, cm.Namespace) { uninstallOperator = false } - if value, ok := sub.Labels[constant.OpreqLabel]; !ok || value != "true" { + if value, ok := cm.Labels[constant.OpreqLabel]; !ok || value != "true" { uninstallOperator = false } diff --git a/controllers/operator/manager.go b/controllers/operator/manager.go index cfbadb4d..8ab5e673 100644 --- a/controllers/operator/manager.go +++ b/controllers/operator/manager.go @@ -462,6 +462,82 @@ func (m *ODLMOperator) GetSubscription(ctx context.Context, name, operatorNs, se return &subCandidates[0], nil } +// GetDeployment gets Deployment by name and package name +func (m *ODLMOperator) GetDeployment(ctx context.Context, name, operatorNs, servicesNs, packageName string) (*appsv1.Deployment, error) { + klog.V(3).Infof("Fetch Deployment %s (package name: %s) in operatorNamespace %s and servicesNamespace %s", name, packageName, operatorNs, servicesNs) + + tenantScope := make(map[string]struct{}) + for _, ns := range []string{operatorNs, servicesNs} { + tenantScope[ns] = struct{}{} + } + + var depCandidates []appsv1.Deployment + for ns := range tenantScope { + depList := &appsv1.DeploymentList{} + if err := m.Client.List(ctx, depList, &client.ListOptions{ + Namespace: ns, + }); err != nil { + return nil, err + } + + for _, dep := range depList.Items { + if dep.Name == name || dep.Annotations["packageName"] == packageName { + depCandidates = append(depCandidates, dep) + } + } + } + + if len(depCandidates) == 0 { + return nil, nil + } + + if len(depCandidates) > 1 { + return nil, fmt.Errorf("there are multiple deployments using package %v", packageName) + } + + return &depCandidates[0], nil +} + +func (m *ODLMOperator) GetOpReqCM(ctx context.Context, name, operatorNs, servicesNs, packageName string) (*corev1.ConfigMap, error) { + klog.V(3).Infof("Fetch tracking configmap %s in operatorNamespace %s and servicesNamespace %s", name, operatorNs, servicesNs) + + tenantScope := make(map[string]struct{}) + for _, ns := range []string{operatorNs, servicesNs} { + tenantScope[ns] = struct{}{} + } + + var cmCandidates []corev1.ConfigMap + for ns := range tenantScope { + cmList := &corev1.ConfigMapList{} + if err := m.Client.List(ctx, cmList, &client.ListOptions{ + Namespace: ns, + }); err != nil { + return nil, err + } + + // for _, sub := range subList.Items { + // if sub.Name == name || sub.Spec.Package == packageName { + // subCandidates = append(subCandidates, sub) + // } + // } + for _, cm := range cmList.Items { + if cm.Name == packageName { + cmCandidates = append(cmCandidates, cm) + } + } + } + + if len(cmCandidates) == 0 { + return nil, nil + } + + if len(cmCandidates) > 1 { + return nil, fmt.Errorf("there are multiple subscriptions using package %v", packageName) + } + + return &cmCandidates[0], nil +} + // GetClusterServiceVersion gets the ClusterServiceVersion from the subscription func (m *ODLMOperator) GetClusterServiceVersion(ctx context.Context, sub *olmv1alpha1.Subscription) (*olmv1alpha1.ClusterServiceVersion, error) { // Check if subscription is nil @@ -699,6 +775,14 @@ func (m *ODLMOperator) GetOperandFromRegistry(ctx context.Context, reg *apiv1alp return opt, nil } +func (m *ODLMOperator) GetOperandFromRegistryNoOLM(ctx context.Context, reg *apiv1alpha1.OperandRegistry, operandName string) (*apiv1alpha1.Operator, error) { + opt := reg.GetOperator(operandName) + if opt == nil { + return nil, nil + } + return opt, nil +} + func (m *ODLMOperator) CheckLabel(unstruct unstructured.Unstructured, labels map[string]string) bool { for k, v := range labels { if !m.HasLabel(unstruct, k) { From 92ec5da1f8caa63c4492ae906bf9e771a27332c3 Mon Sep 17 00:00:00 2001 From: Allen Li <46284272+qpdpQ@users.noreply.github.com> Date: Tue, 4 Feb 2025 13:14:54 -0500 Subject: [PATCH 173/179] bump up odlm version for CD (#1111) Signed-off-by: Allen Li --- Makefile | 4 ++-- ...eployment-lifecycle-manager.clusterserviceversion.yaml | 8 ++++---- bundle/metadata/annotations.yaml | 4 ++-- ...eployment-lifecycle-manager.clusterserviceversion.yaml | 4 ++-- helm-cluster-scoped/Chart.yaml | 4 ++-- helm/Chart.yaml | 4 ++-- helm/templates/operator-deployment.yaml | 4 ++-- helm/templates/rbac.yaml | 8 ++++---- helm/values.yaml | 2 +- version/version.go | 2 +- 10 files changed, 22 insertions(+), 22 deletions(-) diff --git a/Makefile b/Makefile index 3e1f49b9..f747d204 100644 --- a/Makefile +++ b/Makefile @@ -84,7 +84,7 @@ OPERATOR_IMAGE_NAME ?= odlm # Current Operator bundle image name BUNDLE_IMAGE_NAME ?= odlm-operator-bundle # Current Operator version -OPERATOR_VERSION ?= 4.3.9 +OPERATOR_VERSION ?= 4.4.0 # Kind cluster name KIND_CLUSTER_NAME ?= "odlm" @@ -211,7 +211,7 @@ bundle-manifests: yq generate-all: yq manifests kustomize operator-sdk ## Generate bundle manifests, metadata and package manifests $(OPERATOR_SDK) generate kustomize manifests -q - - make bundle-manifests CHANNELS=v4.3 DEFAULT_CHANNEL=v4.3 + - make bundle-manifests CHANNELS=v4.4 DEFAULT_CHANNEL=v4.4 ##@ Test diff --git a/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml b/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml index 57506a00..8d45defa 100644 --- a/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml +++ b/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml @@ -132,7 +132,7 @@ metadata: createdAt: "2024-09-28T19:55:35Z" description: The Operand Deployment Lifecycle Manager provides a Kubernetes CRD-based API to manage the lifecycle of operands. nss.operator.ibm.com/managed-operators: ibm-odlm - olm.skipRange: '>=1.2.0 <4.3.9' + olm.skipRange: '>=1.2.0 <4.4.0' operators.openshift.io/infrastructure-features: '["disconnected"]' operators.operatorframework.io/builder: operator-sdk-v1.32.0 operators.operatorframework.io/project_layout: go.kubebuilder.io/v3 @@ -150,7 +150,7 @@ metadata: operatorframework.io/arch.ppc64le: supported operatorframework.io/arch.s390x: supported operatorframework.io/os.linux: supported - name: operand-deployment-lifecycle-manager.v4.3.9 + name: operand-deployment-lifecycle-manager.v4.4.0 namespace: placeholder spec: apiservicedefinitions: {} @@ -875,7 +875,7 @@ spec: minKubeVersion: 1.19.0 provider: name: IBM - version: 4.3.9 + version: 4.4.0 relatedImages: - - image: icr.io/cpopen/odlm:4.3.9 + - image: icr.io/cpopen/odlm:4.4.0 name: ODLM_IMAGE diff --git a/bundle/metadata/annotations.yaml b/bundle/metadata/annotations.yaml index e4758c86..10e9371e 100644 --- a/bundle/metadata/annotations.yaml +++ b/bundle/metadata/annotations.yaml @@ -4,8 +4,8 @@ annotations: operators.operatorframework.io.bundle.manifests.v1: manifests/ operators.operatorframework.io.bundle.metadata.v1: metadata/ operators.operatorframework.io.bundle.package.v1: ibm-odlm - operators.operatorframework.io.bundle.channels.v1: v4.3 - operators.operatorframework.io.bundle.channel.default.v1: v4.3 + operators.operatorframework.io.bundle.channels.v1: v4.4 + operators.operatorframework.io.bundle.channel.default.v1: v4.4 operators.operatorframework.io.metrics.builder: operator-sdk-v1.32.0 operators.operatorframework.io.metrics.mediatype.v1: metrics+v1 operators.operatorframework.io.metrics.project_layout: go.kubebuilder.io/v3 diff --git a/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml b/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml index fc966d91..bdcedb80 100644 --- a/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml +++ b/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml @@ -11,7 +11,7 @@ metadata: description: The Operand Deployment Lifecycle Manager provides a Kubernetes CRD-based API to manage the lifecycle of operands. nss.operator.ibm.com/managed-operators: ibm-odlm - olm.skipRange: '>=1.2.0 <4.3.9' + olm.skipRange: '>=1.2.0 <4.4.0' operators.openshift.io/infrastructure-features: '["disconnected"]' operators.operatorframework.io/builder: operator-sdk-v1.2.0 operators.operatorframework.io/project_layout: go.kubebuilder.io/v2 @@ -489,6 +489,6 @@ spec: provider: name: IBM relatedImages: - - image: icr.io/cpopen/odlm:4.3.9 + - image: icr.io/cpopen/odlm:4.4.0 name: ODLM_IMAGE version: 0.0.0 diff --git a/helm-cluster-scoped/Chart.yaml b/helm-cluster-scoped/Chart.yaml index 64e8b190..fe69038a 100644 --- a/helm-cluster-scoped/Chart.yaml +++ b/helm-cluster-scoped/Chart.yaml @@ -2,5 +2,5 @@ apiVersion: v2 name: ibm-odlm-cluster-scoped description: A Helm chart for ibm-odlm type: application -version: 4.3.9 -appVersion: 4.3.9 \ No newline at end of file +version: 4.4.0 +appVersion: 4.4.0 \ No newline at end of file diff --git a/helm/Chart.yaml b/helm/Chart.yaml index ceaf57ef..c80dcabf 100644 --- a/helm/Chart.yaml +++ b/helm/Chart.yaml @@ -2,5 +2,5 @@ apiVersion: v2 name: ibm-odlm description: A Helm chart for ibm-odlm type: application -version: 4.3.9 -appVersion: 4.3.9 \ No newline at end of file +version: 4.4.0 +appVersion: 4.4.0 \ No newline at end of file diff --git a/helm/templates/operator-deployment.yaml b/helm/templates/operator-deployment.yaml index e0c5846f..2c43f269 100644 --- a/helm/templates/operator-deployment.yaml +++ b/helm/templates/operator-deployment.yaml @@ -156,7 +156,7 @@ spec: # olm.operatorNamespace: cs-op # olm.skipRange: '>=1.2.0 <4.3.8' # olm.targetNamespaces: cs-op - operatorframework.io/properties: '{"properties":[{"type":"olm.gvk","value":{"group":"operator.ibm.com","kind":"OperandBindInfo","version":"v1alpha1"}},{"type":"olm.gvk","value":{"group":"operator.ibm.com","kind":"OperandConfig","version":"v1alpha1"}},{"type":"olm.gvk","value":{"group":"operator.ibm.com","kind":"OperandRegistry","version":"v1alpha1"}},{"type":"olm.gvk","value":{"group":"operator.ibm.com","kind":"OperandRequest","version":"v1alpha1"}},{"type":"olm.gvk","value":{"group":"operator.ibm.com","kind":"OperatorConfig","version":"v1alpha1"}},{"type":"olm.package","value":{"packageName":"ibm-odlm","version":"4.3.8"}}]}' + operatorframework.io/properties: '{"properties":[{"type":"olm.gvk","value":{"group":"operator.ibm.com","kind":"OperandBindInfo","version":"v1alpha1"}},{"type":"olm.gvk","value":{"group":"operator.ibm.com","kind":"OperandConfig","version":"v1alpha1"}},{"type":"olm.gvk","value":{"group":"operator.ibm.com","kind":"OperandRegistry","version":"v1alpha1"}},{"type":"olm.gvk","value":{"group":"operator.ibm.com","kind":"OperandRequest","version":"v1alpha1"}},{"type":"olm.gvk","value":{"group":"operator.ibm.com","kind":"OperatorConfig","version":"v1alpha1"}},{"type":"olm.package","value":{"packageName":"ibm-odlm","version":"4.4.0"}}]}' operators.openshift.io/infrastructure-features: '["disconnected"]' operators.operatorframework.io/builder: operator-sdk-v1.32.0 operators.operatorframework.io/project_layout: go.kubebuilder.io/v3 @@ -201,7 +201,7 @@ spec: name: namespace-scope optional: true - name: OPERATOR_CONDITION_NAME - value: operand-deployment-lifecycle-manager.v4.3.9 + value: operand-deployment-lifecycle-manager.v4.4.0 - name: NO_OLM value: "true" image: {{ .Values.imagePullPrefix}}/{{ .Values.imageRegistryNamespaceOperator}}/{{ .Values.operatorImage }}:{{ .Values.operatorVersion }} diff --git a/helm/templates/rbac.yaml b/helm/templates/rbac.yaml index d599bdf7..f3c7fae8 100644 --- a/helm/templates/rbac.yaml +++ b/helm/templates/rbac.yaml @@ -190,13 +190,13 @@ metadata: apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: - name: operand-deployment-lifecycle-manager.v4.3.9 + name: operand-deployment-lifecycle-manager.v4.4.0 namespace: {{ .Values.operatorNamespace }} rules: - apiGroups: - operators.coreos.com resourceNames: - - operand-deployment-lifecycle-manager.v4.3.9 + - operand-deployment-lifecycle-manager.v4.4.0 resources: - operatorconditions verbs: @@ -209,12 +209,12 @@ rules: apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: - name: operand-deployment-lifecycle-manager.v4.3.9 + name: operand-deployment-lifecycle-manager.v4.4.0 namespace: {{ .Values.operatorNamespace }} roleRef: apiGroup: rbac.authorization.k8s.io kind: Role - name: operand-deployment-lifecycle-manager.v4.3.9 + name: operand-deployment-lifecycle-manager.v4.4.0 subjects: - kind: ServiceAccount name: operand-deployment-lifecycle-manager diff --git a/helm/values.yaml b/helm/values.yaml index b9ef354d..c1237abd 100644 --- a/helm/values.yaml +++ b/helm/values.yaml @@ -4,7 +4,7 @@ imagePullSecret: ibm-entitlement-key # Note there are no leading or trailing /'s imageRegistryNamespaceOperator: cpopen imageRegistryNamespaceOperand: cpopen/cpfs -operatorVersion: 4.3.9 +operatorVersion: 4.4.0 # other configuration you think you might need for your operator # following are examples, not required: diff --git a/version/version.go b/version/version.go index 57140a6d..95f3117b 100644 --- a/version/version.go +++ b/version/version.go @@ -17,5 +17,5 @@ package version var ( - Version = "4.3.9" + Version = "4.4.0" ) From 872fdf8ac2a97587f86e1cf673390b320fd7bc06 Mon Sep 17 00:00:00 2001 From: Henry Li Date: Tue, 4 Feb 2025 15:23:33 -0500 Subject: [PATCH 174/179] updated chart to work with CICD automation (#1112) Signed-off-by: Henry Li --- helm-cluster-scoped/values.yaml | 5 ++--- helm/templates/operator-deployment.yaml | 2 +- helm/values.yaml | 6 ++---- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/helm-cluster-scoped/values.yaml b/helm-cluster-scoped/values.yaml index 5dbe421c..c612e1d1 100644 --- a/helm-cluster-scoped/values.yaml +++ b/helm-cluster-scoped/values.yaml @@ -7,6 +7,5 @@ imageRegistryNamespaceOperand: cpopen/cpfs # other configuration you think you might need for your operator # following are examples, not required: -operatorNamespace: ibm-common-services -servicesNamespace: service -operatorImage: odlm \ No newline at end of file +operatorNamespace: "" +servicesNamespace: "" diff --git a/helm/templates/operator-deployment.yaml b/helm/templates/operator-deployment.yaml index 2c43f269..2823cf6a 100644 --- a/helm/templates/operator-deployment.yaml +++ b/helm/templates/operator-deployment.yaml @@ -204,7 +204,7 @@ spec: value: operand-deployment-lifecycle-manager.v4.4.0 - name: NO_OLM value: "true" - image: {{ .Values.imagePullPrefix}}/{{ .Values.imageRegistryNamespaceOperator}}/{{ .Values.operatorImage }}:{{ .Values.operatorVersion }} + image: {{ .Values.imagePullPrefix}}/{{ .Values.imageRegistryNamespaceOperator}}/odlm:4.4.0 imagePullPolicy: IfNotPresent livenessProbe: failureThreshold: 10 diff --git a/helm/values.yaml b/helm/values.yaml index c1237abd..c612e1d1 100644 --- a/helm/values.yaml +++ b/helm/values.yaml @@ -4,10 +4,8 @@ imagePullSecret: ibm-entitlement-key # Note there are no leading or trailing /'s imageRegistryNamespaceOperator: cpopen imageRegistryNamespaceOperand: cpopen/cpfs -operatorVersion: 4.4.0 # other configuration you think you might need for your operator # following are examples, not required: -operatorNamespace: ibm-common-services -servicesNamespace: service -operatorImage: odlm \ No newline at end of file +operatorNamespace: "" +servicesNamespace: "" From f39a52b1c9297165deeaebe13aba8a387aca6886 Mon Sep 17 00:00:00 2001 From: Henry Li Date: Tue, 4 Feb 2025 17:27:52 -0500 Subject: [PATCH 175/179] updated chart to use global values to meet CPD spec (#1113) Signed-off-by: Henry Li --- helm-cluster-scoped/values.yaml | 8 ++++---- helm/templates/operator-deployment.yaml | 6 +++--- helm/templates/rbac.yaml | 12 ++++++------ helm/values.yaml | 8 ++++---- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/helm-cluster-scoped/values.yaml b/helm-cluster-scoped/values.yaml index c612e1d1..199e6e03 100644 --- a/helm-cluster-scoped/values.yaml +++ b/helm-cluster-scoped/values.yaml @@ -1,5 +1,5 @@ -imagePullPrefix: icr.io -imagePullSecret: ibm-entitlement-key +# imagePullPrefix: icr.io +# imagePullSecret: ibm-entitlement-key # Note there are no leading or trailing /'s imageRegistryNamespaceOperator: cpopen @@ -7,5 +7,5 @@ imageRegistryNamespaceOperand: cpopen/cpfs # other configuration you think you might need for your operator # following are examples, not required: -operatorNamespace: "" -servicesNamespace: "" +# operatorNamespace: "" +# servicesNamespace: "" diff --git a/helm/templates/operator-deployment.yaml b/helm/templates/operator-deployment.yaml index 2823cf6a..3c70f13e 100644 --- a/helm/templates/operator-deployment.yaml +++ b/helm/templates/operator-deployment.yaml @@ -5,7 +5,7 @@ metadata: app.kubernetes.io/managed-by: Helm productName: IBM_Cloud_Platform_Common_Services name: operand-deployment-lifecycle-manager - namespace: {{ .Values.operatorNamespace }} + namespace: {{ .Values.global.operatorNamespace }} spec: progressDeadlineSeconds: 600 replicas: 1 @@ -204,7 +204,7 @@ spec: value: operand-deployment-lifecycle-manager.v4.4.0 - name: NO_OLM value: "true" - image: {{ .Values.imagePullPrefix}}/{{ .Values.imageRegistryNamespaceOperator}}/odlm:4.4.0 + image: {{ .Values.global.imagePullPrefix }}/{{ .Values.imageRegistryNamespaceOperator }}/odlm:4.4.0 imagePullPolicy: IfNotPresent livenessProbe: failureThreshold: 10 @@ -248,7 +248,7 @@ spec: terminationMessagePath: /dev/termination-log terminationMessagePolicy: File imagePullSecrets: - - name: {{ .Values.imagePullSecret }} + - name: {{ .Values.global.imagePullSecret }} dnsPolicy: ClusterFirst restartPolicy: Always schedulerName: default-scheduler diff --git a/helm/templates/rbac.yaml b/helm/templates/rbac.yaml index f3c7fae8..0cbf5988 100644 --- a/helm/templates/rbac.yaml +++ b/helm/templates/rbac.yaml @@ -2,7 +2,7 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: name: operand-deployment-lifecycle-manager - namespace: {{ .Values.operatorNamespace }} + namespace: {{ .Values.global.operatorNamespace }} rules: - apiGroups: - "" @@ -176,14 +176,14 @@ roleRef: subjects: - kind: ServiceAccount name: operand-deployment-lifecycle-manager - namespace: {{ .Values.operatorNamespace }} + namespace: {{ .Values.global.operatorNamespace }} --- apiVersion: v1 kind: ServiceAccount metadata: name: operand-deployment-lifecycle-manager - namespace: {{ .Values.operatorNamespace }} + namespace: {{ .Values.global.operatorNamespace }} --- ### role only for olm @@ -191,7 +191,7 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: name: operand-deployment-lifecycle-manager.v4.4.0 - namespace: {{ .Values.operatorNamespace }} + namespace: {{ .Values.global.operatorNamespace }} rules: - apiGroups: - operators.coreos.com @@ -210,7 +210,7 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: operand-deployment-lifecycle-manager.v4.4.0 - namespace: {{ .Values.operatorNamespace }} + namespace: {{ .Values.global.operatorNamespace }} roleRef: apiGroup: rbac.authorization.k8s.io kind: Role @@ -218,4 +218,4 @@ roleRef: subjects: - kind: ServiceAccount name: operand-deployment-lifecycle-manager - namespace: {{ .Values.operatorNamespace }} + namespace: {{ .Values.global.operatorNamespace }} diff --git a/helm/values.yaml b/helm/values.yaml index c612e1d1..199e6e03 100644 --- a/helm/values.yaml +++ b/helm/values.yaml @@ -1,5 +1,5 @@ -imagePullPrefix: icr.io -imagePullSecret: ibm-entitlement-key +# imagePullPrefix: icr.io +# imagePullSecret: ibm-entitlement-key # Note there are no leading or trailing /'s imageRegistryNamespaceOperator: cpopen @@ -7,5 +7,5 @@ imageRegistryNamespaceOperand: cpopen/cpfs # other configuration you think you might need for your operator # following are examples, not required: -operatorNamespace: "" -servicesNamespace: "" +# operatorNamespace: "" +# servicesNamespace: "" From cfc57ced9cc60899ffd70460b68c4253290d68c3 Mon Sep 17 00:00:00 2001 From: Travis CI User Date: Thu, 6 Feb 2025 14:14:12 +0000 Subject: [PATCH 176/179] Trigger build with new base image --- base_images.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/base_images.json b/base_images.json index a4b990e3..ec22d1ca 100644 --- a/base_images.json +++ b/base_images.json @@ -7,7 +7,7 @@ "destStage": "edge", "destNamespace": "build-images", "destImage": "ubi9-minimal", - "tag": "9.5-1736404155", + "tag": "9.5-1738643652", "updatePackages": [] }, { @@ -18,7 +18,7 @@ "destStage": "edge", "destNamespace": "build-images", "destImage": "ubi9", - "tag": "9.5-1736404036", + "tag": "9.5-1738643550", "updatePackages": [] }, { @@ -29,20 +29,20 @@ "destStage": "edge", "destNamespace": "build-images", "destImage": "ubi9-micro", - "tag": "9.5-1736426761", + "tag": "9.5-1738659858", "updatePackages": [] }, { "imageType": "node", "sourceImage": "ubi9-minimal", - "sourceTag": "9.5-1736404155", + "sourceTag": "9.5-1738643652", "destImage": "node-v20-ubi9-minimal", "nodeVersion": "20.18.2" }, { "imageType": "node", "sourceImage": "ubi9-minimal", - "sourceTag": "9.5-1736404155", + "sourceTag": "9.5-1738643652", "destImage": "node-v22-ubi9-minimal", "nodeVersion": "22.13.1" } From 82479bbf90ec528abd9d87833e2638030952eb5d Mon Sep 17 00:00:00 2001 From: Ben Luzarraga <31223504+bluzarraga@users.noreply.github.com> Date: Thu, 6 Feb 2025 14:53:02 -0600 Subject: [PATCH 177/179] specify operator namespace in rolebinding (#1117) --- helm/templates/rbac.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/helm/templates/rbac.yaml b/helm/templates/rbac.yaml index 0cbf5988..90a7a1f9 100644 --- a/helm/templates/rbac.yaml +++ b/helm/templates/rbac.yaml @@ -169,6 +169,7 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: operand-deployment-lifecycle-manager + namespace: {{ .Values.global.operatorNamespace }} roleRef: apiGroup: rbac.authorization.k8s.io kind: Role From c50ee8d32dcd742ed6cecbdefdc8828a74562e6c Mon Sep 17 00:00:00 2001 From: Jeremy Cheng <81793294+Jeremy-Cheng-stack@users.noreply.github.com> Date: Thu, 6 Feb 2025 15:54:01 -0500 Subject: [PATCH 178/179] Update OWNERS (#1116) --- OWNERS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/OWNERS b/OWNERS index dc89fb09..0a254210 100644 --- a/OWNERS +++ b/OWNERS @@ -4,9 +4,11 @@ approvers: - qpdpQ - bluzarraga - YCShen1010 +- Jeremy-Cheng-stack reviewers: - bitscuit - Daniel-Fan - qpdpQ - bluzarraga - YCShen1010 +- Jeremy-Cheng-stack From e3f0628ab8f5c800722c8ef853845f5915d67585 Mon Sep 17 00:00:00 2001 From: YuChen Shen <59578388+YCShen1010@users.noreply.github.com> Date: Wed, 12 Feb 2025 15:39:38 -0500 Subject: [PATCH 179/179] Enhance cleanup of OperandRequest for non-OLM case (#1114) * delete OperandRequest ConfigMap when uninstall operator condition true Signed-off-by: YuChen * fix lint error Signed-off-by: YuChen * removing get deployment function Signed-off-by: YuChen * add prefix and tracker label for opreq configmap Signed-off-by: YuChen * clean up debugging log Signed-off-by: YuChen * clean up function not in use Signed-off-by: YuChen --------- Signed-off-by: YuChen --- controllers/constant/constant.go | 5 +- .../operandrequestnoolm_controller.go | 26 +--- .../operandrequestnoolm/reconcile_operand.go | 1 - .../operandrequestnoolm/reconcile_operator.go | 128 ++++++++---------- controllers/operator/manager.go | 65 ++------- 5 files changed, 70 insertions(+), 155 deletions(-) diff --git a/controllers/constant/constant.go b/controllers/constant/constant.go index 49fe0044..3015495b 100644 --- a/controllers/constant/constant.go +++ b/controllers/constant/constant.go @@ -28,9 +28,12 @@ const ( //NotUninstallLabel is the label used to prevent subscription/CR from uninstall NotUninstallLabel string = "operator.ibm.com/opreq-do-not-uninstall" - //OpreqLabel is the label used to label the subscription/CR managed by ODLM + //OpreqLabel is the label used to label the Subscription/CR/Configmap managed by ODLM OpreqLabel string = "operator.ibm.com/opreq-control" + //OpreqTrackerLabel is the label used to label the OperandRequest Configmap managed by ODLM + OpreqTrackerLabel string = "operator.ibm.com/operand-request-tracker" + //InternalOpreqLabel is the label used label the OperandRequest internally created by ODLM OperandOnlyLabel string = "operator.ibm.com/operand-only" diff --git a/controllers/operandrequestnoolm/operandrequestnoolm_controller.go b/controllers/operandrequestnoolm/operandrequestnoolm_controller.go index 99a9c294..377cc10d 100644 --- a/controllers/operandrequestnoolm/operandrequestnoolm_controller.go +++ b/controllers/operandrequestnoolm/operandrequestnoolm_controller.go @@ -20,7 +20,6 @@ import ( "context" "fmt" "reflect" - "regexp" "strings" "sync" "time" @@ -109,6 +108,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctrl.Re } }() + // Get start to delete the OperandRequest // Remove finalizer when DeletionTimestamp none zero if !requestInstance.ObjectMeta.DeletionTimestamp.IsZero() { //Checkfinalizers calls the delete function, not necessarily subscription based @@ -268,30 +268,6 @@ func (r *Reconciler) getRegistryToRequestMapper() handler.MapFunc { } } -func (r *Reconciler) getSubToRequestMapper() handler.MapFunc { - return func(object client.Object) []ctrl.Request { - reg, _ := regexp.Compile(`^(.*)\.(.*)\.(.*)\/request`) - annotations := object.GetAnnotations() - var reqName, reqNamespace string - for annotation := range annotations { - if reg.MatchString(annotation) { - annotationSlices := strings.Split(annotation, ".") - reqNamespace = annotationSlices[0] - reqName = annotationSlices[1] - } - } - if reqNamespace == "" || reqName == "" { - return []ctrl.Request{} - } - return []ctrl.Request{ - {NamespacedName: types.NamespacedName{ - Name: reqName, - Namespace: reqNamespace, - }}, - } - } -} - func (r *Reconciler) getConfigToRequestMapper() handler.MapFunc { ctx := context.Background() return func(object client.Object) []ctrl.Request { diff --git a/controllers/operandrequestnoolm/reconcile_operand.go b/controllers/operandrequestnoolm/reconcile_operand.go index 3ac4cdf2..65844b01 100644 --- a/controllers/operandrequestnoolm/reconcile_operand.go +++ b/controllers/operandrequestnoolm/reconcile_operand.go @@ -843,7 +843,6 @@ func (r *Reconciler) deleteCustomResource(ctx context.Context, existingCR unstru klog.V(3).Infof("There is no custom resource: %s from custom resource definition: %s", name, kind) } else { if r.CheckLabel(crShouldBeDeleted, map[string]string{constant.OpreqLabel: "true"}) && !r.CheckLabel(crShouldBeDeleted, map[string]string{constant.NotUninstallLabel: "true"}) { - klog.V(3).Infof("Deleting custom resource: %s from custom resource definition: %s", name, kind) err := r.Delete(ctx, &crShouldBeDeleted) if err != nil && !apierrors.IsNotFound(err) { return errors.Wrapf(err, "failed to delete custom resource -- Kind: %s, NamespacedName: %s/%s", kind, namespace, name) diff --git a/controllers/operandrequestnoolm/reconcile_operator.go b/controllers/operandrequestnoolm/reconcile_operator.go index 6bd6d296..47f2bd5a 100644 --- a/controllers/operandrequestnoolm/reconcile_operator.go +++ b/controllers/operandrequestnoolm/reconcile_operator.go @@ -155,7 +155,7 @@ func (r *Reconciler) reconcileOpReqCM(ctx context.Context, requestInstance *oper // Check configmap if exist namespace := r.GetOperatorNamespace(opt.InstallMode, opt.Namespace) - cm, err := r.GetOpReqCM(ctx, opt.Name, namespace, registryInstance.Namespace, opt.PackageName) + cm, err := r.GetOpReqCM(ctx, opt.PackageName, namespace, registryInstance.Namespace) if cm == nil && err == nil { if opt.InstallMode == operatorv1alpha1.InstallModeNoop { @@ -212,7 +212,6 @@ func (r *Reconciler) reconcileOpReqCM(ctx context.Context, requestInstance *oper cm.Annotations[requestInstance.Namespace+"."+requestInstance.Name+"."+operand.Name+"/request"] = opt.Channel cm.Annotations[requestInstance.Namespace+"."+requestInstance.Name+"."+operand.Name+"/operatorNamespace"] = namespace cm.Annotations["packageName"] = opt.PackageName - cm.Labels["operator.ibm.com/watched-by-odlm"] = "true" if opt.InstallMode == operatorv1alpha1.InstallModeNoop { requestInstance.SetNoSuitableRegistryCondition(registryKey.String(), opt.Name+" is in maintenance status", operatorv1alpha1.ResourceTypeOperandRegistry, corev1.ConditionTrue, &r.Mutex) @@ -259,7 +258,7 @@ func (r *Reconciler) createOpReqCM(ctx context.Context, cr *operatorv1alpha1.Ope } } - // Create CM + // Create OperandRequest CM klog.V(2).Info("Creating the Configmap: " + opt.Name) cm := co.configmap @@ -307,7 +306,6 @@ func (r *Reconciler) updateOpReqCM(ctx context.Context, cr *operatorv1alpha1.Ope func (r *Reconciler) uninstallOperatorsAndOperands(ctx context.Context, operandName string, requestInstance *operatorv1alpha1.OperandRequest, registryInstance *operatorv1alpha1.OperandRegistry, configInstance *operatorv1alpha1.OperandConfig) error { // No error handling for un-installation step in case Catalog has been deleted op, _ := r.GetOperandFromRegistryNoOLM(ctx, registryInstance, operandName) - // klog.V(1).Info("op to check in uninstallOperatorsAndOperands: ", op.Name, " o: ", fmt.Sprintf("%v", operandName)) if op == nil { klog.Warningf("Operand %s not found", operandName) return nil @@ -316,84 +314,66 @@ func (r *Reconciler) uninstallOperatorsAndOperands(ctx context.Context, operandN namespace := r.GetOperatorNamespace(op.InstallMode, op.Namespace) //Assuing we can still use op as a parameter, we should be able to get the deployment with ease - deploy, err := r.GetDeployment(ctx, operandName, namespace, registryInstance.Namespace, op.PackageName) - // klog.V(1).Info("deployment in uninstallOperatorsAndOperands: ", deploy.Name) - if deploy == nil && err == nil { - klog.V(3).Infof("There is no Deployment called %s or using package name %s in the namespace %s and %s", operandName, op.PackageName, namespace, registryInstance.Namespace) - return nil - } else if err != nil { - klog.Errorf("Failed to get Deployment called %s or using package name %s in the namespace %s and %s", operandName, op.PackageName, namespace, registryInstance.Namespace) + if deploymentList, err := r.GetDeploymentListFromPackage(ctx, op.PackageName, op.Namespace); err != nil { + // If can't get deployment, requeue the request return err - } + } else if deploymentList != nil { - if deploy.Labels == nil { - // Subscription existing and not managed by OperandRequest controller - klog.V(2).Infof("Deployment %s in the namespace %s isn't created by ODLM", deploy.Name, deploy.Namespace) - return nil - } + if deploymentList[0].Labels == nil { + // Deployment existing and not managed by OperandRequest controller + klog.V(2).Infof("Deployment %s in the namespace %s isn't created by ODLM", deploymentList[0].Name, deploymentList[0].Namespace) + return nil + } - // if _, ok := deploy.Labels[constant.OpreqLabel]; !ok { - // if !op.UserManaged { - // klog.V(2).Infof("Deployment %s in the namespace %s isn't created by ODLM and isn't user managed", deploy.Name, deploy.Namespace) - // return nil - // } - // } - - cm, err := r.GetOpReqCM(ctx, op.Name, deploy.Namespace, registryInstance.Namespace, op.PackageName) - // klog.V(1).Info("Configmap tracking operand: ", cm.Name) - if cm != nil && err == nil { - uninstallOperator, uninstallOperand := checkOpReqCMAnnotationsForUninstall(requestInstance.ObjectMeta.Name, requestInstance.ObjectMeta.Namespace, op.Name, op.InstallMode, cm) - // klog.V(1).Info("uinstall operator: ", uninstallOperator, " uninstall operand: ", uninstallOperand) - if !uninstallOperand && !uninstallOperator { + cm, err := r.GetOpReqCM(ctx, op.PackageName, deploymentList[0].Namespace, registryInstance.Namespace) + if cm != nil && err == nil { + uninstallOperator, uninstallOperand := checkOpReqCMAnnotationsForUninstall(requestInstance.ObjectMeta.Name, requestInstance.ObjectMeta.Namespace, op.Name, op.InstallMode, cm) + // Updated the Configmap for the OperandRequest if err = r.updateOpReqCM(ctx, requestInstance, cm); err != nil { requestInstance.SetMemberStatus(op.Name, operatorv1alpha1.OperatorFailed, "", &r.Mutex) return err } - requestInstance.SetMemberStatus(op.Name, operatorv1alpha1.OperatorUpdating, "", &r.Mutex) + if !uninstallOperand && !uninstallOperator { + requestInstance.SetMemberStatus(op.Name, operatorv1alpha1.OperatorUpdating, "", &r.Mutex) - klog.V(1).Infof("No deletion, operator %s/%s and its operands are still requested by other OperandRequests", cm.Namespace, cm.Name) - return nil - } - if deploymentList, err := r.GetDeploymentListFromPackage(ctx, op.PackageName, op.Namespace); err != nil { - // If can't get deployment, requeue the request - return err - } else if deploymentList != nil { - klog.Infof("Found %d Deployment for package %s/%s", len(deploymentList), op.Name, namespace) - if uninstallOperand { - klog.V(1).Infof("Deleting all the Custom Resources for Deployment, Namespace: %s, Name: %s", deploymentList[0].Namespace, deploymentList[0].Name) - if err := r.deleteAllCustomResource(ctx, deploymentList[0], requestInstance, configInstance, operandName, configInstance.Namespace); err != nil { - return err + klog.V(1).Infof("No deletion, operator %s/%s and its operands are still requested by other OperandRequests", cm.Namespace, cm.Name) + return nil + } + if deploymentList, err := r.GetDeploymentListFromPackage(ctx, op.PackageName, op.Namespace); err != nil { + // If can't get deployment, requeue the request + return err + } else if deploymentList != nil { + klog.Infof("Found %d Deployment for package %s/%s", len(deploymentList), op.Name, namespace) + if uninstallOperand { + + klog.V(1).Infof("Deleting all the Custom Resources for Deployment, Namespace: %s, Name: %s", deploymentList[0].Namespace, deploymentList[0].Name) + if err := r.deleteAllCustomResource(ctx, deploymentList[0], requestInstance, configInstance, operandName, configInstance.Namespace); err != nil { + return err + } + klog.V(1).Infof("Deleting all the k8s Resources for Deployment, Namespace: %s, Name: %s", deploymentList[0].Namespace, deploymentList[0].Name) + if err := r.deleteAllK8sResource(ctx, configInstance, operandName, configInstance.Namespace); err != nil { + return err + } } - klog.V(1).Infof("Deleting all the k8s Resources for Deployment, Namespace: %s, Name: %s", deploymentList[0].Namespace, deploymentList[0].Name) - if err := r.deleteAllK8sResource(ctx, configInstance, operandName, configInstance.Namespace); err != nil { - return err + // TODO should odlm delete deployments or should that be handled by helm? + // Keep this part for OperandRequest Configmap deletion + if uninstallOperator { + if r.checkUninstallLabel(cm) { + klog.V(1).Infof("Operator %s has label operator.ibm.com/opreq-do-not-uninstall. Skip the uninstall", op.Name) + return nil + } + + // Delete the OperandRequest Configmap + if err := r.deleteOpReqCM(ctx, requestInstance, cm); err != nil { + return err + } } } - //TODO should odlm delete deployments or should that be handled by helm? - // if uninstallOperator { - // if r.checkUninstallLabel(cm) { - // klog.V(1).Infof("Operator %s has label operator.ibm.com/opreq-do-not-uninstall. Skip the uninstall", op.Name) - // return nil - // } - - // klog.V(3).Info("Set Deleting Condition in the operandRequest") - // //TODO replace the resource types set in these setdeletingcondition functions - // requestInstance.SetDeletingCondition(deploymentList[0].Name, operatorv1alpha1.ResourceTypeDeployment, corev1.ConditionTrue, &r.Mutex) - - // for _, deployment := range deploymentList { - // klog.V(1).Infof("Deleting the deployment, Namespace: %s, Name: %s", deployment.Namespace, deployment.Name) - // if err := r.Delete(ctx, deployment); err != nil { - // requestInstance.SetDeletingCondition(deployment.Name, operatorv1alpha1.ResourceTypeDeployment, corev1.ConditionFalse, &r.Mutex) - // return errors.Wrapf(err, "failed to delete the deployment %s/%s", deployment.Namespace, deployment.Name) - // } - // } - // } + } else if err != nil { + klog.Errorf("Failed to get Configmap called %s or using package name %s in the namespace %s and %s", operandName, op.PackageName, namespace, registryInstance.Namespace) + return err } - } else if err != nil { - klog.Errorf("Failed to get Configmap called %s or using package name %s in the namespace %s and %s", operandName, op.PackageName, namespace, registryInstance.Namespace) - return err } - return nil } @@ -476,7 +456,6 @@ func (r *Reconciler) absentOperatorsAndOperands(ctx context.Context, requestInst go func() { defer wg.Done() op, _ := r.GetOperandFromRegistryNoOLM(ctx, registryInstance, fmt.Sprintf("%v", o)) - // klog.V(1).Info("op to check in absentOperatorsandOperands: ", op.Name, " o: ", fmt.Sprintf("%v", o)) if op == nil { klog.Warningf("Operand %s not found", fmt.Sprintf("%v", o)) } @@ -540,8 +519,9 @@ func (r *Reconciler) generateClusterObjects(o *operatorv1alpha1.Operator, regist klog.V(3).Info("Generating Cluster Objects") co := &clusterObjects{} labels := map[string]string{ - constant.OpreqLabel: "true", - "operator.ibm.com/watched-by-odlm": "true", + constant.OpreqLabel: "true", + constant.ODLMWatchedLabel: "true", + constant.OpreqTrackerLabel: "true", } klog.V(3).Info("Generating Namespace: ", o.Namespace) @@ -571,7 +551,7 @@ func (r *Reconciler) generateClusterObjects(o *operatorv1alpha1.Operator, regist //CM object cm := &corev1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{ - Name: o.PackageName, + Name: "opreq-" + o.PackageName, Namespace: namespace, Labels: labels, Annotations: annotations, @@ -610,7 +590,6 @@ func checkOpReqCMAnnotationsForUninstall(reqName, reqNs, opName, installMode str uninstallOperator := true uninstallOperand := true - klog.V(2).Info("Checking tracking configmap for uninstall for operand: ", opName) delete(cm.Annotations, reqNs+"."+reqName+"."+opName+"/request") delete(cm.Annotations, reqNs+"."+reqName+"."+opName+"/operatorNamespace") @@ -649,6 +628,5 @@ func checkOpReqCMAnnotationsForUninstall(reqName, reqNs, opName, installMode str if (!uninstallOperator && installMode == operatorv1alpha1.InstallModeNoop) || (uninstallOperator && len(opreqNsSlice) != 0) || util.Contains(operatorNameSlice, opName) { uninstallOperand = false } - return uninstallOperator, uninstallOperand } diff --git a/controllers/operator/manager.go b/controllers/operator/manager.go index 8ab5e673..d759f95e 100644 --- a/controllers/operator/manager.go +++ b/controllers/operator/manager.go @@ -462,67 +462,26 @@ func (m *ODLMOperator) GetSubscription(ctx context.Context, name, operatorNs, se return &subCandidates[0], nil } -// GetDeployment gets Deployment by name and package name -func (m *ODLMOperator) GetDeployment(ctx context.Context, name, operatorNs, servicesNs, packageName string) (*appsv1.Deployment, error) { - klog.V(3).Infof("Fetch Deployment %s (package name: %s) in operatorNamespace %s and servicesNamespace %s", name, packageName, operatorNs, servicesNs) +func (m *ODLMOperator) GetOpReqCM(ctx context.Context, operatorName, operatorNs, servicesNs string) (*corev1.ConfigMap, error) { + klog.V(3).Infof("Fetch tracking configmap %s in operatorNamespace %s and servicesNamespace %s", operatorName, operatorNs, servicesNs) - tenantScope := make(map[string]struct{}) - for _, ns := range []string{operatorNs, servicesNs} { - tenantScope[ns] = struct{}{} - } - - var depCandidates []appsv1.Deployment - for ns := range tenantScope { - depList := &appsv1.DeploymentList{} - if err := m.Client.List(ctx, depList, &client.ListOptions{ - Namespace: ns, - }); err != nil { - return nil, err - } - - for _, dep := range depList.Items { - if dep.Name == name || dep.Annotations["packageName"] == packageName { - depCandidates = append(depCandidates, dep) - } - } - } - - if len(depCandidates) == 0 { - return nil, nil - } - - if len(depCandidates) > 1 { - return nil, fmt.Errorf("there are multiple deployments using package %v", packageName) - } - - return &depCandidates[0], nil -} - -func (m *ODLMOperator) GetOpReqCM(ctx context.Context, name, operatorNs, servicesNs, packageName string) (*corev1.ConfigMap, error) { - klog.V(3).Infof("Fetch tracking configmap %s in operatorNamespace %s and servicesNamespace %s", name, operatorNs, servicesNs) - - tenantScope := make(map[string]struct{}) - for _, ns := range []string{operatorNs, servicesNs} { - tenantScope[ns] = struct{}{} + tenantScope := []string{operatorNs} + if operatorNs != servicesNs { + tenantScope = append(tenantScope, servicesNs) } var cmCandidates []corev1.ConfigMap - for ns := range tenantScope { + for _, ns := range tenantScope { cmList := &corev1.ConfigMapList{} - if err := m.Client.List(ctx, cmList, &client.ListOptions{ - Namespace: ns, - }); err != nil { + if err := m.Client.List(ctx, cmList, &client.ListOptions{Namespace: ns}); err != nil { return nil, err } - // for _, sub := range subList.Items { - // if sub.Name == name || sub.Spec.Package == packageName { - // subCandidates = append(subCandidates, sub) - // } - // } for _, cm := range cmList.Items { - if cm.Name == packageName { - cmCandidates = append(cmCandidates, cm) + if cm.Annotations != nil { + if pkg, exists := cm.Annotations["packageName"]; exists && pkg == operatorName { + cmCandidates = append(cmCandidates, cm) + } } } } @@ -532,7 +491,7 @@ func (m *ODLMOperator) GetOpReqCM(ctx context.Context, name, operatorNs, service } if len(cmCandidates) > 1 { - return nil, fmt.Errorf("there are multiple subscriptions using package %v", packageName) + return nil, fmt.Errorf("there are multiple Configmaps using package %v", operatorName) } return &cmCandidates[0], nil