diff --git a/Makefile b/Makefile index 19e7b0b4..52fbc5fe 100755 --- a/Makefile +++ b/Makefile @@ -53,7 +53,7 @@ IMAGE_SHA = $(lastword $(subst @, ,$(IMAGE_REPO_DIGEST))) REGISTRY_IMAGE_SHA = $(lastword $(subst @, ,$(REGISTRY_IMAGE_REPO_DIGEST))) # Current release (used for CSV management) -CURRENT_RELEASE=0.9.0 +CURRENT_RELEASE=0.10.0 # OS detection ifeq ($(OS),Windows_NT) @@ -66,11 +66,10 @@ endif endif -.PHONY: build deploy deploy-olm build-image build-registry-image push-image push-registry-image push-manifest int-test-install int-test-collections int-test-uninstall int-test-lifecycle +.PHONY: build deploy deploy-olm build-image build-registry-image push-image push-registry-image push-manifest int-test-install int-test-stacks int-test-uninstall int-test-lifecycle build: generate GO111MODULE=on go install ./cmd/manager - GO111MODULE=on go install ./cmd/manager/collection GO111MODULE=on go install ./cmd/manager/stack GO111MODULE=on go install ./cmd/admission-webhook GO111MODULE=on go install ./cmd/serving @@ -81,7 +80,6 @@ build-image: generate # commands separately here. # operator-sdk build ${IMAGE} GO111MODULE=on CGO_ENABLED=0 GOOS=linux GOARCH=$(ARCH) go build -o build/_output/bin/kabanero-operator -gcflags "all=-trimpath=$(GOPATH)" -asmflags "all=-trimpath=$(GOPATH)" -ldflags "-X main.GitTag=$(TRAVIS_TAG) -X main.GitCommit=$(TRAVIS_COMMIT) -X main.GitRepoSlug=$(TRAVIS_REPO_SLUG) -X main.BuildDate=`date -u +%Y%m%d.%H%M%S`" github.com/kabanero-io/kabanero-operator/cmd/manager - GO111MODULE=on CGO_ENABLED=0 GOOS=linux GOARCH=$(ARCH) go build -o build/_output/bin/kabanero-operator-collection-controller -gcflags "all=-trimpath=$(GOPATH)" -asmflags "all=-trimpath=$(GOPATH)" -ldflags "-X main.GitTag=$(TRAVIS_TAG) -X main.GitCommit=$(TRAVIS_COMMIT) -X main.GitRepoSlug=$(TRAVIS_REPO_SLUG) -X main.BuildDate=`date -u +%Y%m%d.%H%M%S`" github.com/kabanero-io/kabanero-operator/cmd/manager/collection GO111MODULE=on CGO_ENABLED=0 GOOS=linux GOARCH=$(ARCH) go build -o build/_output/bin/kabanero-operator-stack-controller -gcflags "all=-trimpath=$(GOPATH)" -asmflags "all=-trimpath=$(GOPATH)" -ldflags "-X main.GitTag=$(TRAVIS_TAG) -X main.GitCommit=$(TRAVIS_COMMIT) -X main.GitRepoSlug=$(TRAVIS_REPO_SLUG) -X main.BuildDate=`date -u +%Y%m%d.%H%M%S`" github.com/kabanero-io/kabanero-operator/cmd/manager/stack GO111MODULE=on CGO_ENABLED=0 GOOS=linux GOARCH=$(ARCH) go build -o build/_output/bin/admission-webhook -gcflags "all=-trimpath=$(GOPATH)" -asmflags "all=-trimpath=$(GOPATH)" -ldflags "-X main.GitTag=$(TRAVIS_TAG) -X main.GitCommit=$(TRAVIS_COMMIT) -X main.GitRepoSlug=$(TRAVIS_REPO_SLUG) -X main.BuildDate=`date -u +%Y%m%d.%H%M%S`" github.com/kabanero-io/kabanero-operator/cmd/admission-webhook GO111MODULE=on CGO_ENABLED=0 GOOS=linux GOARCH=$(ARCH) go build -o build/_output/bin/serving -gcflags "all=-trimpath=$(GOPATH)" -asmflags "all=-trimpath=$(GOPATH)" -ldflags "-X main.GitTag=$(TRAVIS_TAG) -X main.GitCommit=$(TRAVIS_COMMIT) -X main.GitRepoSlug=$(TRAVIS_REPO_SLUG) -X main.BuildDate=`date -u +%Y%m%d.%H%M%S`" github.com/kabanero-io/kabanero-operator/cmd/serving @@ -90,11 +88,12 @@ build-image: generate build-registry-image: # Build an OLM private registry for Kabanero. Should be run after push-image so the IMAGE SHA is generated + rm -Rf build/registry mkdir -p build/registry cp LICENSE build/registry/LICENSE cp -R registry/manifests build/registry/ cp registry/Dockerfile build/registry/Dockerfile - cp deploy/crds/kabanero.io_kabaneros_crd.yaml deploy/crds/kabanero.io_collections_crd.yaml deploy/crds/kabanero.io_stacks_crd.yaml build/registry/manifests/kabanero-operator/$(CURRENT_RELEASE)/ + cp deploy/crds/kabanero.io_kabaneros_crd.yaml deploy/crds/kabanero.io_stacks_crd.yaml build/registry/manifests/kabanero-operator/$(CURRENT_RELEASE)/ # Use the internal service address in the CSV ifdef INTERNAL_REGISTRY @@ -158,7 +157,6 @@ generate: install: kubectl config set-context $$(kubectl config current-context) --namespace=kabanero kubectl apply -f deploy/crds/kabanero.io_kabaneros_crd.yaml - kubectl apply -f deploy/crds/kabanero.io_collections_crd.yaml kubectl apply -f deploy/crds/kabanero.io_stacks_crd.yaml deploy: @@ -199,7 +197,7 @@ ifndef GITHUB_TOKEN endif mkdir -p build/bin curl -L https://github.com/mitchellh/golicense/releases/download/v0.2.0/golicense_0.2.0_$(detected_OS)_x86_64.tar.gz | tar -C build/bin -xzf - golicense - build/bin/golicense -plain ./license-rules.json build/_output/bin/admission-webhook build/_output/bin/kabanero-operator build/_output/bin/kabanero-operator-collection-controller build/_output/bin/kabanero-operator-stack-controller build/_output/bin/serving | sort > 3RD_PARTY || true + build/bin/golicense -plain ./license-rules.json build/_output/bin/admission-webhook build/_output/bin/kabanero-operator build/_output/bin/kabanero-operator-stack-controller build/_output/bin/serving | sort > 3RD_PARTY || true rm build/bin/golicense # Integration Tests diff --git a/README.md b/README.md index a907e902..33005ce0 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ We suggest you install from a [release](https://github.com/kabanero-io/kabanero- [![Build Status](https://travis-ci.org/kabanero-io/kabanero-operator.svg?branch=master)](https://travis-ci.org/kabanero-io/kabanero-operator) The Kabanero operator is developed using: -* `operator-sdk` version 0.16.0. +* `operator-sdk` version 0.17.1. * `go` version 1.13.x ## Clone the Kabanero operator @@ -17,7 +17,7 @@ git clone https://github.com/kabanero-io/kabanero-operator cd kabanero-operator ``` -# Quickstart - OpenShift Container Platform (OCP) 4.3 +# Quickstart - OpenShift Container Platform (OCP) 4.4 We recommend you follow the install instructions referenced above to set up your cluster for the first time. If you would rather set it up manually, please continue with the following steps: @@ -31,7 +31,7 @@ oc login -u admin -p admin https://openshift.my.com:8443/ ## Deploy Prerequisite operators: The following operators need to be installed at the cluster scope: -* [OpenShift Serverless Operator](https://docs.openshift.com/container-platform/4.3/serverless/installing-openshift-serverless.html) +* [OpenShift Serverless Operator](https://docs.openshift.com/container-platform/4.4/serverless/installing-openshift-serverless.html) * OpenShift Pipelines Operator (from community-operators) * Appsody Operator (from certified-operators) * Open Liberty Operator (from certified-operators) diff --git a/build/Dockerfile b/build/Dockerfile index c6ae79c1..ada9dd91 100644 --- a/build/Dockerfile +++ b/build/Dockerfile @@ -4,7 +4,7 @@ FROM registry.access.redhat.com/ubi7/ubi-minimal:latest LABEL vendor="Kabanero" \ name="Kabanero Operator" \ summary="Image for Kabanero Operator" \ - description="This image contains the controller for the Kabanero Foundation and Collection. See https://github.com/kabanero-io/kabanero-operator/" + description="This image contains the controller for the Kabanero Foundation. See https://github.com/kabanero-io/kabanero-operator/" # The license must be here for Redhat container certification COPY LICENSE /licenses/ @@ -16,7 +16,6 @@ ENV OPERATOR=/usr/local/bin/kabanero-operator \ # install operator binary and supporting controllers. COPY build/_output/bin/kabanero-operator ${OPERATOR} COPY build/_output/bin/kabanero-operator-stack-controller /usr/local/bin/kabanero-operator-stack-controller -COPY build/_output/bin/kabanero-operator-collection-controller /usr/local/bin/kabanero-operator-collection-controller COPY build/_output/bin/admission-webhook /usr/local/bin/admission-webhook COPY build/_output/bin/serving /usr/local/bin/serving diff --git a/cmd/admission-webhook/main.go b/cmd/admission-webhook/main.go index 57e9fa8c..2d794d61 100644 --- a/cmd/admission-webhook/main.go +++ b/cmd/admission-webhook/main.go @@ -9,8 +9,6 @@ import ( _ "k8s.io/client-go/plugin/pkg/client/auth" "github.com/kabanero-io/kabanero-operator/pkg/apis" - collectionwebhook "github.com/kabanero-io/kabanero-operator/pkg/webhook/collection" - kabanerowebhookv1alpha1 "github.com/kabanero-io/kabanero-operator/pkg/webhook/kabanero/v1alpha1" kabanerowebhookv1alpha2 "github.com/kabanero-io/kabanero-operator/pkg/webhook/kabanero/v1alpha2" stackwebhook "github.com/kabanero-io/kabanero-operator/pkg/webhook/stack" @@ -98,10 +96,6 @@ func main() { // Setup the webhook server hookServer := mgr.GetWebhookServer() hookServer.Port = 9443 - hookServer.Register("/validate-collections", collectionwebhook.BuildValidatingWebhook(&mgr)) - hookServer.Register("/mutate-collections", collectionwebhook.BuildMutatingWebhook(&mgr)) - hookServer.Register("/validate-kabaneros", kabanerowebhookv1alpha1.BuildValidatingWebhook(&mgr)) - hookServer.Register("/mutate-kabaneros", kabanerowebhookv1alpha1.BuildMutatingWebhook(&mgr)) hookServer.Register("/validate-kabaneros/v1alpha2", kabanerowebhookv1alpha2.BuildValidatingWebhook(&mgr)) hookServer.Register("/validate-stacks", stackwebhook.BuildValidatingWebhook(&mgr)) hookServer.Register("/mutate-stacks", stackwebhook.BuildMutatingWebhook(&mgr)) diff --git a/cmd/manager/collection/main.go b/cmd/manager/collection/main.go deleted file mode 100755 index 618f6a3a..00000000 --- a/cmd/manager/collection/main.go +++ /dev/null @@ -1,119 +0,0 @@ -package main - -import ( - "fmt" - "os" - "runtime" - - // Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.) - _ "k8s.io/client-go/plugin/pkg/client/auth" - - "github.com/kabanero-io/kabanero-operator/pkg/apis" - "github.com/kabanero-io/kabanero-operator/pkg/controller/collection" - "sigs.k8s.io/controller-runtime/pkg/client/config" - "sigs.k8s.io/controller-runtime/pkg/manager" - logf "sigs.k8s.io/controller-runtime/pkg/log" - "sigs.k8s.io/controller-runtime/pkg/log/zap" - "sigs.k8s.io/controller-runtime/pkg/manager/signals" - - pipelinev1alpha1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1" -) - -// Change below variables to serve metrics on different host or port. -var ( - metricsHost = "0.0.0.0" - metricsPort int32 = 8383 -) -var log = logf.Log.WithName("cmd") - -// These variables are injected during the build using ldflags -var GitTag string -var GitCommit string -var GitRepoSlug string -var BuildDate string - -func printCollectionControllerData() { - log.Info(fmt.Sprintf("Go Version: %s", runtime.Version())) - log.Info(fmt.Sprintf("Go OS/Arch: %s/%s", runtime.GOOS, runtime.GOARCH)) - - if len(GitTag) > 0 { - log.Info(fmt.Sprintf("kabanero-collection-operator Git tag: %s", GitTag)) - } - - if len(GitCommit) > 0 { - log.Info(fmt.Sprintf("kabanero-collection-operator Git commit: %s", GitCommit)) - } - - if len(GitRepoSlug) > 0 { - log.Info(fmt.Sprintf("kabanero-collection-operator Git repository: %s", GitRepoSlug)) - } - - if len(BuildDate) == 0 { - BuildDate = "unspecified" - } - log.Info(fmt.Sprintf("kabanero-collection-operator build date: %s", BuildDate)) -} - -func main() { - logf.SetLogger(zap.Logger(false)) - - printCollectionControllerData() - - namespace, err := getCollectionControllerNamespace() - if err != nil { - log.Error(err, "Failed to get watch namespace") - os.Exit(1) - } - - // Get a config to talk to the apiserver - cfg, err := config.GetConfig() - if err != nil { - log.Error(err, "") - os.Exit(1) - } - - // Create a new Cmd to provide shared dependencies and start components - mgr, err := manager.New(cfg, manager.Options{ - Namespace: namespace, - }) - if err != nil { - log.Error(err, "") - os.Exit(1) - } - - log.Info("Registering Components.") - - // Setup Scheme for all resources - if err := apis.AddToScheme(mgr.GetScheme()); err != nil { - log.Error(err, "") - os.Exit(1) - } - - if err := pipelinev1alpha1.AddToScheme(mgr.GetScheme()); err != nil { - log.Error(err, "") - os.Exit(1) - } - - // Setup all Controllers - if err := collection.AddToManager(mgr); err != nil { - log.Error(err, "") - os.Exit(1) - } - - log.Info("Starting the Cmd.") - - // Start the Cmd - if err := mgr.Start(signals.SetupSignalHandler()); err != nil { - log.Error(err, "Manager exited non-zero") - os.Exit(1) - } -} - -// Returns the namespace the collection controller is running in. -func getCollectionControllerNamespace() (string, error) { - ns, found := os.LookupEnv("KABANERO_NAMESPACE") - if !found { - return "", fmt.Errorf("KABANERO_NAMESPACE must be set as an environment variable") - } - return ns, nil -} diff --git a/config/samples/collection.yaml b/config/samples/collection.yaml deleted file mode 100644 index 097b59fe..00000000 --- a/config/samples/collection.yaml +++ /dev/null @@ -1,15 +0,0 @@ -apiVersion: kabanero.io/v1alpha1 -kind: Collection -metadata: - name: java-microprofile -spec: - version: 0.0.2 - - # Triggers the activation or deactivation of a collection's assets based on - # the allowd values of active and inactive. - # The initial desiredState value for a collection is determined by the - # activateDefaultCollections setting specified in the collection repo section of - # the kabanero CR instance. Post kabanero CR instance deployment, the desiredState - # value of collection can be updated by editing the collection's resource. If the - # value entered is not one of the allowed values, the value of active is used. - desiredState: active diff --git a/config/samples/default.yaml b/config/samples/default.yaml index 463e01bd..e078f70c 100644 --- a/config/samples/default.yaml +++ b/config/samples/default.yaml @@ -3,7 +3,7 @@ kind: Kabanero metadata: name: kabanero spec: - version: "0.9.0" + version: "0.10.0" stacks: repositories: - name: central @@ -11,6 +11,6 @@ spec: url: https://github.com/kabanero-io/kabanero-stack-hub/releases/download/0.9.0/kabanero-stack-hub-index.yaml pipelines: - id: default - sha256: 63b98242b60f6a1cf240b430d24659b9727d16013935553a798be1e6c122c479 + sha256: deb5162495e1fe60ab52632f0879f9c9b95e943066590574865138791cbe948f https: - url: https://github.com/kabanero-io/kabanero-pipelines/releases/download/0.9.0/default-kabanero-pipelines.tar.gz + url: https://github.com/kabanero-io/kabanero-pipelines/releases/download/0.9.1/default-kabanero-pipelines.tar.gz diff --git a/config/samples/full.yaml b/config/samples/full.yaml index ccfb2bcf..3ecf9110 100644 --- a/config/samples/full.yaml +++ b/config/samples/full.yaml @@ -9,21 +9,21 @@ metadata: spec: # The platform version determines the desired version for all components, but those # can be overriden individually as well - version: "0.9.0" + version: "0.10.0" targetNamespaces: - kabanero cliServices: # Overrides the setting for version on this component - version: "0.9.0" + version: "0.10.0" # Overrides the image as a separate repository or tag repository: kabanero/kabanero-command-line-services - tag: "0.9.0" + tag: "0.9.1" # Overrides the image uri - image: kabanero/kabanero-command-line-services:0.9.0 + image: kabanero/kabanero-command-line-services:0.9.1 # Indicates the token expiration time # Specify a positive integer followed by a unit of time, which can be hours (h), minutes (m), or seconds (s). @@ -31,20 +31,9 @@ spec: # You can include multiple values in a single entry. For example, 1m30s is equivalent to 90 seconds. sessionExpirationSeconds: "1440m" - collectionController: - # Overrides the setting for version on this component - version: "0.9.0" - - # Overrides the image as a separate repository or tag - repository: kabanero/kabanero-operator - tag: "TRAVIS_TAG" - - # Overrides the image uri - image: kabanero/kabanero-operator:TRAVIS_TAG - stackController: # Overrides the setting for version on this component - version: "0.9.0" + version: "0.10.0" # Overrides the image as a separate repository or tag repository: kabanero/kabanero-operator @@ -58,7 +47,7 @@ spec: enable: true # Overrides the setting for version on this component - version: "0.9.0" + version: "0.10.0" # Overrides the image as a separate repository or tag repository: kabanero/landing @@ -69,7 +58,7 @@ spec: admissionControllerWebhook: # Overrides the setting for version on this component - version: "0.9.0" + version: "0.10.0" # Overrides the image as a separate repository or tag repository: kabanero/kabanero-operator @@ -99,7 +88,7 @@ spec: # Image used in Devfile registry deployment. devFileRegistryImage: # Overrides the setting for version on this component. - version: "0.9.0" + version: "0.10.0" # Overrides the image as a separate repository or tag repository: kabanero/che-devfile-registry @@ -131,16 +120,16 @@ spec: url: https://github.com/kabanero-io/kabanero-stack-hub/releases/download/0.9.0/kabanero-stack-hub-index.yaml pipelines: - id: default - sha256: 63b98242b60f6a1cf240b430d24659b9727d16013935553a798be1e6c122c479 + sha256: deb5162495e1fe60ab52632f0879f9c9b95e943066590574865138791cbe948f https: - url: https://github.com/kabanero-io/kabanero-pipelines/releases/download/0.9.0/default-kabanero-pipelines.tar.gz + url: https://github.com/kabanero-io/kabanero-pipelines/releases/download/0.9.1/default-kabanero-pipelines.tar.gz gitops: pipelines: - id: gitops - sha256: 683e8a05482a166ad4d76b6358227d3807a66e7edd8bc80483d6a88bca6c4095 + sha256: 7996bf29f338f8154e9c7db977833bf33d0a6d4e228109fab411d3b38ed4b99e https: - url: https://github.com/kabanero-io/kabanero-pipelines/releases/download/0.9.0/kabanero-gitops-pipelines.tar.gz + url: https://github.com/kabanero-io/kabanero-pipelines/releases/download/0.9.1/kabanero-gitops-pipelines.tar.gz governancePolicy: # Provide governance configuration for all stacks managed by Kabanero. The allowed configuration policies are: @@ -172,7 +161,7 @@ spec: # Overrides the version of the events operator, as defined in # config/versions.yaml - version: "0.9.0" + version: "0.10.0" # Overrides the events-operator image as a separate repository or tag repository: kabanero/events-operator diff --git a/config/samples/override_software_versions.yaml b/config/samples/override_software_versions.yaml index df2af341..f34f9233 100644 --- a/config/samples/override_software_versions.yaml +++ b/config/samples/override_software_versions.yaml @@ -1,4 +1,4 @@ -apiVersion: kabanero.io/v1alpha1 +apiVersion: kabanero.io/v1alpha2 kind: Kabanero metadata: name: kabanero1 @@ -9,7 +9,7 @@ spec: # Overrides the internally determined CLI services version with the provided value version: "0.1.0" --- -apiVersion: kabanero.io/v1alpha1 +apiVersion: kabanero.io/v1alpha2 kind: Kabanero metadata: name: kabanero1 @@ -18,7 +18,7 @@ spec: # Overrides the internally determined CLI services image with the provided value image: kabanero/kabanero-command-line-services:0.1.0 --- -apiVersion: kabanero.io/v1alpha1 +apiVersion: kabanero.io/v1alpha2 kind: Kabanero metadata: name: kabanero2 @@ -28,7 +28,7 @@ spec: # The tag will be internally determined repository: kabanero/kabanero-command-line-services --- -apiVersion: kabanero.io/v1alpha1 +apiVersion: kabanero.io/v1alpha2 kind: Kabanero metadata: name: kabanero2 @@ -38,7 +38,7 @@ spec: # The repository will be internally determined tag: "0.1.1" --- -apiVersion: kabanero.io/v1alpha1 +apiVersion: kabanero.io/v1alpha2 kind: Kabanero metadata: name: kabanero3 diff --git a/config/samples/simple.yaml b/config/samples/simple.yaml index 12ecc413..612aa82e 100644 --- a/config/samples/simple.yaml +++ b/config/samples/simple.yaml @@ -1,4 +1,4 @@ -apiVersion: kabanero.io/v1alpha1 +apiVersion: kabanero.io/v1alpha2 kind: Kabanero metadata: name: kabanero diff --git a/config/versions.yaml b/config/versions.yaml index 4a3b378e..c46f0b88 100644 --- a/config/versions.yaml +++ b/config/versions.yaml @@ -9,10 +9,31 @@ # When the Kabanero instance does not specify which version of Kabanero to use, # this is the value -default: "0.9.0" +default: "0.10.0" # Top level: relates Kabanero versions to software versions kabanero: +- version: "0.10.0" + related-versions: + cli-services: "0.10.0" + landing: "0.10.0" + events: "0.10.0" + stack-controller: "0.10.0" + admission-webhook: "0.10.0" + sso: "7.3.2" + codeready-workspaces: "0.10.0" + +- version: "0.9.1" + related-versions: + cli-services: "0.9.1" + landing: "0.9.0" + events: "0.9.0" + collection-controller: "0.9.1" + stack-controller: "0.9.1" + admission-webhook: "0.9.1" + sso: "7.3.2" + codeready-workspaces: "0.9.0" + - version: "0.9.0" related-versions: cli-services: "0.9.0" @@ -71,6 +92,11 @@ kabanero: related-software: landing: + - version: "0.10.0" + orchestrations: "orchestrations/landing/0.2" + identifiers: + repository: "kabanero/landing" + tag: "0.9.0" - version: "0.9.0" orchestrations: "orchestrations/landing/0.2" identifiers: @@ -98,6 +124,16 @@ related-software: identifiers: repository: "davco01a/kabanero-command-line-services" tag: "latest" + - version: "0.10.0" + orchestrations: "orchestrations/cli-services/0.2" + identifiers: + repository: "kabanero/kabanero-command-line-services" + tag: "0.9.1" + - version: "0.9.1" + orchestrations: "orchestrations/cli-services/0.2" + identifiers: + repository: "kabanero/kabanero-command-line-services" + tag: "0.9.1" - version: "0.9.0" orchestrations: "orchestrations/cli-services/0.2" identifiers: @@ -120,6 +156,11 @@ related-software: tag: "0.6.0" codeready-workspaces: + - version: "0.10.0" + orchestrations: "orchestrations/codeready-workspaces/0.1" + identifiers: + devfile-reg-repository: "kabanero/che-devfile-registry" + devfile-reg-tag: "0.11.0" - version: "0.9.0" orchestrations: "orchestrations/codeready-workspaces/0.1" identifiers: @@ -137,6 +178,11 @@ related-software: devfile-reg-tag: "0.8.0" events: + - version: "0.10.0" + orchestrations: "orchestrations/events/0.2" + identifiers: + repository: "kabanero/events-operator" + tag: "0.1.0" - version: "0.9.0" orchestrations: "orchestrations/events/0.2" identifiers: @@ -149,11 +195,16 @@ related-software: tag: "0.1" collection-controller: - - version: "0.9.0" + - version: "0.9.1" orchestrations: "orchestrations/collection-controller/0.1" identifiers: repository: "FROM_POD" tag: "FROM_POD" + - version: "0.9.0" + orchestrations: "orchestrations/collection-controller/0.1" + identifiers: + repository: "kabanero/kabanero-operator" + tag: "0.9.0" - version: "0.8.0" orchestrations: "orchestrations/collection-controller/0.1" identifiers: @@ -176,11 +227,21 @@ related-software: tag: "0.6.0" stack-controller: - - version: "0.9.0" + - version: "0.10.0" orchestrations: "orchestrations/stack-controller/0.1" identifiers: repository: "FROM_POD" tag: "FROM_POD" + - version: "0.9.1" + orchestrations: "orchestrations/stack-controller/0.1" + identifiers: + repository: "kabanero/kabanero-operator" + tag: "0.9.1" + - version: "0.9.0" + orchestrations: "orchestrations/stack-controller/0.1" + identifiers: + repository: "kabanero/kabanero-operator" + tag: "0.9.0" - version: "0.8.0" orchestrations: "orchestrations/stack-controller/0.1" identifiers: @@ -203,11 +264,21 @@ related-software: tag: "0.6.0" admission-webhook: - - version: "0.9.0" + - version: "0.10.0" orchestrations: "orchestrations/admission-webhook/0.2" identifiers: repository: "FROM_POD" tag: "FROM_POD" + - version: "0.9.1" + orchestrations: "orchestrations/admission-webhook/0.2" + identifiers: + repository: "kabanero/kabanero-operator" + tag: "0.9.1" + - version: "0.9.0" + orchestrations: "orchestrations/admission-webhook/0.2" + identifiers: + repository: "kabanero/kabanero-operator" + tag: "0.9.0" - version: "0.8.0" orchestrations: "orchestrations/admission-webhook/0.2" identifiers: diff --git a/contrib/gen_operator_deployment.sh b/contrib/gen_operator_deployment.sh index babff880..1bc4ec9c 100755 --- a/contrib/gen_operator_deployment.sh +++ b/contrib/gen_operator_deployment.sh @@ -130,7 +130,6 @@ EOF # Add all needed yaml files. cat $DEST_DIR/dependencies.yaml >> $DEST_FILE_TMP; echo "---" >> $DEST_FILE_TMP cat $DEST_DIR/crds/kabanero_kabanero_crd.yaml >> $DEST_FILE_TMP; echo "---" >> $DEST_FILE_TMP -cat $DEST_DIR/crds/kabanero_collection_crd.yaml >> $DEST_FILE_TMP; echo "---" >> $DEST_FILE_TMP cat $DEST_DIR/service_account.yaml >> $DEST_FILE_TMP; echo "---" >> $DEST_FILE_TMP cat $DEST_DIR/operator.yaml >> $DEST_FILE_TMP; echo "---" >> $DEST_FILE_TMP; echo cat $DEST_DIR/role.yaml >> $DEST_FILE_TMP; echo "---" >> $DEST_FILE_TMP; diff --git a/deploy/crds/kabanero.io_kabaneros_crd.yaml b/deploy/crds/kabanero.io_kabaneros_crd.yaml index 4971317f..9c5796e5 100644 --- a/deploy/crds/kabanero.io_kabaneros_crd.yaml +++ b/deploy/crds/kabanero.io_kabaneros_crd.yaml @@ -365,7 +365,7 @@ spec: type: object type: object type: object - served: true + served: false storage: false - name: v1alpha2 schema: @@ -991,6 +991,23 @@ spec: version: type: string type: object + targetNamespaces: + description: Target namespace status + properties: + message: + type: string + namespaces: + description: These are the target namespaces that are currently + being used. The spec.targetNamespaces will replace these when + the operator has finished applying the role bindings to those + namespaces. + items: + type: string + type: array + x-kubernetes-list-type: set + ready: + type: string + type: object tekton: description: Tekton instance readiness status. properties: diff --git a/deploy/install.sh b/deploy/install.sh index 33d4a064..398d61f3 100755 --- a/deploy/install.sh +++ b/deploy/install.sh @@ -333,7 +333,7 @@ fi # Create service account to used by pipelines oc apply -f $KABANERO_CUSTOMRESOURCES_YAML --selector kabanero.io/install=24-pipeline-sa -# Role used by the collection controller to manipulate triggers in the +# Role used to manipulate triggers in the # tekton-pipelines namespace (for use by tekton github webhooks extension) oc apply -f $KABANERO_CUSTOMRESOURCES_YAML --selector kabanero.io/install=25-triggers-role @@ -351,9 +351,8 @@ sleep 3 echo "***************************************************************************" echo "* " echo "* The installation script is complete. You can now create an instance " -echo "* of the Kabanero CR. If you have cloned and curated a collection set, " -echo "* apply the Kabanero CR that you created. Or, to create the default " -echo "* instance: " +echo "* of the Kabanero CR. If you have cloned and curated a stack hub, apply " +echo "* the Kabanero CR that you created. Or, to create the default instance: " echo "* " echo "* oc apply -n kabanero -f ${SAMPLE_KAB_INSTANCE_URL} " echo "* " diff --git a/deploy/kabanero-subscriptions.yaml b/deploy/kabanero-subscriptions.yaml index 3d1bbe14..7e4e30fe 100644 --- a/deploy/kabanero-subscriptions.yaml +++ b/deploy/kabanero-subscriptions.yaml @@ -169,7 +169,7 @@ metadata: labels: kabanero.io/install: 14-subscription spec: - channel: release-0.9 + channel: release-0.10 installPlanApproval: Automatic name: kabanero-operator source: kabanero-catalog diff --git a/deploy/uninstall.sh b/deploy/uninstall.sh index 57953cc1..62f82c35 100755 --- a/deploy/uninstall.sh +++ b/deploy/uninstall.sh @@ -99,7 +99,7 @@ oc delete serviceaccounts,deployments --selector=kabanero.io/component=kappnav - oc delete clusterroles,clusterrolebindings,crds --selector=kabanero.io/component=kappnav --ignore-not-found oc delete namespaces --selector=kabanero.io/component=kappnav --ignore-not-found -# Delete the Role used by the collection controller to manipulate triggers +# Delete the Role used to manipulate triggers oc delete --ignore-not-found -f $KABANERO_CUSTOMRESOURCES_YAML --selector kabanero.io/install=25-triggers-role # Tekton Dashboard diff --git a/doc/collections.md b/doc/collections.md deleted file mode 100644 index 04fdde35..00000000 --- a/doc/collections.md +++ /dev/null @@ -1,40 +0,0 @@ -# Collections - -Collection contents are maintained in a Kabanero repository. A Kabanero instance refers to one or more collections repositories and can additionally specify whether *featured* collections are to be activated through the `enableFeatured` attribute. - -*TODO:* consider moving the enableFeatured attribute to the repository. - -## Collection Activation - -Collections are said to be *activated* based upon the presence of a Collection resource kind which references a collection by name and version. When searching for a collection by name, the repository ordering found in the Kabanero instance will be respected. - -## Collection Upgrade - -Only one version of a collection can be active in a particular namespace at a time. The collection resource will reference the currently activated version. By updating the 'version' attribute of the collection spec, a new version can be activated. - -## Featured Collections - -The maintainer of a collections repository can choose to flag certain collections are being "featured". When a collections repository is added to a Kabanero instance and the installation of featured collections is enabled, the featured collections are identified and activated. - -## Removal of Collection Repositories - -A collection repository can be removed from a Kabanero instance by updating the collection repository list, for example: - -``` - collections: - repositories: - - name: experimental - url: https://github.com/kabanero-io/kabanero-collection/blob/master/experimental - - name: my-experimental - url: https://myrepo.com/experimental -``` - -could be changed to: -``` - collections: - repositories: - - name: experimental - url: https://myrepo.com/experimental -``` - -When a collection repository is removed from the list, no action is taken unless all of the referenced collection resources have also been removed. diff --git a/doc/resources.md b/doc/resources.md index f16a4b85..ab539cc3 100644 --- a/doc/resources.md +++ b/doc/resources.md @@ -3,7 +3,7 @@ A Kabanero instance is described by a resource definition with `kind: Kabanero`: ``` -apiVersion: kabanero.io/v1alpha1 +apiVersion: kabanero.io/v1alpha2 kind: Kabanero metadata: name: kabanero @@ -15,16 +15,16 @@ Creation of a Kabanero Instance has multiple impacts: * May cause cluster level configuration, such as KNative Serving being enabled on the cluster * May cause deployment of instance specific resources, such as dashboard user interfaces, API endpoints, etc. -## Collections +## Stacks -A collection is scoped to a namespace. When a collection is applied, there may be a number of Kubernetes resources which come with the collection, and these are applied into the same namespace as the collection resource. +A stack is scoped to a namespace. When a stack is applied, there may be a number of Kubernetes resources which come with the stack, and these are applied into the same namespace as the stack resource. ### Example -The following `Collection` resource is assigned to the namespace `mynamespace`: +The following `Stack` resource is assigned to the namespace `mynamespace`: ``` -apiVersion: kabanero.io/v1alpha1 -kind: Collection +apiVersion: kabanero.io/v1alpha2 +kind: Stack metadata: name: java-microprofile namespace: mynamespace @@ -32,7 +32,7 @@ spec: version: 1.0.0 ``` -This collection will create a number of Tekton pipelines in the same namespace: +This stack will create a number of Tekton pipelines in the same namespace: ``` apiVersion: kind: Pipeline @@ -43,4 +43,4 @@ spec: ... ``` -For further details see [collections](collections.md) \ No newline at end of file +For further details see [stacks](stacks.md) \ No newline at end of file diff --git a/doc/stacks.md b/doc/stacks.md new file mode 100644 index 00000000..30fa398a --- /dev/null +++ b/doc/stacks.md @@ -0,0 +1,55 @@ +# Stacks + +Stack contents are maintained in a Kabanero repository. A Kabanero instance refers to one or more stacks repositories and can additionally specify whether *featured* stacks are to be activated through the `enableFeatured` attribute. + +*TODO:* consider moving the enableFeatured attribute to the repository. + +## Stack Activation + +Stacks are said to be *activated* based upon the presence of a Stack resource kind which references a stack by name and version. When searching for a stack by name, the repository ordering found in the Kabanero instance will be respected. + +## Stack Upgrade + +Only one version of a stack can be active in a particular namespace at a time. The stack resource will reference the currently activated version. By updating the 'version' attribute of the stack spec, a new version can be activated. + +## Featured Stacks + +The maintainer of a stacks repository can choose to flag certain stacks are being "featured". When a stacks repository is added to a Kabanero instance and the installation of featured stacks is enabled, the featured stacks are identified and activated. + +## Removal of Stack Repositories + +A stack repository can be removed from a Kabanero instance by updating the stack repository list, for example: + +``` + stacks: + # A list of those repositories which are searched for stacks + repositories: + - name: release-0.8 + https: + url: https://github.com/kabanero-io/kabanero-stack-hub/releases/download/0.8.0/kabanero-stack-hub-index.yaml + - name: incubator + https: + url: https://github.com/kabanero-io/kabanero-stack-hub/releases/download/0.9.0-rc.1/kabanero-stack-hub-index.yaml + pipelines: + - id: default + sha256: 3f3e440b3eed24273fd43c40208fdd95de6eadeb82b7bb461f52e1e5da7e239d + https: + url: https://github.com/kabanero-io/kabanero-pipelines/releases/download/0.8.0/default-kabanero-pipelines.tar.gz +``` + +could be changed to: +``` + stacks: + # A list of those repositories which are searched for stacks + repositories: + - name: release-0.8 + https: + url: https://github.com/kabanero-io/kabanero-stack-hub/releases/download/0.8.0/kabanero-stack-hub-index.yaml + pipelines: + - id: default + sha256: 3f3e440b3eed24273fd43c40208fdd95de6eadeb82b7bb461f52e1e5da7e239d + https: + url: https://github.com/kabanero-io/kabanero-pipelines/releases/download/0.8.0/default-kabanero-pipelines.tar.gz +``` + +When a stack repository is removed from the list, no action is taken unless all of the referenced stack resources have also been removed. diff --git a/pkg/apis/kabanero/v1alpha1/collection_types.go b/pkg/apis/kabanero/v1alpha1/collection_types.go deleted file mode 100644 index 3a80082f..00000000 --- a/pkg/apis/kabanero/v1alpha1/collection_types.go +++ /dev/null @@ -1,124 +0,0 @@ -package v1alpha1 - -import ( - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. -// NOTE: The +listType=set marker are required by OpenAPI generation for list types. - -const ( - // CollectionDesiredStateActive represents a desired collection active state. - // It indicates that the collection needs activation. - CollectionDesiredStateActive = "active" - - // CollectionDesiredStateInactive represents a desired collection inactive state. - // It indicates that the collection needs to be deactivated. - CollectionDesiredStateInactive = "inactive" -) - -// CollectionSpec defines the desired composition of a Collection -// +k8s:openapi-gen=true -type CollectionSpec struct { - RepositoryUrl string `json:"repositoryUrl,omitempty"` - SkipCertVerification bool `json:"skipCertVerification,omitempty"` - Name string `json:"name,omitempty"` - Version string `json:"version,omitempty"` - DesiredState string `json:"desiredState,omitempty"` - // +listType=set - Versions []CollectionVersion `json:"versions,omitempty"` -} - -// CollectionVersion defines the desired composition of a specific collection version. -type CollectionVersion struct { - RepositoryUrl string `json:"repositoryUrl,omitempty"` - Version string `json:"version,omitempty"` - DesiredState string `json:"desiredState,omitempty"` - SkipCertVerification bool `json:"skipCertVerification,omitempty"` -} - -// PipelineStatus defines the observed state of the assets located within a single pipeline .tar.gz. -type PipelineStatus struct { - Name string `json:"name,omitEmpty"` - Url string `json:"url,omitEmpty"` - Digest string `json:"digest,omitEmpty"` - // +listType=set - ActiveAssets []RepositoryAssetStatus `json:"activeAssets,omitempty"` -} - -// RepositoryAssetStatus defines the observed state of a single asset in a respository, in the collection. -type RepositoryAssetStatus struct { - Name string `json:"assetName,omitempty"` - Namespace string `json:"namespace,omitempty"` - Group string `json:"group,omitempty"` - Version string `json:"version,omitempty"` - Kind string `json:"kind,omitempty"` - Digest string `json:"assetDigest,omitempty"` - Status string `json:"status,omitempty"` - StatusMessage string `json:"statusMessage,omitempty"` -} - -// CollectionStatus defines the observed state of a collection -// +k8s:openapi-gen=true -type CollectionStatus struct { - ActiveVersion string `json:"activeVersion,omitempty"` - ActiveLocation string `json:"activeLocation,omitempty"` - // +listType=set - ActivePipelines []PipelineStatus `json:"activePipelines,omitempty"` - AvailableVersion string `json:"availableVersion,omitempty"` - AvailableLocation string `json:"availableLocation,omitempty"` - Status string `json:"status,omitempty"` - StatusMessage string `json:"statusMessage,omitempty"` - // +listType=set - Images []Image `json:"images,omitempty"` - // +listType=set - Versions []CollectionVersionStatus `json:"versions,omitempty"` -} - -// CollectionVersionStatus defines the observed state of a specific collection version. -type CollectionVersionStatus struct { - Version string `json:"version,omitempty"` - Location string `json:"location,omitempty"` - // +listType=set - Pipelines []PipelineStatus `json:"pipelines,omitempty"` - Status string `json:"status,omitempty"` - StatusMessage string `json:"statusMessage,omitempty"` - // +listType=set - Images []Image `json:"images,omitempty"` -} - -// Image defines a container image used by a collection -type Image struct { - Id string `json:"id,omitempty"` - Image string `json:"image,omitempty"` -} - -// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object - -// Collection is the Schema for the collections API -// +k8s:openapi-gen=true -// +kubebuilder:subresource:status -// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description="CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations." -// +kubebuilder:printcolumn:name="Status",type="string",JSONPath=".status.status",description="Collection status." -// +kubebuilder:resource:path=collections,scope=Namespaced -type Collection struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - - Spec CollectionSpec `json:"spec,omitempty"` - Status CollectionStatus `json:"status,omitempty"` -} - -// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object - -// CollectionList contains a list of Collection -type CollectionList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - // +listType=set - Items []Collection `json:"items"` -} - -func init() { - SchemeBuilder.Register(&Collection{}, &CollectionList{}) -} diff --git a/pkg/apis/kabanero/v1alpha1/kabanero_types.go b/pkg/apis/kabanero/v1alpha1/kabanero_types.go index 5480ff0d..583f75ab 100644 --- a/pkg/apis/kabanero/v1alpha1/kabanero_types.go +++ b/pkg/apis/kabanero/v1alpha1/kabanero_types.go @@ -298,6 +298,7 @@ type AdmissionControllerWebhookStatus struct { // +kubebuilder:printcolumn:name="Version",type="string",JSONPath=".status.kabaneroInstance.version",description="Kabanero operator instance version." // +kubebuilder:printcolumn:name="Ready",type="string",JSONPath=".status.kabaneroInstance.ready",description="Kabanero operator instance readiness status. The status is directly correlated to the availability of the operator's resources dependencies." // +kubebuilder:resource:path=kabaneros,scope=Namespaced +// +kubebuilder:unservedversion type Kabanero struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` diff --git a/pkg/apis/kabanero/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/kabanero/v1alpha1/zz_generated.deepcopy.go index 731008bb..7c3191d3 100644 --- a/pkg/apis/kabanero/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/kabanero/v1alpha1/zz_generated.deepcopy.go @@ -151,34 +151,6 @@ func (in *CliStatus) DeepCopy() *CliStatus { return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Collection) DeepCopyInto(out *Collection) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - in.Spec.DeepCopyInto(&out.Spec) - in.Status.DeepCopyInto(&out.Status) - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Collection. -func (in *Collection) DeepCopy() *Collection { - if in == nil { - return nil - } - out := new(Collection) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *Collection) 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 *CollectionControllerSpec) DeepCopyInto(out *CollectionControllerSpec) { *out = *in @@ -211,139 +183,6 @@ func (in *CollectionControllerStatus) DeepCopy() *CollectionControllerStatus { return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *CollectionList) DeepCopyInto(out *CollectionList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]Collection, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CollectionList. -func (in *CollectionList) DeepCopy() *CollectionList { - if in == nil { - return nil - } - out := new(CollectionList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *CollectionList) 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 *CollectionSpec) DeepCopyInto(out *CollectionSpec) { - *out = *in - if in.Versions != nil { - in, out := &in.Versions, &out.Versions - *out = make([]CollectionVersion, len(*in)) - copy(*out, *in) - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CollectionSpec. -func (in *CollectionSpec) DeepCopy() *CollectionSpec { - if in == nil { - return nil - } - out := new(CollectionSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *CollectionStatus) DeepCopyInto(out *CollectionStatus) { - *out = *in - if in.ActivePipelines != nil { - in, out := &in.ActivePipelines, &out.ActivePipelines - *out = make([]PipelineStatus, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - if in.Images != nil { - in, out := &in.Images, &out.Images - *out = make([]Image, len(*in)) - copy(*out, *in) - } - if in.Versions != nil { - in, out := &in.Versions, &out.Versions - *out = make([]CollectionVersionStatus, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CollectionStatus. -func (in *CollectionStatus) DeepCopy() *CollectionStatus { - if in == nil { - return nil - } - out := new(CollectionStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *CollectionVersion) DeepCopyInto(out *CollectionVersion) { - *out = *in - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CollectionVersion. -func (in *CollectionVersion) DeepCopy() *CollectionVersion { - if in == nil { - return nil - } - out := new(CollectionVersion) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *CollectionVersionStatus) DeepCopyInto(out *CollectionVersionStatus) { - *out = *in - if in.Pipelines != nil { - in, out := &in.Pipelines, &out.Pipelines - *out = make([]PipelineStatus, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - if in.Images != nil { - in, out := &in.Images, &out.Images - *out = make([]Image, len(*in)) - copy(*out, *in) - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CollectionVersionStatus. -func (in *CollectionVersionStatus) DeepCopy() *CollectionVersionStatus { - if in == nil { - return nil - } - out := new(CollectionVersionStatus) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *EventsCustomizationSpec) DeepCopyInto(out *EventsCustomizationSpec) { *out = *in @@ -402,22 +241,6 @@ func (in *GithubConfig) DeepCopy() *GithubConfig { return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Image) DeepCopyInto(out *Image) { - *out = *in - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Image. -func (in *Image) DeepCopy() *Image { - if in == nil { - return nil - } - out := new(Image) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *InstanceCollectionConfig) DeepCopyInto(out *InstanceCollectionConfig) { *out = *in @@ -749,43 +572,6 @@ func (in *KnativeServingStatus) DeepCopy() *KnativeServingStatus { return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PipelineStatus) DeepCopyInto(out *PipelineStatus) { - *out = *in - if in.ActiveAssets != nil { - in, out := &in.ActiveAssets, &out.ActiveAssets - *out = make([]RepositoryAssetStatus, len(*in)) - copy(*out, *in) - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PipelineStatus. -func (in *PipelineStatus) DeepCopy() *PipelineStatus { - if in == nil { - return nil - } - out := new(PipelineStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *RepositoryAssetStatus) DeepCopyInto(out *RepositoryAssetStatus) { - *out = *in - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RepositoryAssetStatus. -func (in *RepositoryAssetStatus) DeepCopy() *RepositoryAssetStatus { - if in == nil { - return nil - } - out := new(RepositoryAssetStatus) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *RepositoryConfig) DeepCopyInto(out *RepositoryConfig) { *out = *in diff --git a/pkg/apis/kabanero/v1alpha1/zz_generated.defaults.go b/pkg/apis/kabanero/v1alpha1/zz_generated.defaults.go deleted file mode 100644 index 7985166a..00000000 --- a/pkg/apis/kabanero/v1alpha1/zz_generated.defaults.go +++ /dev/null @@ -1,16 +0,0 @@ -// +build !ignore_autogenerated - -// Code generated by defaulter-gen. DO NOT EDIT. - -package v1alpha1 - -import ( - runtime "k8s.io/apimachinery/pkg/runtime" -) - -// RegisterDefaults adds defaulters functions to the given scheme. -// Public to allow building arbitrary schemes. -// All generated defaulters are covering - they call all nested defaulters. -func RegisterDefaults(scheme *runtime.Scheme) error { - return nil -} diff --git a/pkg/apis/kabanero/v1alpha1/zz_generated.openapi.go b/pkg/apis/kabanero/v1alpha1/zz_generated.openapi.go deleted file mode 100644 index 6b4289e4..00000000 --- a/pkg/apis/kabanero/v1alpha1/zz_generated.openapi.go +++ /dev/null @@ -1,443 +0,0 @@ -// +build !ignore_autogenerated - -// This file was autogenerated by openapi-gen. Do not edit it manually! - -package v1alpha1 - -import ( - spec "github.com/go-openapi/spec" - common "k8s.io/kube-openapi/pkg/common" -) - -func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenAPIDefinition { - return map[string]common.OpenAPIDefinition{ - "github.com/kabanero-io/kabanero-operator/pkg/apis/kabanero/v1alpha1.Collection": schema_pkg_apis_kabanero_v1alpha1_Collection(ref), - "github.com/kabanero-io/kabanero-operator/pkg/apis/kabanero/v1alpha1.CollectionSpec": schema_pkg_apis_kabanero_v1alpha1_CollectionSpec(ref), - "github.com/kabanero-io/kabanero-operator/pkg/apis/kabanero/v1alpha1.CollectionStatus": schema_pkg_apis_kabanero_v1alpha1_CollectionStatus(ref), - "github.com/kabanero-io/kabanero-operator/pkg/apis/kabanero/v1alpha1.Kabanero": schema_pkg_apis_kabanero_v1alpha1_Kabanero(ref), - "github.com/kabanero-io/kabanero-operator/pkg/apis/kabanero/v1alpha1.KabaneroSpec": schema_pkg_apis_kabanero_v1alpha1_KabaneroSpec(ref), - "github.com/kabanero-io/kabanero-operator/pkg/apis/kabanero/v1alpha1.KabaneroStatus": schema_pkg_apis_kabanero_v1alpha1_KabaneroStatus(ref), - } -} - -func schema_pkg_apis_kabanero_v1alpha1_Collection(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "Collection is the Schema for the collections API", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "kind": { - SchemaProps: spec.SchemaProps{ - 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{"string"}, - Format: "", - }, - }, - "apiVersion": { - SchemaProps: spec.SchemaProps{ - 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{"string"}, - Format: "", - }, - }, - "metadata": { - SchemaProps: spec.SchemaProps{ - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"), - }, - }, - "spec": { - SchemaProps: spec.SchemaProps{ - Ref: ref("github.com/kabanero-io/kabanero-operator/pkg/apis/kabanero/v1alpha1.CollectionSpec"), - }, - }, - "status": { - SchemaProps: spec.SchemaProps{ - Ref: ref("github.com/kabanero-io/kabanero-operator/pkg/apis/kabanero/v1alpha1.CollectionStatus"), - }, - }, - }, - }, - }, - Dependencies: []string{ - "github.com/kabanero-io/kabanero-operator/pkg/apis/kabanero/v1alpha1.CollectionSpec", "github.com/kabanero-io/kabanero-operator/pkg/apis/kabanero/v1alpha1.CollectionStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"}, - } -} - -func schema_pkg_apis_kabanero_v1alpha1_CollectionSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "CollectionSpec defines the desired composition of a Collection", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "repositoryUrl": { - SchemaProps: spec.SchemaProps{ - Type: []string{"string"}, - Format: "", - }, - }, - "skipCertVerification": { - SchemaProps: spec.SchemaProps{ - Type: []string{"boolean"}, - Format: "", - }, - }, - "name": { - SchemaProps: spec.SchemaProps{ - Type: []string{"string"}, - Format: "", - }, - }, - "version": { - SchemaProps: spec.SchemaProps{ - Type: []string{"string"}, - Format: "", - }, - }, - "desiredState": { - SchemaProps: spec.SchemaProps{ - Type: []string{"string"}, - Format: "", - }, - }, - "versions": { - VendorExtensible: spec.VendorExtensible{ - Extensions: spec.Extensions{ - "x-kubernetes-list-type": "set", - }, - }, - SchemaProps: spec.SchemaProps{ - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Ref: ref("github.com/kabanero-io/kabanero-operator/pkg/apis/kabanero/v1alpha1.CollectionVersion"), - }, - }, - }, - }, - }, - }, - }, - }, - Dependencies: []string{ - "github.com/kabanero-io/kabanero-operator/pkg/apis/kabanero/v1alpha1.CollectionVersion"}, - } -} - -func schema_pkg_apis_kabanero_v1alpha1_CollectionStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "CollectionStatus defines the observed state of a collection", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "activeVersion": { - SchemaProps: spec.SchemaProps{ - Type: []string{"string"}, - Format: "", - }, - }, - "activeLocation": { - SchemaProps: spec.SchemaProps{ - Type: []string{"string"}, - Format: "", - }, - }, - "activePipelines": { - VendorExtensible: spec.VendorExtensible{ - Extensions: spec.Extensions{ - "x-kubernetes-list-type": "set", - }, - }, - SchemaProps: spec.SchemaProps{ - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Ref: ref("github.com/kabanero-io/kabanero-operator/pkg/apis/kabanero/v1alpha1.PipelineStatus"), - }, - }, - }, - }, - }, - "availableVersion": { - SchemaProps: spec.SchemaProps{ - Type: []string{"string"}, - Format: "", - }, - }, - "availableLocation": { - SchemaProps: spec.SchemaProps{ - Type: []string{"string"}, - Format: "", - }, - }, - "status": { - SchemaProps: spec.SchemaProps{ - Type: []string{"string"}, - Format: "", - }, - }, - "statusMessage": { - SchemaProps: spec.SchemaProps{ - Type: []string{"string"}, - Format: "", - }, - }, - "images": { - VendorExtensible: spec.VendorExtensible{ - Extensions: spec.Extensions{ - "x-kubernetes-list-type": "set", - }, - }, - SchemaProps: spec.SchemaProps{ - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Ref: ref("github.com/kabanero-io/kabanero-operator/pkg/apis/kabanero/v1alpha1.Image"), - }, - }, - }, - }, - }, - "versions": { - VendorExtensible: spec.VendorExtensible{ - Extensions: spec.Extensions{ - "x-kubernetes-list-type": "set", - }, - }, - SchemaProps: spec.SchemaProps{ - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Ref: ref("github.com/kabanero-io/kabanero-operator/pkg/apis/kabanero/v1alpha1.CollectionVersionStatus"), - }, - }, - }, - }, - }, - }, - }, - }, - Dependencies: []string{ - "github.com/kabanero-io/kabanero-operator/pkg/apis/kabanero/v1alpha1.CollectionVersionStatus", "github.com/kabanero-io/kabanero-operator/pkg/apis/kabanero/v1alpha1.Image", "github.com/kabanero-io/kabanero-operator/pkg/apis/kabanero/v1alpha1.PipelineStatus"}, - } -} - -func schema_pkg_apis_kabanero_v1alpha1_Kabanero(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "kind": { - SchemaProps: spec.SchemaProps{ - 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{"string"}, - Format: "", - }, - }, - "apiVersion": { - SchemaProps: spec.SchemaProps{ - 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{"string"}, - Format: "", - }, - }, - "metadata": { - SchemaProps: spec.SchemaProps{ - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"), - }, - }, - "spec": { - SchemaProps: spec.SchemaProps{ - Ref: ref("github.com/kabanero-io/kabanero-operator/pkg/apis/kabanero/v1alpha1.KabaneroSpec"), - }, - }, - "status": { - SchemaProps: spec.SchemaProps{ - Ref: ref("github.com/kabanero-io/kabanero-operator/pkg/apis/kabanero/v1alpha1.KabaneroStatus"), - }, - }, - }, - }, - }, - Dependencies: []string{ - "github.com/kabanero-io/kabanero-operator/pkg/apis/kabanero/v1alpha1.KabaneroSpec", "github.com/kabanero-io/kabanero-operator/pkg/apis/kabanero/v1alpha1.KabaneroStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"}, - } -} - -func schema_pkg_apis_kabanero_v1alpha1_KabaneroSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "KabaneroSpec defines the desired state of Kabanero", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "version": { - SchemaProps: spec.SchemaProps{ - Type: []string{"string"}, - Format: "", - }, - }, - "targetNamespaces": { - VendorExtensible: spec.VendorExtensible{ - Extensions: spec.Extensions{ - "x-kubernetes-list-type": "set", - }, - }, - SchemaProps: spec.SchemaProps{ - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Type: []string{"string"}, - Format: "", - }, - }, - }, - }, - }, - "github": { - SchemaProps: spec.SchemaProps{ - Ref: ref("github.com/kabanero-io/kabanero-operator/pkg/apis/kabanero/v1alpha1.GithubConfig"), - }, - }, - "collections": { - SchemaProps: spec.SchemaProps{ - Ref: ref("github.com/kabanero-io/kabanero-operator/pkg/apis/kabanero/v1alpha1.InstanceCollectionConfig"), - }, - }, - "tekton": { - SchemaProps: spec.SchemaProps{ - Ref: ref("github.com/kabanero-io/kabanero-operator/pkg/apis/kabanero/v1alpha1.TektonCustomizationSpec"), - }, - }, - "cliServices": { - SchemaProps: spec.SchemaProps{ - Ref: ref("github.com/kabanero-io/kabanero-operator/pkg/apis/kabanero/v1alpha1.KabaneroCliServicesCustomizationSpec"), - }, - }, - "landing": { - SchemaProps: spec.SchemaProps{ - Ref: ref("github.com/kabanero-io/kabanero-operator/pkg/apis/kabanero/v1alpha1.KabaneroLandingCustomizationSpec"), - }, - }, - "che": { - SchemaProps: spec.SchemaProps{ - Ref: ref("github.com/kabanero-io/kabanero-operator/pkg/apis/kabanero/v1alpha1.CheCustomizationSpec"), - }, - }, - "events": { - SchemaProps: spec.SchemaProps{ - Ref: ref("github.com/kabanero-io/kabanero-operator/pkg/apis/kabanero/v1alpha1.EventsCustomizationSpec"), - }, - }, - "collectionController": { - SchemaProps: spec.SchemaProps{ - Ref: ref("github.com/kabanero-io/kabanero-operator/pkg/apis/kabanero/v1alpha1.CollectionControllerSpec"), - }, - }, - "admissionControllerWebhook": { - SchemaProps: spec.SchemaProps{ - Ref: ref("github.com/kabanero-io/kabanero-operator/pkg/apis/kabanero/v1alpha1.AdmissionControllerWebhookCustomizationSpec"), - }, - }, - }, - }, - }, - Dependencies: []string{ - "github.com/kabanero-io/kabanero-operator/pkg/apis/kabanero/v1alpha1.AdmissionControllerWebhookCustomizationSpec", "github.com/kabanero-io/kabanero-operator/pkg/apis/kabanero/v1alpha1.CheCustomizationSpec", "github.com/kabanero-io/kabanero-operator/pkg/apis/kabanero/v1alpha1.CollectionControllerSpec", "github.com/kabanero-io/kabanero-operator/pkg/apis/kabanero/v1alpha1.EventsCustomizationSpec", "github.com/kabanero-io/kabanero-operator/pkg/apis/kabanero/v1alpha1.GithubConfig", "github.com/kabanero-io/kabanero-operator/pkg/apis/kabanero/v1alpha1.InstanceCollectionConfig", "github.com/kabanero-io/kabanero-operator/pkg/apis/kabanero/v1alpha1.KabaneroCliServicesCustomizationSpec", "github.com/kabanero-io/kabanero-operator/pkg/apis/kabanero/v1alpha1.KabaneroLandingCustomizationSpec", "github.com/kabanero-io/kabanero-operator/pkg/apis/kabanero/v1alpha1.TektonCustomizationSpec"}, - } -} - -func schema_pkg_apis_kabanero_v1alpha1_KabaneroStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "KabaneroStatus defines the observed state of the Kabanero instance.", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "kabaneroInstance": { - SchemaProps: spec.SchemaProps{ - Description: "Kabanero operator instance readiness status. The status is directly correlated to the availability of resources dependencies.", - Ref: ref("github.com/kabanero-io/kabanero-operator/pkg/apis/kabanero/v1alpha1.KabaneroInstanceStatus"), - }, - }, - "knativeEventing": { - SchemaProps: spec.SchemaProps{ - Description: "Knative eventing instance readiness status.", - Ref: ref("github.com/kabanero-io/kabanero-operator/pkg/apis/kabanero/v1alpha1.KnativeEventingStatus"), - }, - }, - "serverless": { - SchemaProps: spec.SchemaProps{ - Description: "OpenShift serverless operator status.", - Ref: ref("github.com/kabanero-io/kabanero-operator/pkg/apis/kabanero/v1alpha1.ServerlessStatus"), - }, - }, - "tekton": { - SchemaProps: spec.SchemaProps{ - Description: "Tekton instance readiness status.", - Ref: ref("github.com/kabanero-io/kabanero-operator/pkg/apis/kabanero/v1alpha1.TektonStatus"), - }, - }, - "cli": { - SchemaProps: spec.SchemaProps{ - Description: "CLI readiness status.", - Ref: ref("github.com/kabanero-io/kabanero-operator/pkg/apis/kabanero/v1alpha1.CliStatus"), - }, - }, - "landing": { - SchemaProps: spec.SchemaProps{ - Description: "Kabanero Landing page readiness status.", - Ref: ref("github.com/kabanero-io/kabanero-operator/pkg/apis/kabanero/v1alpha1.KabaneroLandingPageStatus"), - }, - }, - "appsody": { - SchemaProps: spec.SchemaProps{ - Description: "Appsody instance readiness status.", - Ref: ref("github.com/kabanero-io/kabanero-operator/pkg/apis/kabanero/v1alpha1.AppsodyStatus"), - }, - }, - "kappnav": { - SchemaProps: spec.SchemaProps{ - Description: "Kabanero Application Navigator instance readiness status.", - Ref: ref("github.com/kabanero-io/kabanero-operator/pkg/apis/kabanero/v1alpha1.KappnavStatus"), - }, - }, - "che": { - SchemaProps: spec.SchemaProps{ - Description: "Che instance readiness status.", - Ref: ref("github.com/kabanero-io/kabanero-operator/pkg/apis/kabanero/v1alpha1.CheStatus"), - }, - }, - "events": { - SchemaProps: spec.SchemaProps{ - Description: "Events instance status", - Ref: ref("github.com/kabanero-io/kabanero-operator/pkg/apis/kabanero/v1alpha1.EventsStatus"), - }, - }, - "collectionController": { - SchemaProps: spec.SchemaProps{ - Description: "Kabanero collection controller readiness status.", - Ref: ref("github.com/kabanero-io/kabanero-operator/pkg/apis/kabanero/v1alpha1.CollectionControllerStatus"), - }, - }, - "admissionControllerWebhook": { - SchemaProps: spec.SchemaProps{ - Description: "Admission webhook instance status", - Ref: ref("github.com/kabanero-io/kabanero-operator/pkg/apis/kabanero/v1alpha1.AdmissionControllerWebhookStatus"), - }, - }, - }, - }, - }, - Dependencies: []string{ - "github.com/kabanero-io/kabanero-operator/pkg/apis/kabanero/v1alpha1.AdmissionControllerWebhookStatus", "github.com/kabanero-io/kabanero-operator/pkg/apis/kabanero/v1alpha1.AppsodyStatus", "github.com/kabanero-io/kabanero-operator/pkg/apis/kabanero/v1alpha1.CheStatus", "github.com/kabanero-io/kabanero-operator/pkg/apis/kabanero/v1alpha1.CliStatus", "github.com/kabanero-io/kabanero-operator/pkg/apis/kabanero/v1alpha1.CollectionControllerStatus", "github.com/kabanero-io/kabanero-operator/pkg/apis/kabanero/v1alpha1.EventsStatus", "github.com/kabanero-io/kabanero-operator/pkg/apis/kabanero/v1alpha1.KabaneroInstanceStatus", "github.com/kabanero-io/kabanero-operator/pkg/apis/kabanero/v1alpha1.KabaneroLandingPageStatus", "github.com/kabanero-io/kabanero-operator/pkg/apis/kabanero/v1alpha1.KappnavStatus", "github.com/kabanero-io/kabanero-operator/pkg/apis/kabanero/v1alpha1.KnativeEventingStatus", "github.com/kabanero-io/kabanero-operator/pkg/apis/kabanero/v1alpha1.ServerlessStatus", "github.com/kabanero-io/kabanero-operator/pkg/apis/kabanero/v1alpha1.TektonStatus"}, - } -} diff --git a/pkg/apis/kabanero/v1alpha2/kabanero_types.go b/pkg/apis/kabanero/v1alpha2/kabanero_types.go index a6945e92..c0fb11fc 100644 --- a/pkg/apis/kabanero/v1alpha2/kabanero_types.go +++ b/pkg/apis/kabanero/v1alpha2/kabanero_types.go @@ -290,6 +290,19 @@ type KabaneroStatus struct { Sso SsoStatus `json:"sso,omitempty"` Gitops GitopsStatus `json:"gitops,omitempty"` + + // Target namespace status + TargetNamespaces TargetNamespaceStatus `json:"targetNamespaces,omitempty"` +} + +type TargetNamespaceStatus struct { + // These are the target namespaces that are currently being used. The + // spec.targetNamespaces will replace these when the operator has finished + // applying the role bindings to those namespaces. + // +listType=set + Namespaces []string `json:"namespaces,omitempty"` + Ready string `json:"ready,omitempty"` + Message string `json:"message,omitempty"` } // PipelineStatus defines the observed state of the assets located within a single pipeline .tar.gz. diff --git a/pkg/apis/kabanero/v1alpha2/zz_generated.deepcopy.go b/pkg/apis/kabanero/v1alpha2/zz_generated.deepcopy.go index e60dadeb..e0f059d0 100644 --- a/pkg/apis/kabanero/v1alpha2/zz_generated.deepcopy.go +++ b/pkg/apis/kabanero/v1alpha2/zz_generated.deepcopy.go @@ -696,6 +696,7 @@ func (in *KabaneroStatus) DeepCopyInto(out *KabaneroStatus) { out.AdmissionControllerWebhook = in.AdmissionControllerWebhook out.Sso = in.Sso in.Gitops.DeepCopyInto(&out.Gitops) + in.TargetNamespaces.DeepCopyInto(&out.TargetNamespaces) return } @@ -1088,6 +1089,27 @@ func (in *StackVersionStatus) DeepCopy() *StackVersionStatus { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TargetNamespaceStatus) DeepCopyInto(out *TargetNamespaceStatus) { + *out = *in + if in.Namespaces != nil { + in, out := &in.Namespaces, &out.Namespaces + *out = make([]string, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TargetNamespaceStatus. +func (in *TargetNamespaceStatus) DeepCopy() *TargetNamespaceStatus { + if in == nil { + return nil + } + out := new(TargetNamespaceStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *TektonStatus) DeepCopyInto(out *TektonStatus) { *out = *in diff --git a/pkg/controller/collection/archive.go b/pkg/controller/collection/archive.go deleted file mode 100644 index 129e3457..00000000 --- a/pkg/controller/collection/archive.go +++ /dev/null @@ -1,269 +0,0 @@ -package collection - -import ( - "archive/tar" - "bytes" - "compress/gzip" - "crypto/sha256" - "encoding/hex" - "errors" - "fmt" - "io" - "strings" - "unicode" - - "github.com/go-logr/logr" - yml "gopkg.in/yaml.v2" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "k8s.io/apimachinery/pkg/util/yaml" -) - -// Collection archive manifest.yaml -type CollectionManifest struct { - Contents []CollectionContents `yaml:"contents,omitempty"` -} - -type CollectionContents struct { - File string `yaml:"file,omitempty"` - Sha256 string `yaml:"sha256,omitempty"` -} - -// This is the rendered asset, including its sha256 from the manifest. -type CollectionAsset struct { - Name string - Group string - Version string - Kind string - Sha256 string - Yaml unstructured.Unstructured -} - -func DownloadToByte(url string) ([]byte, error) { - return getFromCache(url, false) -} - -// Print something that looks similar to xxd output -func commTrace(buffer []byte) string { - var sb strings.Builder - for bytesLeft := len(buffer); bytesLeft > 0; { - var bytesThisRound []byte - if bytesLeft >= 16 { - bytesThisRound = buffer[len(buffer)-bytesLeft:len(buffer)-bytesLeft+16] - } else { - bytesThisRound = buffer[len(buffer)-bytesLeft:] - } - - // Build up the line to print - sb.WriteString(fmt.Sprintf("%.08X: ", len(buffer)-bytesLeft)) - for i := 0; i < 16; i = i + 2 { - x := len(bytesThisRound) - i - if x >= 2 { - sb.WriteString(fmt.Sprintf("%.04X ", bytesThisRound[i:i+2])) - } else if x == 1 { - sb.WriteString(fmt.Sprintf("%.02X ", bytesThisRound[i])) - } else { - sb.WriteString(" ") - } - } - - for _, b := range bytesThisRound { - if unicode.IsPrint(rune(b)) { - sb.WriteByte(b) - } else { - sb.WriteString(".") - } - } - sb.WriteString("\n") - - // Subtract for next loop - bytesLeft -= len(bytesThisRound) - } - - return sb.String() -} - -// Read X bytes from reader. -func readBytesFromReader(size int64, r io.Reader) ([]byte, error) { - b := make([]byte, size) - for bytesLeft := size; bytesLeft > 0; { - i, err := r.Read(b[size-bytesLeft:]) - bytesLeft -= int64(i) - // An EOF error is normal as long as we read all the bytes. - if err != nil { - if err == io.EOF { - if bytesLeft != 0 { - return nil, fmt.Errorf("EOF received before end of file: %v", err.Error()) - } - - break; - } - - // Otherwise, just return the error. - return nil, err - } - } - - return b, nil -} - -//Read the manifests from a tar.gz archive -//It would be better to use the manifest.yaml as the index, and check the signatures -//For now, ignore manifest.yaml and return all other yaml files from the archive -func decodeManifests(archive []byte, renderingContext map[string]interface{}, reqLogger logr.Logger) ([]CollectionAsset, error) { - manifests := []CollectionAsset{} - var collectionmanifest CollectionManifest - - // Read the manifest.yaml from the collection archive - r := bytes.NewReader(archive) - gzReader, err := gzip.NewReader(r) - if err != nil { - return nil, errors.New(fmt.Sprintf("Could not read manifest gzip")) - } - tarReader := tar.NewReader(gzReader) - - foundManifest := false - var headers []string - for { - header, err := tarReader.Next() - - if err == io.EOF { - break - } - - if err != nil { - return nil, errors.New(fmt.Sprintf("Could not read manifest tar")) - } - - headers = append(headers, header.Name) - - switch { - case strings.TrimPrefix(header.Name, "./") == "manifest.yaml": - //Buffer the document for further processing - b, err := readBytesFromReader(header.Size, tarReader) - if err != nil { - return nil, fmt.Errorf("Error reading archive %v: %v", header.Name, err.Error()) - } - err = yml.Unmarshal(b, &collectionmanifest) - if err != nil { - return nil, err - } - foundManifest = true - } - } - - reqLogger.Info(fmt.Sprintf("Header names: %v", strings.Join(headers, ","))) - - if foundManifest != true { - return nil, fmt.Errorf("Error reading archive, unable to read manifest.yaml") - } - - // Re-Read the archive and validate against archive manifest.yaml - r = bytes.NewReader(archive) - gzReader, err = gzip.NewReader(r) - if err != nil { - return nil, errors.New(fmt.Sprintf("Could not read manifest gzip")) - } - tarReader = tar.NewReader(gzReader) - - for { - header, err := tarReader.Next() - - if err == io.EOF { - break - } - - if err != nil { - return nil, errors.New(fmt.Sprintf("Could not read manifest tar")) - } - - // Ignore manifest.yaml on this pass, only read yaml files - switch { - case strings.TrimPrefix(header.Name, "./") == "manifest.yaml": - break - case strings.HasSuffix(header.Name, ".yaml"): - //Buffer the document for further processing - b, err := readBytesFromReader(header.Size, tarReader) - if err != nil { - return nil, fmt.Errorf("Error reading archive %v: %v", header.Name, err.Error()) - } - - // Checksum. Lookup the read file in the index and compare sha256 - match := false - b_sum := sha256.Sum256(b) - assetSumString := "" - for _, content := range collectionmanifest.Contents { - if content.File == strings.TrimPrefix(header.Name, "./") { - // Older releases may not have a sha256 in the manifest.yaml - assetSumString = content.Sha256 - if content.Sha256 != "" { - var c_sum [32]byte - decoded, err := hex.DecodeString(content.Sha256) - if err != nil { - return nil, err - } - copy(c_sum[:], decoded) - if b_sum != c_sum { - return nil, fmt.Errorf("Archive file: %v manifest.yaml checksum: %x did not match file checksum: %x", header.Name, c_sum, b_sum) - } - match = true - } else { - // Would be nice if we could make this a warning message, but it seems like the only - // options are error and info. It's possible that some implementation has other methods - // but someone needs to investigate. - reqLogger.Info(fmt.Sprintf("Archive file %v was listed in the manifest but had no checksum. Checksum validation for this file is skipped.", header.Name)) - match = true - } - } - } - if match != true { - return nil, fmt.Errorf("File %v was found in the archive, but not in the manifest.yaml", header.Name) - } - - //Apply the Kabanero yaml directive processor - s := &DirectiveProcessor{} - b, err = s.Render(b, renderingContext) - if err != nil { - return nil, fmt.Errorf("Error processing directives %v: %v", header.Name, err.Error()) - } - - decoder := yaml.NewYAMLToJSONDecoder(bytes.NewReader(b)) - out := unstructured.Unstructured{} - for err = decoder.Decode(&out); err == nil; { - gvk := out.GroupVersionKind() - manifests = append(manifests, CollectionAsset{Name: out.GetName(), Group: gvk.Group, Version: gvk.Version, Kind: gvk.Kind, Yaml: out, Sha256: assetSumString}) - out = unstructured.Unstructured{} - err = decoder.Decode(&out) - } - - if (err != nil) && (err != io.EOF) { - return nil, fmt.Errorf("Error decoding %v: %v", header.Name, err.Error()) - } - } - } - return manifests, nil -} - -func GetManifests(url string, checksum string, renderingContext map[string]interface{}, reqLogger logr.Logger) ([]CollectionAsset, error) { - b, err := DownloadToByte(url) - if err != nil { - return nil, err - } - - b_sum := sha256.Sum256(b) - var c_sum [32]byte - decoded, err := hex.DecodeString(checksum) - if err != nil { - return nil, err - } - copy(c_sum[:], decoded) - - if b_sum != c_sum { - return nil, fmt.Errorf("Index checksum: %x not match download checksum: %x", c_sum, b_sum) - } - - manifests, err := decodeManifests(b, renderingContext, reqLogger) - if err != nil { - return nil, err - } - return manifests, err -} diff --git a/pkg/controller/collection/archive_test.go b/pkg/controller/collection/archive_test.go deleted file mode 100644 index 9e64c6a0..00000000 --- a/pkg/controller/collection/archive_test.go +++ /dev/null @@ -1,59 +0,0 @@ -package collection - -import ( - "fmt" - "testing" - logf "sigs.k8s.io/controller-runtime/pkg/log" -) - -func TestGetManifests(t *testing.T) { - reqLogger := logf.NullLogger{} - sha256 := "8eacd2a6870c2b7c729ae1441cc58d6f1356bde08a022875f9f50bca8fc66543" - manifests, err := GetManifests("https://github.com/kabanero-io/collections/releases/download/v0.0.1/incubator.java-microprofile.pipeline.default.tar.gz", sha256, map[string]interface{}{"CollectionName": "Eclipse Microprofile", "CollectionId": "java-microprofile"}, reqLogger) - if err != nil { - t.Fatal(err) - } - - for _, manifest := range manifests { - t.Log(manifest) - } -} - -func TestCommTraceZero(t *testing.T) { - out := commTrace(nil) - if out != "" { - t.Fatal(fmt.Sprintf("Trace of zero bytes should yield an empty string, but got: %v", out)) - } -} - -func TestCommTraceSixteen(t *testing.T) { - buffer := "1234567890123456" - out := commTrace([]byte(buffer)) - if out != "00000000: 3132 3334 3536 3738 3930 3132 3334 3536 1234567890123456\n" { - t.Fatal(fmt.Sprintf("Trace of 16 bytes incorrect output: %v", out)) - } -} - -func TestCommTraceEight(t *testing.T) { - buffer := "12345678" - out := commTrace([]byte(buffer)) - if out != "00000000: 3132 3334 3536 3738 12345678\n" { - t.Fatal(fmt.Sprintf("Trace of 8 bytes incorrect output: %v", out)) - } -} - -func TestCommTraceNine(t *testing.T) { - buffer := "123456789" - out := commTrace([]byte(buffer)) - if out != "00000000: 3132 3334 3536 3738 39 123456789\n" { - t.Fatal(fmt.Sprintf("Trace of 9 bytes incorrect output: %v", out)) - } -} - -func TestCommTraceThirtyTwo(t *testing.T) { - buffer := "12345678901234567890123456789012" - out := commTrace([]byte(buffer)) - if out != "00000000: 3132 3334 3536 3738 3930 3132 3334 3536 1234567890123456\n00000010: 3738 3930 3132 3334 3536 3738 3930 3132 7890123456789012\n" { - t.Fatal(fmt.Sprintf("Trace of 9 bytes incorrect output: %v", out)) - } -} diff --git a/pkg/controller/collection/collection.go b/pkg/controller/collection/collection.go deleted file mode 100644 index 89c98fc8..00000000 --- a/pkg/controller/collection/collection.go +++ /dev/null @@ -1,55 +0,0 @@ -package collection - -// Collection holds collection specific data. -type Collection struct { - DefaultDashboard string `yaml:"default-dashboard,omitempty"` - DefaultImage string `yaml:"default-image,omitempty"` - DefaultPipeline string `yaml:"default-pipeline,omitempty"` - DefaultTemplate string `yaml:"default-template,omitempty"` - Description string `yaml:"description,omitempty"` - Id string `yaml:"id,omitempty"` - Images []Images `yaml:"images,omitempty"` - License string `yaml:"license,omitempty"` - Maintainers []Maintainers `yaml:"maintainers,omitempty"` - Name string `yaml:"name,omitempty"` - Pipelines []Pipelines `yaml:"pipelines,omitempty"` - Templates []Templates `yaml:"templates,omitempty"` - Version string `yaml:"version,omitempty"` -} - -// Images holds a collection image data. -type Images struct { - Id string `yaml:"id,omitempty"` - Image string `yaml:"image,omitempty"` -} - -// Maintainers holds collection maintainer information. -type Maintainers struct { - Email string `yaml:"email,omitempty"` - GithubId string `yaml:"github-id,omitempty"` - Name string `yaml:"name,omitempty"` -} - -// Pipelines holds a collection's associated pipeline data. -type Pipelines struct { - Id string `yaml:"id,omitempty"` - Sha256 string `yaml:"sha256,omitempty"` - Url string `yaml:"url,omitempty"` -} - -// Templates holds the collection's associated template data. -type Templates struct { - Id string `yaml:"id,omitempty"` - Url string `yaml:"url,omitempty"` -} - -// PipelineManifest holds the collection's associated pipeline manifests. -type PipelineManifest struct { - Contents []PipelineFiles `yaml:"contents,omitempty"` -} - -// PipelineFiles holds the collection's associated pipeline files. -type PipelineFiles struct { - File string `yaml:"file,omitempty"` - Sha256 string `yaml:"sha256,omitempty"` -} diff --git a/pkg/controller/collection/collection_controller.go b/pkg/controller/collection/collection_controller.go deleted file mode 100644 index 6251594e..00000000 --- a/pkg/controller/collection/collection_controller.go +++ /dev/null @@ -1,514 +0,0 @@ -package collection - -import ( - "context" - "fmt" - - "github.com/go-logr/logr" - kabanerov1alpha1 "github.com/kabanero-io/kabanero-operator/pkg/apis/kabanero/v1alpha1" - kabanerov1alpha2 "github.com/kabanero-io/kabanero-operator/pkg/apis/kabanero/v1alpha2" - sutils "github.com/kabanero-io/kabanero-operator/pkg/controller/stack/utils" - pipelinev1alpha1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1" - "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/runtime/schema" - "k8s.io/apimachinery/pkg/types" - "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" - logf "sigs.k8s.io/controller-runtime/pkg/log" - "sigs.k8s.io/controller-runtime/pkg/manager" - "sigs.k8s.io/controller-runtime/pkg/predicate" - "sigs.k8s.io/controller-runtime/pkg/reconcile" - "sigs.k8s.io/controller-runtime/pkg/source" -) - -var log = logf.Log.WithName("controller_collection") - -const ( - // Finalizer. - collectionFinalizerName = "kabanero.io/collection-controller" -) - -// Add creates a new Collection Controller and adds it to the Manager. The Manager will set fields on the Controller -// and Start it when the Manager is Started. -func Add(mgr manager.Manager) error { - return add(mgr, newReconciler(mgr)) -} - -// newReconciler returns a new reconcile.Reconciler -func newReconciler(mgr manager.Manager) reconcile.Reconciler { - return &ReconcileCollection{client: mgr.GetClient(), scheme: mgr.GetScheme(), indexResolver: ResolveIndex} -} - -// add adds a new Controller to mgr with r as the reconcile.Reconciler -func add(mgr manager.Manager, r reconcile.Reconciler) error { - // Create a new controller - c, err := controller.New("collection-controller", mgr, controller.Options{Reconciler: r}) - if err != nil { - return err - } - - // Create Collection predicate - cPred := predicate.Funcs{ - GenericFunc: func(e event.GenericEvent) bool { - return false - }, - UpdateFunc: func(e event.UpdateEvent) bool { - // Returning true only when the metadata generation has changed, - // allows us to ignore events where only the object status has changed, - // since the generation is not incremented when only the status changes - return e.MetaOld.GetGeneration() != e.MetaNew.GetGeneration() - }, - } - - // Watch for changes to primary resource Collection - err = c.Watch(&source.Kind{Type: &kabanerov1alpha1.Collection{}}, &handler.EnqueueRequestForObject{}, cPred) - if err != nil { - return err - } - - // Create a handler for handling Tekton Pipeline & Task events - tH := &handler.EnqueueRequestForOwner{ - IsController: true, - OwnerType: &kabanerov1alpha1.Collection{}, - } - - // Create Tekton predicate - tPred := predicate.Funcs{ - CreateFunc: func(e event.CreateEvent) bool { - // ignore Create. Collection create applies the documents. Watch would unnecessarily requeue. - return false - }, - GenericFunc: func(e event.GenericEvent) bool { - return false - }, - UpdateFunc: func(e event.UpdateEvent) bool { - // Returning true only when the metadata generation has changed, - // allows us to ignore events where only the object status has changed, - // since the generation is not incremented when only the status changes - return e.MetaOld.GetGeneration() != e.MetaNew.GetGeneration() - }, - } - - // Watch for changes to Collection Tekton Pipeline objects - err = c.Watch(&source.Kind{Type: &pipelinev1alpha1.Pipeline{}}, tH, tPred) - if err != nil { - log.Info(fmt.Sprintf("Tekton Pipelines may not be installed")) - return err - } - - err = c.Watch(&source.Kind{Type: &pipelinev1alpha1.Task{}}, tH, tPred) - if err != nil { - log.Info(fmt.Sprintf("Tekton Pipelines may not be installed")) - return err - } - - return nil -} - -// blank assignment to verify that ReconcileCollection implements reconcile.Reconciler -var _ reconcile.Reconciler = &ReconcileCollection{} - -// ReconcileCollection reconciles a Collection object -type ReconcileCollection struct { - // This client, initialized using mgr.Client() above, is a split client - // that reads objects from the cache and writes to the apiserver - client client.Client - scheme *runtime.Scheme - - //The indexResolver which will be used during reconciliation - indexResolver func(kabanerov1alpha1.RepositoryConfig, []Pipelines, []Trigger, string) (*Index, error) -} - -// Reconcile processes collection resource instances. -// 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. -// NOTE: -// Collection resources are deprecated as of Kabanero Operator version 0.6.0 and are replaced with Stack resources. -// Therefore, the function of this controller is to handle collection migration to stacks and collection deletion. -func (r *ReconcileCollection) Reconcile(request reconcile.Request) (reconcile.Result, error) { - ctx := context.Background() - - reqLogger := log.WithValues("Request.Namespace", request.Namespace, "Request.Name", request.Name) - reqLogger.Info("Reconciling Collection") - - // Fetch the Collection instance - instance := &kabanerov1alpha1.Collection{} - err := r.client.Get(context.TODO(), request.NamespacedName, instance) - if err != nil { - if errors.IsNotFound(err) { - return reconcile.Result{}, nil - } - return reconcile.Result{}, err - } - - // Resolve the kabanero instance - var k *kabanerov1alpha1.Kabanero - l := kabanerov1alpha1.KabaneroList{} - err = r.client.List(context.Background(), &l, client.InNamespace(instance.GetNamespace())) - if err != nil { - return reconcile.Result{}, err - } - for _, _k := range l.Items { - k = &_k - } - reqLogger.Info("Resolved Kabanero", "kabanero", k) - - // If the collection is being deleted, and our finalizer is set, process it. - beingDeleted, err := processDeletion(ctx, instance, r.client, reqLogger) - if err != nil { - return reconcile.Result{}, err - } - - if beingDeleted { - return reconcile.Result{}, nil - } - - // The collection is not being deleted. Migrate the collection to a stack. - collectionName := instance.ObjectMeta.Name - collectionNamespace := instance.ObjectMeta.Namespace - - // Before we convert the collection instance to a stack instance, see if - // the stack with that same name in the same namespace is already available. - stack := kabanerov1alpha2.Stack{} - name := types.NamespacedName{ - Name: collectionName, - Namespace: collectionNamespace, - } - - err = r.client.Get(context.TODO(), name, &stack) - if err != nil { - if errors.IsNotFound(err) { - stackInstance, err := r.convertCollectionToStack(k, instance) - - if err != nil { - reqLogger.Error(err, fmt.Sprintf("Unable convert collection with the name of %v to stack.", collectionName)) - return reconcile.Result{}, err - } - - err = r.client.Create(context.TODO(), stackInstance) - if err != nil { - reqLogger.Error(err, fmt.Sprintf("Unable create a stack from collection with the name of %v.", collectionName)) - return reconcile.Result{}, err - } - } else { - return reconcile.Result{}, err - } - } - - // Clean up existing collection assets. - err = deleteCollection(r.client, instance, reqLogger) - if err != nil { - reqLogger.Error(err, fmt.Sprintf("Unable delete collection with the name of %v.", collectionName)) - return reconcile.Result{}, err - } - - return reconcile.Result{}, nil -} - -// Converts a collection to a stack. -func (r *ReconcileCollection) convertCollectionToStack(k *kabanerov1alpha1.Kabanero, collection *kabanerov1alpha1.Collection) (*kabanerov1alpha2.Stack, error) { - ownerIsController := true - stackInstance := &kabanerov1alpha2.Stack{ - ObjectMeta: metav1.ObjectMeta{ - Name: collection.ObjectMeta.Name, - Namespace: collection.ObjectMeta.Namespace, - OwnerReferences: []metav1.OwnerReference{ - metav1.OwnerReference{ - APIVersion: k.TypeMeta.APIVersion, - Kind: k.TypeMeta.Kind, - Name: k.ObjectMeta.Name, - UID: k.ObjectMeta.UID, - Controller: &ownerIsController, - }, - }, - }, - Spec: kabanerov1alpha2.StackSpec{ - Name: collection.Spec.Name, - }, - } - - // Add the versions field. - cCopy := collection.DeepCopy() - if len(collection.Spec.Versions) == 0 && len(collection.Spec.Version) != 0 { - cCopy.Spec.Versions = []kabanerov1alpha1.CollectionVersion{{ - RepositoryUrl: collection.Spec.RepositoryUrl, - Version: collection.Spec.Version, - DesiredState: collection.Spec.DesiredState, - SkipCertVerification: collection.Spec.SkipCertVerification, - }} - } - err := r.processVersionsField(k, stackInstance, cCopy) - if err != nil { - return nil, err - } - - return stackInstance, nil -} - -// Adds collection information to the versions field of the input stack object. -func (r *ReconcileCollection) processVersionsField(k *kabanerov1alpha1.Kabanero, stackInstance *kabanerov1alpha2.Stack, collection *kabanerov1alpha1.Collection) error { - stackInstance.Spec.Versions = make([]kabanerov1alpha2.StackVersion, len(collection.Spec.Versions)) - - for i, cv := range collection.Spec.Versions { - stackInstance.Spec.Versions[i] = kabanerov1alpha2.StackVersion{ - Version: cv.Version, - DesiredState: cv.DesiredState, - SkipCertVerification: cv.SkipCertVerification, - } - - // Add pipelines and images entries to the stack's versions field. - // This information is obtained from the collection's status fields. However, if there is reason to believe - // that the data reported in the collection's status fields is not accurate or it does not exists, try to - // get the information from the index specified in the kabanero instance. - var images []kabanerov1alpha1.Image = []kabanerov1alpha1.Image{} - var pipelines []kabanerov1alpha1.PipelineStatus = []kabanerov1alpha1.PipelineStatus{} - for _, scvData := range collection.Status.Versions { - if cv.Version == scvData.Version { - images = scvData.Images - pipelines = scvData.Pipelines - break - } - } - - if collection.Status.Status != kabanerov1alpha1.CollectionDesiredStateActive || len(images) == 0 || len(pipelines) == 0 { - collections, err := r.readCollectionsFromIndex(k) - if err != nil { - return err - } - - cByNameMap, ok := collections[collection.Spec.Name] - if ok { - indexCollection, ok := cByNameMap[cv.Version] - if ok { - stackInstance.Spec.Versions[i].Images = make([]kabanerov1alpha2.Image, len(indexCollection.Images)) - for j, m := range indexCollection.Images { - repo, err := sutils.GetImageRepository(m.Image) - if err != nil { - return fmt.Errorf(fmt.Sprintf("Collection %v %v contained an invalid image. Image: %v. Error: %v", collection.Spec.Name, collection.Spec.Versions[i].Version, m.Image, err)) - } - stackInstance.Spec.Versions[i].Images[j].Image = repo - stackInstance.Spec.Versions[i].Images[j].Id = m.Id - } - - stackInstance.Spec.Versions[i].Pipelines = make([]kabanerov1alpha2.PipelineSpec, len(indexCollection.Pipelines)) - for k, p := range indexCollection.Pipelines { - stackInstance.Spec.Versions[i].Pipelines[k].Id = p.Id - stackInstance.Spec.Versions[i].Pipelines[k].Sha256 = p.Sha256 - stackInstance.Spec.Versions[i].Pipelines[k].Https.Url = p.Url - } - - continue - } - } - - err = fmt.Errorf(fmt.Sprintf("Collection with the name of %v and version of %v was not found in kabanero configured indexes.", collection.Name, cv.Version)) - return err - } - - // Copy data from the status section - stackInstance.Spec.Versions[i].Images = make([]kabanerov1alpha2.Image, len(images)) - for j, m := range images { - repo, err := sutils.GetImageRepository(m.Image) - if err != nil { - return fmt.Errorf(fmt.Sprintf("Collection %v %v contained an invalid image. Image: %v. Error: %v", collection.Spec.Name, collection.Spec.Versions[i].Version, m.Image, err)) - } - stackInstance.Spec.Versions[i].Images[j].Image = repo - stackInstance.Spec.Versions[i].Images[j].Id = m.Id - } - stackInstance.Spec.Versions[i].Pipelines = make([]kabanerov1alpha2.PipelineSpec, len(pipelines)) - for k, p := range pipelines { - stackInstance.Spec.Versions[i].Pipelines[k].Id = p.Name - stackInstance.Spec.Versions[i].Pipelines[k].Sha256 = p.Digest - stackInstance.Spec.Versions[i].Pipelines[k].Https.Url = p.Url - } - } - - return nil -} - -// Retrieves all collection objects associated with the kabanero specified indexes. -func (r *ReconcileCollection) readCollectionsFromIndex(k *kabanerov1alpha1.Kabanero) (map[string]map[string]Collection, error) { - collectionMap := make(map[string]map[string]Collection) - for _, repo := range k.Spec.Collections.Repositories { - index, err := r.indexResolver(repo, []Pipelines{}, []Trigger{}, "") - if err != nil { - return nil, err - } - versionMap := make(map[string]Collection) - for i, c := range index.Collections { - versionMap[index.Collections[i].Version] = c - collectionMap[c.Id] = versionMap - } - } - - return collectionMap, nil -} - -// Deletes the specified collection. -func deleteCollection(c client.Client, collection *kabanerov1alpha1.Collection, reqLogger logr.Logger) error { - // Clean up existing collection assets. - err := cleanupAssets(context.TODO(), collection, c, reqLogger) - if err != nil { - reqLogger.Error(err, "Error during cleanup processing.") - return err - } - - // Remove the finalizer entry from the instance. - err = removeCollectionFinalizer(context.TODO(), collection, c, reqLogger) - if err != nil { - reqLogger.Error(err, "Error while attempting to remove the finalizer.") - return err - } - - // Delete the collection. - err = c.Delete(context.TODO(), collection) - if err != nil { - reqLogger.Error(err, "Error while attempting to remove the finalizer.") - return err - } - - return nil -} - -// Drives collection instance deletion processing. This includes creating a finalizer, handling -// collection instance cleanup logic, and finalizer removal. -func processDeletion(ctx context.Context, collection *kabanerov1alpha1.Collection, c client.Client, reqLogger logr.Logger) (bool, error) { - // The collection instance is not deleted. Create a finalizer if it was not created already. - foundFinalizer := false - for _, finalizer := range collection.Finalizers { - if finalizer == collectionFinalizerName { - foundFinalizer = true - } - } - - beingDeleted := !collection.DeletionTimestamp.IsZero() - if !beingDeleted { - if !foundFinalizer { - collection.Finalizers = append(collection.Finalizers, collectionFinalizerName) - err := c.Update(ctx, collection) - if err != nil { - reqLogger.Error(err, "Unable to set the collection controller finalizer.") - return beingDeleted, err - } - } - - return beingDeleted, nil - } - - // The instance is being deleted. - if foundFinalizer { - // Drive collection cleanup processing. - err := cleanupAssets(ctx, collection, c, reqLogger) - if err != nil { - reqLogger.Error(err, "Error during cleanup processing.") - return beingDeleted, err - } - - // Remove the finalizer entry from the instance. - err = removeCollectionFinalizer(ctx, collection, c, reqLogger) - if err != nil { - reqLogger.Error(err, "Error while attempting to remove the finalizer.") - return beingDeleted, err - } - } - - return beingDeleted, nil -} - -// Removes the collection finalizer. -func removeCollectionFinalizer(ctx context.Context, collection *kabanerov1alpha1.Collection, c client.Client, reqLogger logr.Logger) error { - var newFinalizerList []string - for _, finalizer := range collection.Finalizers { - if finalizer == collectionFinalizerName { - continue - } - newFinalizerList = append(newFinalizerList, finalizer) - } - - collection.Finalizers = newFinalizerList - err := c.Update(ctx, collection) - - return err -} - -// Handles the finalizer cleanup logic for the Collection instance. -func cleanupAssets(ctx context.Context, collection *kabanerov1alpha1.Collection, c client.Client, reqLogger logr.Logger) error { - ownerIsController := false - assetOwner := metav1.OwnerReference{ - APIVersion: collection.APIVersion, - Kind: collection.Kind, - Name: collection.Name, - UID: collection.UID, - Controller: &ownerIsController, - } - - // Run thru the status and delete everything.... we're just going to try once since it's unlikely - // that anything that goes wrong here would be rectified by a retry. - for _, version := range collection.Status.Versions { - for _, pipeline := range version.Pipelines { - for _, asset := range pipeline.ActiveAssets { - // Old assets may not have a namespace set - correct that now. - if len(asset.Namespace) == 0 { - asset.Namespace = collection.GetNamespace() - } - - deleteAsset(c, asset, assetOwner) - } - } - } - - return nil -} - -// Deletes an asset. This can mean removing an object owner, or completely deleting it. -func deleteAsset(c client.Client, asset kabanerov1alpha1.RepositoryAssetStatus, assetOwner metav1.OwnerReference) error { - u := &unstructured.Unstructured{} - u.SetGroupVersionKind(schema.GroupVersionKind{ - Group: asset.Group, - Version: asset.Version, - Kind: asset.Kind, - }) - - err := c.Get(context.Background(), client.ObjectKey{ - Namespace: asset.Namespace, - Name: asset.Name, - }, u) - - if err != nil { - if errors.IsNotFound(err) == false { - log.Error(err, fmt.Sprintf("Unable to check asset name %v", asset.Name)) - return err - } - } else { - // Get the owner references. See if we're the last one. - ownerRefs := u.GetOwnerReferences() - newOwnerRefs := []metav1.OwnerReference{} - for _, ownerRef := range ownerRefs { - if ownerRef.UID != assetOwner.UID { - newOwnerRefs = append(newOwnerRefs, ownerRef) - } - } - - if len(newOwnerRefs) == 0 { - err = c.Delete(context.TODO(), u) - if err != nil { - log.Error(err, fmt.Sprintf("Unable to delete asset name %v", asset.Name)) - return err - } - } else { - u.SetOwnerReferences(newOwnerRefs) - err = c.Update(context.TODO(), u) - if err != nil { - log.Error(err, fmt.Sprintf("Unable to delete owner reference from %v", asset.Name)) - return err - } - } - } - - return nil -} diff --git a/pkg/controller/collection/collection_controller_test.go b/pkg/controller/collection/collection_controller_test.go deleted file mode 100644 index f0073f94..00000000 --- a/pkg/controller/collection/collection_controller_test.go +++ /dev/null @@ -1,360 +0,0 @@ -package collection - -import ( - "fmt" - "testing" - - "github.com/google/go-cmp/cmp" - kabanerov1alpha1 "github.com/kabanero-io/kabanero-operator/pkg/apis/kabanero/v1alpha1" - kabanerov1alpha2 "github.com/kabanero-io/kabanero-operator/pkg/apis/kabanero/v1alpha2" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -var cPipelines []kabanerov1alpha1.PipelineStatus = []kabanerov1alpha1.PipelineStatus{ - {Name: "commonPipeline", Url: "http://pipelinelink", Digest: "abc121cba"}} - -var cImages []kabanerov1alpha1.Image = []kabanerov1alpha1.Image{ - {Id: "a1b22b1a", Image: "docker.io/kabanero/java-microprofile:0.2"}} - -var cInstance *kabanerov1alpha1.Collection = &kabanerov1alpha1.Collection{ - ObjectMeta: metav1.ObjectMeta{ - Name: "java-microprofile", - Namespace: "Kabanero", - OwnerReferences: []metav1.OwnerReference{ - metav1.OwnerReference{ - APIVersion: "a/1", - Kind: "Kabanero", - Name: "kabanero", - UID: "1234567890", - }, - }, - }, - Spec: kabanerov1alpha1.CollectionSpec{ - Name: "java-microprofile", - Version: "1.2.3", - RepositoryUrl: "https://java-microprofile", - SkipCertVerification: true, - DesiredState: "active", - Versions: []kabanerov1alpha1.CollectionVersion{ - { - Version: "1.2.3", - RepositoryUrl: "https://java-microprofile/1.2.3", - SkipCertVerification: true, - DesiredState: "active", - }, - { - Version: "4.5.6", - RepositoryUrl: "https://java-microprofile/4.5.6", - SkipCertVerification: true, - DesiredState: "active", - }}, - }, - Status: kabanerov1alpha1.CollectionStatus{ - Status: "active", - ActivePipelines: cPipelines, - Images: cImages, - Versions: []kabanerov1alpha1.CollectionVersionStatus{ - { - Version: "1.2.3", - Pipelines: cPipelines, - Images: cImages, - }, - { - Version: "4.5.6", - Pipelines: cPipelines, - Images: cImages, - }, - }, - }, -} - -var sInstance *kabanerov1alpha2.Stack = &kabanerov1alpha2.Stack{ - ObjectMeta: metav1.ObjectMeta{ - Name: "java-microprofile", - Namespace: "Kabanero", - OwnerReferences: []metav1.OwnerReference{ - metav1.OwnerReference{ - APIVersion: "a/1", - Kind: "Kabanero", - Name: "kabanero", - UID: "1234567890", - }, - }, - }, - Spec: kabanerov1alpha2.StackSpec{ - Name: "java-microprofile", - Versions: []kabanerov1alpha2.StackVersion{ - { - Version: "1.2.3", - SkipCertVerification: true, - DesiredState: "active", - Pipelines: []kabanerov1alpha2.PipelineSpec{{Id: "commonPipeline", Sha256: "abc121cba", Https: kabanerov1alpha2.HttpsProtocolFile{Url: "http://pipelinelink"}}}, - Images: []kabanerov1alpha2.Image{{Id: "a1b22b1a", Image: "docker.io/kabanero/java-microprofile"}}, - }, - { - Version: "4.5.6", - SkipCertVerification: true, - DesiredState: "active", - Pipelines: []kabanerov1alpha2.PipelineSpec{{Id: "commonPipeline", Sha256: "abc121cba", Https: kabanerov1alpha2.HttpsProtocolFile{Url: "http://pipelinelink"}}}, - Images: []kabanerov1alpha2.Image{{Id: "a1b22b1a", Image: "docker.io/kabanero/java-microprofile"}}, - }, - }, - }, -} - -var kInstance *kabanerov1alpha1.Kabanero = &kabanerov1alpha1.Kabanero{ - TypeMeta: metav1.TypeMeta{Kind: "Kabanero", - APIVersion: "a/1"}, - ObjectMeta: metav1.ObjectMeta{Name: "kabanero", UID: "1234567890"}, - Spec: kabanerov1alpha1.KabaneroSpec{ - Version: "4.5.6", - Collections: kabanerov1alpha1.InstanceCollectionConfig{ - Repositories: []kabanerov1alpha1.RepositoryConfig{{ - Name: "incubator", - Url: "https://github.com/kabanero-io/collections/releases/download/0.5.0/kabanero-index.yaml", - ActivateDefaultCollections: true, - SkipCertVerification: false, - }}, - }, - }, -} - -var r *ReconcileCollection = &ReconcileCollection{indexResolver: ResolveIndex} - -// Tests a fully deployed collection (status filled in) conversion to stack structure. -func TestConvertNormalCollectionToStack(t *testing.T) { - - expectedStack := *sInstance - stack, err := r.convertCollectionToStack(kInstance, cInstance) - - if err != nil { - t.Fatal(err) - } - - if stack.ObjectMeta.Name != expectedStack.ObjectMeta.Name { - t.Fatal(fmt.Sprintf("The expected stack.ObjectMeta.Name does not match resulting stack.ObjectMeta.Name. Converted: %v. Expected: %v", stack.ObjectMeta.Name, expectedStack.ObjectMeta.Name)) - } - if stack.ObjectMeta.Namespace != expectedStack.ObjectMeta.Namespace { - t.Fatal(fmt.Sprintf("The expected stack.ObjectMeta.Namespace does not match resulting stack.ObjectMeta.Namespace. Converted: %v. Expected: %v", stack.ObjectMeta.Namespace, expectedStack.ObjectMeta.Namespace)) - } - if len(stack.ObjectMeta.OwnerReferences) != 1 { - t.Fatal(fmt.Sprintf("The resulting stack.ObjectMeta.OwnerReferences does not contain an owner entry. It should have one.")) - } - if stack.ObjectMeta.OwnerReferences[0].Kind != kInstance.TypeMeta.Kind { - t.Fatal(fmt.Sprintf("The resulting stack.ObjectMeta.OwnerReferences[0].Kind does not match expected kInstance.TypeMeta.Kind. Converted %v. Expected %v", stack.ObjectMeta.OwnerReferences[0].Kind, kInstance.TypeMeta.Kind)) - } - if stack.ObjectMeta.OwnerReferences[0].UID != kInstance.ObjectMeta.UID { - t.Fatal(fmt.Sprintf("The resulting stack.ObjectMeta.OwnerReferences[0].UID does not match expected kInstance.ObjectMeta.UID. Converted %v. Expected %v", stack.ObjectMeta.OwnerReferences[0].UID, kInstance.ObjectMeta.UID)) - } - if !cmp.Equal(stack.Spec, expectedStack.Spec) { - t.Fatal(fmt.Sprintf("The expected stack and resulting stack are not the same. Coverted: %v. Expected: %v", stack, expectedStack)) - } -} - -// Tests the conversion of a collection resource with no versions[]. -func TestConvertCollectionNoVersionsToStack(t *testing.T) { - expectedStack := sInstance.DeepCopy() - expectedStack.Spec.Versions = []kabanerov1alpha2.StackVersion{ - { - Version: "1.2.3", - SkipCertVerification: true, - DesiredState: "active", - Pipelines: []kabanerov1alpha2.PipelineSpec{{Id: "commonPipeline", Sha256: "abc121cba", Https: kabanerov1alpha2.HttpsProtocolFile{Url: "http://pipelinelink"}}}, - Images: []kabanerov1alpha2.Image{{Id: "a1b22b1a", Image: "docker.io/kabanero/java-microprofile"}}, - }} - tc := cInstance.DeepCopy() - tc.Spec.Versions = nil - - stack, err := r.convertCollectionToStack(kInstance, tc) - if err != nil { - t.Fatal(err) - } - - if stack.ObjectMeta.Name != expectedStack.ObjectMeta.Name { - t.Fatal(fmt.Sprintf("The expected stack.ObjectMeta.Name does not match resulting stack.ObjectMeta.Name. Converted: %v. Expected: %v", stack.ObjectMeta.Name, expectedStack.ObjectMeta.Name)) - } - if stack.ObjectMeta.Namespace != expectedStack.ObjectMeta.Namespace { - t.Fatal(fmt.Sprintf("The expected stack.ObjectMeta.Namespace does not match resulting stack.ObjectMeta.Namespace. Converted: %v. Expected: %v", stack.ObjectMeta.Namespace, expectedStack.ObjectMeta.Namespace)) - } - if len(stack.ObjectMeta.OwnerReferences) != 1 { - t.Fatal(fmt.Sprintf("The resulting stack.ObjectMeta.OwnerReferences does not contain an owner entry. It should have one.")) - } - if stack.ObjectMeta.OwnerReferences[0].Kind != kInstance.TypeMeta.Kind { - t.Fatal(fmt.Sprintf("The resulting stack.ObjectMeta.OwnerReferences[0].Kind does not match expected kInstance.TypeMeta.Kind. Converted %v. Expected %v", stack.ObjectMeta.OwnerReferences[0].Kind, kInstance.TypeMeta.Kind)) - } - if stack.ObjectMeta.OwnerReferences[0].UID != kInstance.ObjectMeta.UID { - t.Fatal(fmt.Sprintf("The resulting stack.ObjectMeta.OwnerReferences[0].UID does not match expected kInstance.ObjectMeta.UID. Converted %v. Expected %v", stack.ObjectMeta.OwnerReferences[0].UID, kInstance.ObjectMeta.UID)) - } - if !cmp.Equal(stack.Spec, expectedStack.Spec) { - t.Fatal(fmt.Sprintf("The expected stack and resulting stack are not the same. Coverted: %v. Expected: %v", stack, expectedStack)) - } -} - -// Tests the conversion of a collection resource where both versions do not have pipelines and images in the status section. -// The pipeline and image data are obtained from the kabnanero instance's index URL. -func TestConvertToStackUsingCollectionWithEmptyPipelineAndImageAllVersions(t *testing.T) { - expectedStack := *sInstance - tc := cInstance.DeepCopy() - tc.Status.ActivePipelines = nil - tc.Status.Images = nil - tc.Spec.Version = "0.2.21" - tc.Status.Versions[0].Pipelines = nil - tc.Status.Versions[0].Images = nil - tc.Spec.Versions[0].Version = "0.2.21" - tc.Status.Versions[1].Pipelines = nil - tc.Status.Versions[1].Images = nil - tc.Spec.Versions[1].Version = "0.2.21" - - stack, err := r.convertCollectionToStack(kInstance, tc) - if err != nil { - t.Fatal(err) - } - - if stack.ObjectMeta.Name != expectedStack.ObjectMeta.Name { - t.Fatal(fmt.Sprintf("The expected stack.ObjectMeta.Name does not match resulting stack.ObjectMeta.Name. Converted: %v. Expected: %v", stack.ObjectMeta.Name, expectedStack.ObjectMeta.Name)) - } - if stack.ObjectMeta.Namespace != expectedStack.ObjectMeta.Namespace { - t.Fatal(fmt.Sprintf("The expected stack.ObjectMeta.Namespace does not match resulting stack.ObjectMeta.Namespace. Converted: %v. Expected: %v", stack.ObjectMeta.Namespace, expectedStack.ObjectMeta.Namespace)) - } - if len(stack.ObjectMeta.OwnerReferences) != 1 { - t.Fatal(fmt.Sprintf("The resulting stack.ObjectMeta.OwnerReferences does not contain an owner entry. It should have one.")) - } - if stack.ObjectMeta.OwnerReferences[0].Kind != kInstance.TypeMeta.Kind { - t.Fatal(fmt.Sprintf("The resulting stack.ObjectMeta.OwnerReferences[0].Kind does not match expected kInstance.TypeMeta.Kind. Converted %v. Expected %v", stack.ObjectMeta.OwnerReferences[0].Kind, kInstance.TypeMeta.Kind)) - } - if stack.ObjectMeta.OwnerReferences[0].UID != kInstance.ObjectMeta.UID { - t.Fatal(fmt.Sprintf("The resulting stack.ObjectMeta.OwnerReferences[0].UID does not match expected kInstance.ObjectMeta.UID. Converted %v. Expected %v", stack.ObjectMeta.OwnerReferences[0].UID, kInstance.ObjectMeta.UID)) - } - - // This version of the collection had no status. - if len(stack.Spec.Versions[0].Images) == 0 { - t.Fatal(fmt.Sprintf("The resulting stack.Spec.Versions[0].Images array is empty. An entry was expected.")) - } - if stack.Spec.Versions[0].Images[0].Id != "java-microprofile" { - t.Fatal(fmt.Sprintf("The resulting stack.Spec.Versions[0].Images[0].Id is not java-microprofile as expected. It instead shows: " + stack.Spec.Versions[0].Images[0].Id)) - } - - if len(stack.Spec.Versions[0].Pipelines) == 0 { - t.Fatal(fmt.Sprintf("The resulting stack.Spec.Versions[0].Pipelines array is empty. An entry was expected.")) - } - if stack.Spec.Versions[0].Pipelines[0].Id != "default" { - t.Fatal(fmt.Sprintf("The resulting stack.Spec.Versions[0].Pipelines[0].Id is not default as expected. It instead shows: " + stack.Spec.Versions[0].Pipelines[0].Id)) - } - - // This version of the collection had a status. - if len(stack.Spec.Versions[1].Images) == 0 { - t.Fatal(fmt.Sprintf("The resulting stack.Spec.Versions[1].Images array is empty. An entry was expected.")) - } - if stack.Spec.Versions[1].Images[0].Id != "java-microprofile" { - t.Fatal(fmt.Sprintf("The resulting stack.Spec.Versions[1].Images[0].Id is not java-microprofile as expected. It instead shows: " + stack.Spec.Versions[0].Images[0].Id)) - } - - if len(stack.Spec.Versions[1].Pipelines) == 0 { - t.Fatal(fmt.Sprintf("The resulting stack.Spec.Versions[1].Pipelines array is empty. An entry was expected.")) - } - if stack.Spec.Versions[1].Pipelines[0].Id != "default" { - t.Fatal(fmt.Sprintf("The resulting stack.Spec.Versions[1].Pipelines[0].Id is not default as expected. It instead shows: " + stack.Spec.Versions[0].Pipelines[0].Id)) - } -} - -// Tests the conversion of a collection resource where one version does not have pipelines and images in the status section. -// The pipeline and image data are obtained from the kabnanero instance's index URL. -// The second version has pipeline and image entries defined in the status section. The data is taken from the status. -func TestConvertToStackUsingCollectionWithOneVersionHasEmptyPipelineAndImage(t *testing.T) { - expectedStack := *sInstance - tc := cInstance.DeepCopy() - tc.Status.ActivePipelines = nil - tc.Status.Images = nil - tc.Spec.Version = "0.2.21" - tc.Status.Versions[0].Pipelines = nil - tc.Status.Versions[0].Images = nil - tc.Spec.Versions[0].Version = "0.2.21" - - stack, err := r.convertCollectionToStack(kInstance, tc) - if err != nil { - t.Fatal(err) - } - - if stack.ObjectMeta.Name != expectedStack.ObjectMeta.Name { - t.Fatal(fmt.Sprintf("The expected stack.ObjectMeta.Name does not match resulting stack.ObjectMeta.Name. Converted: %v. Expected: %v", stack.ObjectMeta.Name, expectedStack.ObjectMeta.Name)) - } - if stack.ObjectMeta.Namespace != expectedStack.ObjectMeta.Namespace { - t.Fatal(fmt.Sprintf("The expected stack.ObjectMeta.Namespace does not match resulting stack.ObjectMeta.Namespace. Converted: %v. Expected: %v", stack.ObjectMeta.Namespace, expectedStack.ObjectMeta.Namespace)) - } - if len(stack.ObjectMeta.OwnerReferences) != 1 { - t.Fatal(fmt.Sprintf("The resulting stack.ObjectMeta.OwnerReferences does not contain an owner entry. It should have one.")) - } - if stack.ObjectMeta.OwnerReferences[0].Kind != kInstance.TypeMeta.Kind { - t.Fatal(fmt.Sprintf("The resulting stack.ObjectMeta.OwnerReferences[0].Kind does not match expected kInstance.TypeMeta.Kind. Converted %v. Expected %v", stack.ObjectMeta.OwnerReferences[0].Kind, kInstance.TypeMeta.Kind)) - } - if stack.ObjectMeta.OwnerReferences[0].UID != kInstance.ObjectMeta.UID { - t.Fatal(fmt.Sprintf("The resulting stack.ObjectMeta.OwnerReferences[0].UID does not match expected kInstance.ObjectMeta.UID. Converted %v. Expected %v", stack.ObjectMeta.OwnerReferences[0].UID, kInstance.ObjectMeta.UID)) - } - - // This version of the collection had no status. - if len(stack.Spec.Versions[0].Images) == 0 { - t.Fatal(fmt.Sprintf("The resulting stack.Spec.Versions[0].Images array is empty. An entry was expected.")) - } - if stack.Spec.Versions[0].Images[0].Id != "java-microprofile" { - t.Fatal(fmt.Sprintf("The resulting stack.Spec.Versions[0].Images[0].Id is not java-microprofile as expected. It instead shows: " + stack.Spec.Versions[0].Images[0].Id)) - } - - if len(stack.Spec.Versions[0].Pipelines) == 0 { - t.Fatal(fmt.Sprintf("The resulting stack.Spec.Versions[0].Pipelines array is empty. An entry was expected.")) - } - if stack.Spec.Versions[0].Pipelines[0].Id != "default" { - t.Fatal(fmt.Sprintf("The resulting stack.Spec.Versions[0].Pipelines[0].Id is not default as expected. It instead shows: " + stack.Spec.Versions[0].Pipelines[0].Id)) - } - - // This version of the collection had a status. - if len(stack.Spec.Versions[1].Images) == 0 { - t.Fatal(fmt.Sprintf("The resulting stack.Spec.Versions[1].Images array is empty. An entry was expected.")) - } - if stack.Spec.Versions[1].Images[0].Id != "a1b22b1a" { - t.Fatal(fmt.Sprintf("The resulting stack.Spec.Versions[1].Images[0].Id is not a1b22b1a as expected. It instead shows: " + stack.Spec.Versions[0].Images[0].Id)) - } - if stack.Spec.Versions[1].Images[0].Image != "docker.io/kabanero/java-microprofile" { - t.Fatal(fmt.Sprintf("The resulting stack.Spec.Versions[1].Images[0].Id is not docker.io/kabanero/java-microprofile as expected. It instead shows: " + stack.Spec.Versions[0].Images[0].Image)) - } - - if len(stack.Spec.Versions[1].Pipelines) == 0 { - t.Fatal(fmt.Sprintf("The resulting stack.Spec.Versions[1].Pipelines array is empty. An entry was expected.")) - } - if stack.Spec.Versions[1].Pipelines[0].Id != "commonPipeline" { - t.Fatal(fmt.Sprintf("The resulting stack.Spec.Versions[1].Pipelines[0].Id is not commonPipeline as expected. It instead shows: " + stack.Spec.Versions[0].Pipelines[0].Id)) - } -} - -// Tests the conversion of a collection with no Images and Pipelines defined and the index.yaml does not -// contain the version of the collection. The collection to stack conversion should fail. -func TestConvertToStackUsingCollectionWithEmptyPipelineAndImageVersionNotFound(t *testing.T) { - tc := cInstance.DeepCopy() - tc.Status.ActivePipelines = nil - tc.Status.Images = nil - tc.Status.Versions[0].Pipelines = nil - tc.Status.Versions[0].Images = nil - - stack, err := r.convertCollectionToStack(kInstance, tc) - if err == nil { - t.Fatal("An error was expected to be thrown because the index did not contain a stack with the name specified in the collection.") - } - if stack != nil { - t.Fatal("A nil stack was expected because there was an error. Instead, the following was found stack was found: ", stack) - } -} - -// Tests the conversion of a collection with inactive status and a name that could not be found in the index.yaml -// associated with the kabanero instance. -func TestConvertToStackUsingCollectionWithInactiveStateAndUnknownStack(t *testing.T) { - tc := cInstance.DeepCopy() - tc.Status.Status = "inactive" - tc.ObjectMeta.Name = "someBogusName" - tc.Spec.Name = "someBogusName" - stack, err := r.convertCollectionToStack(kInstance, tc) - if err == nil { - t.Fatal("An error was expected to be thrown because the index did not contain a stack with the name specified in the collection.") - } - if stack != nil { - t.Fatal("A nil stack was expected because there was an error. Instead, the following was found stack was found: ", stack) - } -} diff --git a/pkg/controller/collection/collection_index.go b/pkg/controller/collection/collection_index.go deleted file mode 100644 index 54c37ccc..00000000 --- a/pkg/controller/collection/collection_index.go +++ /dev/null @@ -1,23 +0,0 @@ -package collection - -// Index holds data pertaining to an index referencing a set of collections. -type Index struct { - // API Version. - APIVersion string `yaml:"apiVersion,omitempty"` - - // Holds version 2 collection's data. - Collections []Collection `yaml:"stacks,omitempty"` - - // Holds version 2 collection's data. - Triggers []Trigger `yaml:"triggers,omitempty"` - - // Source URL of this index - URL string `yaml:"url,omitempty"` -} - -// Trigger holds Trigger information. -type Trigger struct { - Id string `yaml:"id,omitempty"` - Url string `yaml:"url,omitempty"` - Sha256 string `yaml:"sha256,omitempty"` -} \ No newline at end of file diff --git a/pkg/controller/collection/controller.go b/pkg/controller/collection/controller.go deleted file mode 100644 index b1203a5f..00000000 --- a/pkg/controller/collection/controller.go +++ /dev/null @@ -1,18 +0,0 @@ -package collection - -import ( - "sigs.k8s.io/controller-runtime/pkg/manager" -) - -// AddToManagerFuncs is a list of functions to add all Controllers to the Manager -var AddToManagerFuncs []func(manager.Manager) error - -// AddToManager adds all Controllers to the Manager -func AddToManager(m manager.Manager) error { - for _, f := range AddToManagerFuncs { - if err := f(m); err != nil { - return err - } - } - return nil -} diff --git a/pkg/controller/collection/directive_processor.go b/pkg/controller/collection/directive_processor.go deleted file mode 100644 index ff297914..00000000 --- a/pkg/controller/collection/directive_processor.go +++ /dev/null @@ -1,73 +0,0 @@ -package collection - -import ( - "bufio" - "bytes" - "fmt" - "io" - "regexp" - "strings" -) - -// The DirectiveProcessor processes text processing directives found in the yaml source -type DirectiveProcessor struct { -} - -func (g DirectiveProcessor) Render(b []byte, context map[string]interface{}) ([]byte, error) { - //Search for directives - directiveExpr := regexp.MustCompile(`\s?(#Kabanero!.*)$`) - directives := make([]string, 0) - reader := bufio.NewReader(bytes.NewReader(b)) - for { - line, _, err := reader.ReadLine() - - if err == io.EOF { - break - } - - if directiveExpr.Match(line) { - directive := directiveExpr.FindStringSubmatch(string(line))[1] - directives = append(directives, directive) - } - } - - text := string(b) - for _, directive := range directives { - var err error - text, err = g.process_directive(directive, text, context) - if err != nil { - return nil, err - } - } - - return []byte(text), nil -} - -//process_directive processes an individual directive like: #Kabanero! on activate substitute CollectionName for text '${collection-name}' -func (g DirectiveProcessor) process_directive(directive string, text string, context map[string]interface{}) (string, error) { - textSubstitutionExpr := regexp.MustCompile(`#Kabanero!\son\sactivate\s(substitute\s(.+?)\s(for text)\s'(.+?)')`) - if textSubstitutionExpr.MatchString(directive) { - groups := textSubstitutionExpr.FindStringSubmatch(directive) - - //group[0]: e.g. #Kabanero! on activate substitute CollectionName for text '${collection-name}' - //group[1]: e.g. substitute CollectionName for text '${collection-name}' - key := groups[2] // The variable found in the context (CollectionName) - substitution_type := groups[3] //e.g. for text - - if substitution_type == "for text" { - text_to_replace := groups[4] //e.g. '${collection-name}' - - //Prune the directive from the text first - text = strings.Replace(text, directive, "", 1) - text = strings.TrimSpace(text) - - text = strings.ReplaceAll(text, text_to_replace, context[key].(string)) - - return text, nil - } else { - return "", fmt.Errorf("Unknown substitution: %v", substitution_type) - } - } else { - return "", fmt.Errorf("Unknown directive: %v", directive) - } -} diff --git a/pkg/controller/collection/directive_processor_test.go b/pkg/controller/collection/directive_processor_test.go deleted file mode 100644 index 2411a511..00000000 --- a/pkg/controller/collection/directive_processor_test.go +++ /dev/null @@ -1,161 +0,0 @@ -package collection - -import ( - "fmt" - "strings" - "testing" -) - -func TestDirectiveProcessor(t *testing.T) { - tests := []struct { - name string - provided []byte - expected []byte - }{{ - name: "Substitute CollectionName", - provided: []byte(` -#Kabanero! on activate substitute CollectionName for text '${collection-name}' -apiVersion: tekton.dev/v1alpha1 -kind: Pipeline -metadata: - name: ${collection-name}-build-deploy-pipeline -spec: - resources: - - resource1 - tasks: - - name: build-task - taskRef: - name: ${collection-name}-build-task - `), - - expected: []byte(` -apiVersion: tekton.dev/v1alpha1 -kind: Pipeline -metadata: - name: My Collection Name-build-deploy-pipeline -spec: - resources: - - resource1 - tasks: - - name: build-task - taskRef: - name: My Collection Name-build-task - `), - }, - { - name: "Substitute CollectionId", - provided: []byte(` -#Kabanero! on activate substitute CollectionId for text 'CollectionId' -apiVersion: tekton.dev/v1alpha1 -kind: Pipeline -metadata: - name: CollectionId-build-deploy-pipeline -spec: - resources: - - resource1 - tasks: - - name: build-task - taskRef: - name: CollectionId-build-task - `), - - expected: []byte(` -apiVersion: tekton.dev/v1alpha1 -kind: Pipeline -metadata: - name: my-collection-build-deploy-pipeline -spec: - resources: - - resource1 - tasks: - - name: build-task - taskRef: - name: my-collection-build-task - `), - }, - { - name: "Substitute Digest", - provided: []byte(` -#Kabanero! on activate substitute Digest for text 'Digest' -apiVersion: tekton.dev/v1alpha1 -kind: Pipeline -metadata: - name: build-deploy-pipeline-Digest -spec: - resources: - - resource1 - tasks: - - name: build-task - taskRef: - name: build-task-Digest - `), - - expected: []byte(` -apiVersion: tekton.dev/v1alpha1 -kind: Pipeline -metadata: - name: build-deploy-pipeline-12345678 -spec: - resources: - - resource1 - tasks: - - name: build-task - taskRef: - name: build-task-12345678 - `), - }, - { - name: "Substitute StackId Digest", - provided: []byte(` -#Kabanero! on activate substitute StackId for text 'StackId' -#Kabanero! on activate substitute Digest for text 'Digest' -apiVersion: tekton.dev/v1alpha1 -kind: Pipeline -metadata: - name: StackId-build-deploy-pipeline-Digest -spec: - resources: - - resource1 - tasks: - - name: build-task - taskRef: - name: StackId-build-task-Digest - `), - - expected: []byte(` -apiVersion: tekton.dev/v1alpha1 -kind: Pipeline -metadata: - name: my-stack-build-deploy-pipeline-12345678 -spec: - resources: - - resource1 - tasks: - - name: build-task - taskRef: - name: my-stack-build-task-12345678 - `), - }, - } - - for _, tc := range tests { - t.Run(fmt.Sprintf("%s", tc.name), func(t *testing.T) { - context := map[string]interface{}{ - "CollectionName": "My Collection Name", - "CollectionId": "my-collection", - "Digest": "12345678", - "StackId": "my-stack", - } - - r := &DirectiveProcessor{} - b_output, err := r.Render(tc.provided, context) - - if err != nil { - t.Fatal(err) - } - if strings.TrimSpace(string(b_output)) != strings.TrimSpace(string(tc.expected)) { - t.Fatal("Output did not match expectations", string(b_output), string(tc.expected)) - } - }) - } -} diff --git a/pkg/controller/collection/httpcache.go b/pkg/controller/collection/httpcache.go deleted file mode 100644 index efa9c3b3..00000000 --- a/pkg/controller/collection/httpcache.go +++ /dev/null @@ -1,149 +0,0 @@ -package collection - -import ( - "crypto/tls" - "fmt" - "io/ioutil" - "net/http" - "sync" - "time" - rlog "sigs.k8s.io/controller-runtime/pkg/log" -) - -var cachelog = rlog.Log.WithName("httpcache") - -// Value in the cache map. This contains the etag returned from the remote -// server, which is used on subsequent requests to use the cached data. -type cacheValue struct { - etag string - date string - body []byte - lastUsed time.Time -} - -// The cache is stored as a map. We are storing the value as a struct -// instead of a pointer because multiple threads will be using the values -// concurrently. -var httpCache = make(map[string]cacheValue) - -// Initialization mutex -var startPurgeTicker sync.Once - -// The Duration at which a cache entry will be purged. -const purgeDuration = 12 * time.Hour - -// The amount of time between cache purge ticker cycles -const tickerDuration = 30 * time.Minute - -// Mutex for concurrent map access -var cacheLock sync.Mutex - -// Returns the requested resource, either from the cache, or from the -// remote server. The cache is not meant to be a "high performance" or -// "heavily concurrent" cache. -func getFromCache(url string, skipCertVerify bool) ([]byte, error) { - - // Build the request. - req, err := http.NewRequest(http.MethodGet, url, nil) - if err != nil { - return nil, err - } - - // See if the object is in the cache. Drop the lock after adding the - // header so we're not holding the lock around the HTTP request. - cacheLock.Lock() - cacheData, ok := httpCache[url] - cacheLock.Unlock() - if ok { - req.Header.Add("If-None-Match", cacheData.etag) - req.Header.Add("If-Modified-Since", cacheData.date) - } - - // Drive the request. Certificate validation is not disabled by default. - transport := &http.Transport{DisableCompression: true} - if skipCertVerify { - config := &tls.Config{InsecureSkipVerify: skipCertVerify} - transport.TLSClientConfig = config - } - - client := &http.Client{Transport: transport} - resp, err := client.Do(req) - - // If something went horribly wrong, tell the user. - if err != nil { - return nil, err - } - defer resp.Body.Close() - - // Check to see if we're going to use the cached data. - if resp.StatusCode == http.StatusNotModified { - cachelog.Info(fmt.Sprintf("Retrieved from cache: %v", url)) - - // Update the last used time so the entry does not get purged. - cacheData.lastUsed = time.Now() - cacheLock.Lock() - httpCache[url] = cacheData - cacheLock.Unlock() - - return cacheData.body, nil - } else if resp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(fmt.Sprintf("Could not retrieve the resource: %v. Http status code: %v", url, resp.StatusCode)) - } - - // We got some new data back. Read it, and then see if we can cache it. - r := resp.Body - b, err := ioutil.ReadAll(r) - if err != nil { - return nil, err - } - - etag := resp.Header.Get("ETag") - date := resp.Header.Get("Date") - - // Re-lock the cache before either adding or removing the response from it. - cacheLock.Lock() - defer cacheLock.Unlock() - if (len(etag) > 0) && (len(date) > 0) { - // Before adding an entry to the cache, make sure the purge task is running. - startPurgeTicker.Do(startCachePurgeTask) - httpCache[url] = cacheValue{etag: etag, date: date, body: b, lastUsed: time.Now()} - cachelog.Info(fmt.Sprintf("Stored to cache: %v", url)) - } else { - // Take the entry out of the map if it's already there. - delete(httpCache, url) - } - - return b, nil -} - -// Starts the periodic purge task -func startCachePurgeTask() { - // Start a ticker that will receive periodic requests to purge the cache. - purgeTicker := time.NewTicker(tickerDuration) - - // This is the function that will purge the cache. Note that this function - // never ends since we expect this to be running in a Kube pod which will - // never end on its own. - go func() { - for { - select { - case <-purgeTicker.C: - cachelog.Info("Started cache purge") - purgeCache(purgeDuration) - cachelog.Info("Finished cache purge") - } - } - }() -} - -// Purges the cache -func purgeCache(localPurgeDuration time.Duration) { - cacheLock.Lock() - defer cacheLock.Unlock() - for key, _ := range httpCache { - if time.Since(httpCache[key].lastUsed) > localPurgeDuration { - cachelog.Info("Purging from cache: " + key) - delete(httpCache, key) - } - } -} diff --git a/pkg/controller/collection/httpcache_test.go b/pkg/controller/collection/httpcache_test.go deleted file mode 100644 index e9ccd6ba..00000000 --- a/pkg/controller/collection/httpcache_test.go +++ /dev/null @@ -1,192 +0,0 @@ -package collection - -import ( - "testing" - - "bytes" - "net/http" - "net/http/httptest" -) - -const theResponse = "The response." -const theResponse2 = "The response2." - -// HTTP handler that lets us know if the caller asked for the etag. -type CacheHandler struct { - etag string - cacheHits *int32 -} - -func (ch CacheHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) { - // Check to see if the request specified the If-None-Match header - etagHeader := req.Header.Get("If-None-Match") - if etagHeader == ch.etag { - // Indicate the resource has not changed. - rw.WriteHeader(http.StatusNotModified) - *(ch.cacheHits) += 1 - } else { - // Just write the response - rw.Header().Add("ETag", ch.etag) - rw.Header().Add("Date", "GarbageDate") - rw.Write([]byte(theResponse)) - } -} - -// Show that the client is sending the correct etag on a subsequent request. -func TestCachePage(t *testing.T) { - var cacheHits int32 = 0 - handler := CacheHandler{etag: "ABCDE", cacheHits: &cacheHits} - server := httptest.NewServer(handler) - defer server.Close() - - // Get the page twice... the first time should not cache, the second should cache. - data, err := getFromCache(server.URL, false) - if err != nil { - t.Fatal(err) - } - if bytes.Compare([]byte(theResponse), data) != 0 { - t.Fatal("Response 1 not correct") - } - - data, err = getFromCache(server.URL, false) - if err != nil { - t.Fatal(err) - } - if bytes.Compare([]byte(theResponse), data) != 0 { - t.Fatal("Response 2 not correct") - } - - // Make sure that the cache hit one time. - if cacheHits != 1 { - t.Fatalf("Wrong number of cache hits: %v", cacheHits) - } -} - -// HTTP handler that lets us know if the caller asked for the etag. -type CacheChangeHandler struct { - etag1, etag2 string - cacheHits *int32 -} - -func (ch CacheChangeHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) { - // Check to see if the request specified the If-None-Match header - etagHeader := req.Header.Get("If-None-Match") - if etagHeader == ch.etag1 { - // Got back the first etag, change it up and return the second. - rw.Header().Add("ETag", ch.etag2) - rw.Header().Add("Date", "GarbageDate") - rw.Write([]byte(theResponse2)) - } else if etagHeader == ch.etag2 { - // Indicate the resource has not changed. - rw.WriteHeader(http.StatusNotModified) - *(ch.cacheHits) += 1 - } else { - // Just write the response - rw.Header().Add("ETag", ch.etag1) - rw.Header().Add("Date", "GarbageDate") - rw.Write([]byte(theResponse)) - } -} - -// Show that if the server changes the etag, the client will update it. -func TestCacheChangePage(t *testing.T) { - var cacheHits int32 = 0 - handler := CacheChangeHandler{etag1: "ABCDE", etag2: "EFGHI", cacheHits: &cacheHits} - server := httptest.NewServer(handler) - defer server.Close() - - // Get the page thrice... the first time and second time should not cache, the third should cache. - data, err := getFromCache(server.URL, false) - if err != nil { - t.Fatal(err) - } - if bytes.Compare([]byte(theResponse), data) != 0 { - t.Fatal("Response 1 not correct") - } - - data, err = getFromCache(server.URL, false) - if err != nil { - t.Fatal(err) - } - if bytes.Compare([]byte(theResponse2), data) != 0 { - t.Fatal("Response 2 not correct") - } - - data, err = getFromCache(server.URL, false) - if err != nil { - t.Fatal(err) - } - if bytes.Compare([]byte(theResponse2), data) != 0 { - t.Fatal("Response 3 not correct") - } - - // Make sure that the cache hit one time. - if cacheHits != 1 { - t.Fatalf("Wrong number of cache hits: %v", cacheHits) - } -} - -// HTTP handler that does not cache -type NoCacheHandler struct {} - -func (ch NoCacheHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) { - rw.Write([]byte(theResponse)) -} - -// Show that the cache doesn't care if the server does not send etags -func TestNoCachePage(t *testing.T) { - handler := NoCacheHandler{} - server := httptest.NewServer(handler) - defer server.Close() - - // Get the page twice... - data, err := getFromCache(server.URL, false) - if err != nil { - t.Fatal(err) - } - if bytes.Compare([]byte(theResponse), data) != 0 { - t.Fatal("Response 1 not correct") - } - - data, err = getFromCache(server.URL, false) - if err != nil { - t.Fatal(err) - } - if bytes.Compare([]byte(theResponse), data) != 0 { - t.Fatal("Response 2 not correct") - } -} - -// Test that we can purge an entry from the cache successfully. -func TestCachePurge(t *testing.T) { - var cacheHits int32 = 0 - handler := CacheHandler{etag: "ABCDE", cacheHits: &cacheHits} - server := httptest.NewServer(handler) - defer server.Close() - - // Get the page twice... the first time should not cache. - data, err := getFromCache(server.URL, false) - if err != nil { - t.Fatal(err) - } - if bytes.Compare([]byte(theResponse), data) != 0 { - t.Fatal("Response 1 not correct") - } - - // Now purge the cache - purgeCache(0) - - // Get the page the second time... it should not be cached. - data, err = getFromCache(server.URL, false) - if err != nil { - t.Fatal(err) - } - if bytes.Compare([]byte(theResponse), data) != 0 { - t.Fatal("Response 2 not correct") - } - - // Make sure that the cache did not hit. - if cacheHits != 0 { - t.Fatalf("Wrong number of cache hits: %v", cacheHits) - } -} diff --git a/pkg/controller/collection/register.go b/pkg/controller/collection/register.go deleted file mode 100644 index 295b3b0d..00000000 --- a/pkg/controller/collection/register.go +++ /dev/null @@ -1,6 +0,0 @@ -package collection - -func init() { - // AddToManagerFuncs is a list of functions to create controllers and add them to a manager. - AddToManagerFuncs = append(AddToManagerFuncs, Add) -} diff --git a/pkg/controller/collection/renderer.go b/pkg/controller/collection/renderer.go deleted file mode 100644 index 01baf3ba..00000000 --- a/pkg/controller/collection/renderer.go +++ /dev/null @@ -1,7 +0,0 @@ -package collection - -// An ActivationRenderer customizes the source content from the repository before it is applied -type ActivationRenderer interface { - //Render processes the yaml source content before it is unmarshaled into an object model - Render(b []byte, context map[string]interface{}) ([]byte, error) -} diff --git a/pkg/controller/collection/resolver.go b/pkg/controller/collection/resolver.go deleted file mode 100644 index 83a7b716..00000000 --- a/pkg/controller/collection/resolver.go +++ /dev/null @@ -1,89 +0,0 @@ -package collection - -import ( - "regexp" - "strconv" - - "github.com/blang/semver" - kabanerov1alpha1 "github.com/kabanero-io/kabanero-operator/pkg/apis/kabanero/v1alpha1" - "gopkg.in/yaml.v2" -) - -// ResolveIndex returns a structure representation of the yaml file represented by the index. -func ResolveIndex(repoConf kabanerov1alpha1.RepositoryConfig, pipelines []Pipelines, triggers []Trigger, imagePrefix string) (*Index, error) { - url := repoConf.Url - - // user may specify url to yaml file or directory - matched, err := regexp.MatchString(`/([^/]+)[.]yaml$`, url) - if err != nil { - return nil, err - } - if !matched { - url = url + "/index.yaml" - } - - b, err := getFromCache(url, repoConf.SkipCertVerification) - if err != nil { - return nil, err - } - - var index Index - err = yaml.Unmarshal(b, &index) - if err != nil { - return nil, err - } - - processIndexPostRead(&index, pipelines, triggers, imagePrefix) - - index.URL = url - - return &index, nil -} - -// Updates the loaded stack index structure for compliance with the current implementation. -func processIndexPostRead(index *Index, pipelines []Pipelines, triggers []Trigger, imagePrefix string) error { - // Add common pipelines and image. - for i, collection := range index.Collections { - if len(collection.Pipelines) == 0 { - collection.Pipelines = pipelines - } - - if len(collection.Images) == 0 { - version, err := semver.ParseTolerant(collection.Version) - if err != nil { - return err - } - - image := imagePrefix + "/" + collection.Id + ":" + strconv.FormatUint(version.Major, 10) + "." + strconv.FormatUint(version.Minor, 10) - collection.Images = append(collection.Images, Images{Id: collection.Id, Image: image}) - } - - index.Collections[i] = collection - } - - // Add common triggers. - if len(index.Triggers) == 0 { - index.Triggers = triggers - } - - return nil -} - -// SearchCollection returns all collections in the index matching the given name. -func SearchCollection(collectionName string, index *Index) ([]Collection, error) { - //Locate the desired collection in the index - var collectionRefs []Collection - - for _, collectionRef := range index.Collections { - if collectionRef.Id == collectionName { - collectionRefs = append(collectionRefs, collectionRef) - } - } - - if len(collectionRefs) == 0 { - //The collection referenced in the Collection resource has no match in the index - return nil, nil - } - - return collectionRefs, nil -} diff --git a/pkg/controller/collection/resolver_test.go b/pkg/controller/collection/resolver_test.go deleted file mode 100644 index 76def53a..00000000 --- a/pkg/controller/collection/resolver_test.go +++ /dev/null @@ -1,145 +0,0 @@ -package collection - -import ( - "testing" - - kabanerov1alpha1 "github.com/kabanero-io/kabanero-operator/pkg/apis/kabanero/v1alpha1" -) - -func TestResolveIndex(t *testing.T) { - repoConfig := kabanerov1alpha1.RepositoryConfig{ - Name: "name", - Url: "https://github.com/kabanero-io/collections/releases/download/v0.0.1/incubator-index.yaml", - ActivateDefaultCollections: true, - } - - index, err := ResolveIndex(repoConfig, []Pipelines{}, []Trigger{}, "") - if err != nil { - t.Fatal(err) - } - - if index == nil { - t.Fatal("Returned index was nil") - } - - if index.APIVersion != "v2" { - t.Fatal("Expected apiVersion == v2") - } -} - -func TestResolveIndexForStacks(t *testing.T) { - repoConfig := kabanerov1alpha1.RepositoryConfig{ - Name: "openLibertyTest", - Url: "https://github.com/appsody/stacks/releases/download/java-openliberty-v0.1.2/incubator-index.yaml", - ActivateDefaultCollections: true, - } - - pipelines := []Pipelines{{Id: "testPipeline", Sha256: "1234567890", Url: "https://github.com/kabanero-io/collections/releases/download/0.5.0-rc.2/incubator.common.pipeline.default.tar.gz"}} - triggers := []Trigger{{Id: "testTrigger", Sha256: "0987654321", Url: "https://github.com/kabanero-io/collections/releases/download/0.5.0-rc.2/incubator.trigger.tar.gz"}} - index, err := ResolveIndex(repoConfig, pipelines, triggers, "kabanerobeta") - - if err != nil { - t.Fatal(err) - } - - if index == nil { - t.Fatal("The resulting index structure was nil") - } - - // Validate pipeline entries. - numStacks := len(index.Collections) - if len(index.Collections[numStacks-numStacks].Pipelines) == 0 { - t.Fatal("Index.Collections[0].Pipelines is empty. An entry was expected") - } - - c0p0 := index.Collections[numStacks-numStacks].Pipelines[0] - if c0p0.Id != "testPipeline" { - t.Fatal("Expected Index.Collections[umStacks-numStacks].Pipelines[0] to have a pipeline name of testPipeline. Instead it was: " + c0p0.Id) - } - - if len(index.Collections[numStacks-1].Pipelines) == 0 { - t.Fatal("Index.Collections[numStacks-1].Pipelines is empty. An entry was expected") - } - - cLastP0 := index.Collections[numStacks-1].Pipelines[0] - if cLastP0.Id != "testPipeline" { - t.Fatal("Expected Index.Collections[0].Pipelines[0] to have a pipeline name of testPipeline. Instead it was: " + cLastP0.Id) - } - - // Validate trigger entry. - if len(index.Triggers) == 0 { - t.Fatal("Index.Triggers is empty. An entry was expected") - } - trgr := index.Triggers[0] - if trgr.Id != "testTrigger" { - t.Fatal("Expected Index.Triggers[0] to have a trigger name of testTrigger. Instead it was: " + trgr.Id) - } - - // Validate image entry. - if len(index.Collections[0].Images) == 0 { - t.Fatal("index.Collections[0].Images is empty. An entry was expected") - } - - image := index.Collections[0].Images[0] - if len(image.Image) == 0 { - t.Fatal("Expected index.Collections[0].Images[0].Image to have a non-empty value.") - } - - if len(image.Id) == 0 { - t.Fatal("Expected index.Collections[0].Images[0].Id to have a non-empty value.") - } -} - -func TestSearchCollection(t *testing.T) { - index := &Index{ - URL: "http://some/URL/to/V2/collection/index", - APIVersion: "v2", - Collections: []Collection{ - Collection{ - DefaultImage: "java-microprofile", - DefaultPipeline: "default", - DefaultTemplate: "default", - Description: "Test collection", - Id: "java-microprofile", - Images: []Images{ - Images{}, - }, - Maintainers: []Maintainers{ - Maintainers{}, - }, - Name: "Eclipse Microprofile", - Pipelines: []Pipelines{ - Pipelines{}, - }, - }, - Collection{ - DefaultImage: "java-microprofile2", - DefaultPipeline: "default2", - DefaultTemplate: "default2", - Description: "Test collection 2", - Id: "java-microprofile2", - Images: []Images{ - Images{}, - }, - Maintainers: []Maintainers{ - Maintainers{}, - }, - Name: "Eclipse Microprofile 2", - Pipelines: []Pipelines{ - Pipelines{}, - }, - }, - }, - } - - collections, err := SearchCollection("java-microprofile2", index) - if err != nil { - t.Fatal(err) - } - - if len(collections) != 1 { - t.Fatal("The expected number of collections is 1, but found: ", len(collections)) - } - - t.Log(collections) -} diff --git a/pkg/controller/collection/testdata/bad.pipeline.tar.gz b/pkg/controller/collection/testdata/bad.pipeline.tar.gz deleted file mode 100644 index 1c5b7032..00000000 Binary files a/pkg/controller/collection/testdata/bad.pipeline.tar.gz and /dev/null differ diff --git a/pkg/controller/collection/testdata/basic.pipeline.tar.gz b/pkg/controller/collection/testdata/basic.pipeline.tar.gz deleted file mode 100644 index c8ed8b7f..00000000 Binary files a/pkg/controller/collection/testdata/basic.pipeline.tar.gz and /dev/null differ diff --git a/pkg/controller/collection/testdata/digest1.pipeline.tar.gz b/pkg/controller/collection/testdata/digest1.pipeline.tar.gz deleted file mode 100644 index 58f30d6a..00000000 Binary files a/pkg/controller/collection/testdata/digest1.pipeline.tar.gz and /dev/null differ diff --git a/pkg/controller/collection/testdata/digest2.pipeline.tar.gz b/pkg/controller/collection/testdata/digest2.pipeline.tar.gz deleted file mode 100644 index c7b2f0d1..00000000 Binary files a/pkg/controller/collection/testdata/digest2.pipeline.tar.gz and /dev/null differ diff --git a/pkg/controller/collection/testdata/trigger.pipeline.tar.gz b/pkg/controller/collection/testdata/trigger.pipeline.tar.gz deleted file mode 100644 index eba2e872..00000000 Binary files a/pkg/controller/collection/testdata/trigger.pipeline.tar.gz and /dev/null differ diff --git a/pkg/controller/kabaneroplatform/collection-operator.go b/pkg/controller/kabaneroplatform/collection-operator.go deleted file mode 100644 index a1ee98cf..00000000 --- a/pkg/controller/kabaneroplatform/collection-operator.go +++ /dev/null @@ -1,193 +0,0 @@ -package kabaneroplatform - -import ( - "context" - "fmt" - "strings" - - kabanerov1alpha1 "github.com/kabanero-io/kabanero-operator/pkg/apis/kabanero/v1alpha1" - kabanerov1alpha2 "github.com/kabanero-io/kabanero-operator/pkg/apis/kabanero/v1alpha2" - "github.com/go-logr/logr" - mf "github.com/manifestival/manifestival" - mfc "github.com/manifestival/controller-runtime-client" - appsv1 "k8s.io/api/apps/v1" - "sigs.k8s.io/controller-runtime/pkg/client" - rlog "sigs.k8s.io/controller-runtime/pkg/log" -) - -var cclog = rlog.Log.WithName("collection-controller-install") - -const ( - ccVersionSoftCompName = "collection-controller" - ccOrchestrationFileName = "collection-controller.yaml" - - ccDeploymentResourceName = "kabanero-operator-collection-controller" -) - -// Installs the Kabanero collection controller. -func reconcileCollectionController(ctx context.Context, k *kabanerov1alpha2.Kabanero, c client.Client, _ logr.Logger) error { - logger := cclog.WithValues("Kabanero instance namespace", k.Namespace, "Kabanero instance Name", k.Name) - logger.Info("Reconciling Kabanero collection controller installation.") - - // Deploy the Kabanero collection operator. - rev, err := resolveSoftwareRevision(k, ccVersionSoftCompName, k.Spec.CollectionController.Version) - if err != nil { - logger.Error(err, "Kabanero collection controller deployment failed. Unable to resolve software revision.") - return err - } - - templateCtx := rev.Identifiers - image, err := imageUriWithOverrides(k.Spec.CollectionController.Repository, k.Spec.CollectionController.Tag, k.Spec.CollectionController.Image, rev) - if err != nil { - logger.Error(err, "Kabanero collection controller deployment failed. Unable to process image overrides.") - return err - } - templateCtx["image"] = image - templateCtx["instance"] = k.ObjectMeta.UID - templateCtx["version"] = rev.Version - - f, err := rev.OpenOrchestration(ccOrchestrationFileName) - if err != nil { - return err - } - - s, err := renderOrchestration(f, templateCtx) - if err != nil { - return err - } - - mOrig, err := mf.ManifestFrom(mf.Reader(strings.NewReader(s)), mf.UseClient(mfc.NewClient(c)), mf.UseLogger(logger.WithName("manifestival"))) - if err != nil { - return err - } - - transforms := []mf.Transformer{ - mf.InjectOwner(k), - mf.InjectNamespace(k.GetNamespace()), - } - - m, err := mOrig.Transform(transforms...) - if err != nil { - return err - } - - err = m.Apply() - if err != nil { - return err - } - - // Create a RoleBinding in the tekton-pipelines namespace that will allow - // the collection controller to create triggerbinding and triggertemplate - // objects in the tekton-pipelines namespace. - templateCtx["name"] = "kabanero-" + k.GetNamespace() + "-trigger-rolebinding" - templateCtx["kabaneroNamespace"] = k.GetNamespace() - - f, err = rev.OpenOrchestration("collection-controller-tekton.yaml") - if err != nil { - return err - } - - s, err = renderOrchestration(f, templateCtx) - if err != nil { - return err - } - - mOrig, err = mf.ManifestFrom(mf.Reader(strings.NewReader(s)), mf.UseClient(mfc.NewClient(c)), mf.UseLogger(logger.WithName("manifestival"))) - if err != nil { - return err - } - - err = mOrig.Apply() - if err != nil { - return err - } - - return nil -} - -// Removes the cross-namespace objects created during the collection controller -// deployment. -func cleanupCollectionController(ctx context.Context, k *kabanerov1alpha2.Kabanero, c client.Client) error { - logger := cclog.WithValues("Kabanero instance namespace", k.Namespace, "Kabanero instance Name", k.Name) - logger.Info("Removing Kabanero collection controller installation.") - - // First, we need to delete all of the collections that we own. We must do this first, to let the - // collection controller run its finalizer for all of the collections, before deleting the - // collection controller pods etc. - collectionList := &kabanerov1alpha1.CollectionList{} - err := c.List(ctx, collectionList, client.InNamespace(k.GetNamespace())) - if err != nil { - return fmt.Errorf("Unable to list collections in finalizer: %v", err.Error()) - } - - collectionCount := 0 - for _, collection := range collectionList.Items { - for _, ownerRef := range collection.OwnerReferences { - if ownerRef.UID == k.UID { - collectionCount = collectionCount + 1 - if collection.DeletionTimestamp.IsZero() { - err = c.Delete(ctx, &collection) - if err != nil { - // Just log the error... but continue on to the next object. - logger.Error(err, "Unable to delete collection %v", collection.Name) - } - } - } - } - } - - // If there are still some collections left, need to come back and try again later... - if collectionCount > 0 { - return fmt.Errorf("Deletion blocked waiting for %v owned Collections to be deleted", collectionCount) - } - - // There used to be delete logic here for cross-namespace objects (the role binding for - // triggers). This is owned by the stack controler now, and so has been deleted from here. - return nil -} - -// Returns the readiness status of the Kabanero collection controller installation. -func getCollectionControllerStatus(ctx context.Context, k *kabanerov1alpha2.Kabanero, c client.Client) (bool, error) { - k.Status.CollectionController.Message = "" - k.Status.CollectionController.Ready = "False" - - // Retrieve the Kabanero collection controller version. - rev, err := resolveSoftwareRevision(k, ccVersionSoftCompName, k.Spec.CollectionController.Version) - if err != nil { - message := "Unable to retrieve the collection controller version." - cclog.Error(err, message) - k.Status.CollectionController.Message = message + ": " + err.Error() - return false, err - } - k.Status.CollectionController.Version = rev.Version - - // Base the status on the Kabanero collection controller's deployment resource. - ccdeployment := &appsv1.Deployment{} - err = c.Get(ctx, client.ObjectKey{ - Name: ccDeploymentResourceName, - Namespace: k.ObjectMeta.Namespace}, ccdeployment) - - if err != nil { - message := "Unable to retrieve the Kabanero collection controller deployment object." - cclog.Error(err, message) - k.Status.CollectionController.Message = message + ": " + err.Error() - return false, err - } - - conditions := ccdeployment.Status.Conditions - ready := false - for _, condition := range conditions { - if strings.ToLower(string(condition.Type)) == "available" { - if strings.ToLower(string(condition.Status)) == "true" { - ready = true - k.Status.CollectionController.Ready = "True" - } else { - k.Status.CollectionController.Message = condition.Message - } - - break - } - } - - return ready, err -} diff --git a/pkg/controller/kabaneroplatform/gitops_test.go b/pkg/controller/kabaneroplatform/gitops_test.go index 8965ee6f..61712305 100644 --- a/pkg/controller/kabaneroplatform/gitops_test.go +++ b/pkg/controller/kabaneroplatform/gitops_test.go @@ -28,7 +28,11 @@ type testLogger struct{} func (t testLogger) Info(msg string, keysAndValues ...interface{}) { fmt.Printf("Info: %v \n", msg) } func (t testLogger) Enabled() bool { return true } func (t testLogger) Error(err error, msg string, keysAndValues ...interface{}) { - fmt.Printf("Error: %v: %v\n", msg, err.Error()) + if err != nil { + fmt.Printf("Error: %v: %v\n", msg, err.Error()) + } else { + fmt.Printf("Error: %v\n", msg) + } } func (t testLogger) V(level int) logr.InfoLogger { return t } func (t testLogger) WithValues(keysAndValues ...interface{}) logr.Logger { return t } diff --git a/pkg/controller/kabaneroplatform/kabaneroplatform_controller.go b/pkg/controller/kabaneroplatform/kabaneroplatform_controller.go index 439ca019..f7f3eae8 100644 --- a/pkg/controller/kabaneroplatform/kabaneroplatform_controller.go +++ b/pkg/controller/kabaneroplatform/kabaneroplatform_controller.go @@ -2,7 +2,6 @@ package kabaneroplatform import ( "context" - "encoding/json" "fmt" "os" "strings" @@ -10,9 +9,12 @@ import ( "time" "github.com/go-logr/logr" - kabanerov1alpha1 "github.com/kabanero-io/kabanero-operator/pkg/apis/kabanero/v1alpha1" kabanerov1alpha2 "github.com/kabanero-io/kabanero-operator/pkg/apis/kabanero/v1alpha2" "github.com/kabanero-io/kabanero-operator/pkg/controller/utils/timer" + "github.com/kabanero-io/kabanero-operator/pkg/versioning" + mfc "github.com/manifestival/controller-runtime-client" + mf "github.com/manifestival/manifestival" + "github.com/operator-framework/operator-sdk/pkg/k8sutil" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" @@ -46,7 +48,6 @@ type reconcileFuncType struct { } var reconcileFuncs = []reconcileFuncType{ - {name: "collection controller", function: reconcileCollectionController}, {name: "stack controller", function: reconcileStackController}, {name: "landing page", function: deployLandingPage}, {name: "cli service", function: reconcileKabaneroCli}, @@ -54,25 +55,31 @@ var reconcileFuncs = []reconcileFuncType{ {name: "events", function: reconcileEvents}, {name: "sso", function: reconcileSso}, {name: "gitops", function: reconcileGitopsPipelines}, + {name: "target namespaces", function: reconcileTargetNamespaces}, {name: "serving", function: reconcileServing}, } // Add creates a new Kabanero Controller and adds it to the Manager. The Manager will set fields on the Controller // and Start it when the Manager is Started. func Add(mgr manager.Manager) error { - return add(mgr, newReconciler(mgr)) + // It is very unlikely that this would fail, since the main also checks for it. + watchNamespace, err := k8sutil.GetWatchNamespace() + if err != nil { + return err } -// newReconciler returns a new reconcile.Reconciler -func newReconciler(mgr manager.Manager) reconcile.Reconciler { - return &ReconcileKabanero{ + // Lets be sure a single namespace is specified. + numberOfWatchNamespaces := len(strings.Split(watchNamespace, ",")) + if numberOfWatchNamespaces != 1 { + return fmt.Errorf("%v watch namespaces were specified, but only a single watch namespace is supported: %v", numberOfWatchNamespaces, watchNamespace) + } + + r := &ReconcileKabanero{ client: mgr.GetClient(), scheme: mgr.GetScheme(), - requeueDelayMap: make(map[string]RequeueData)} -} + requeueDelayMap: make(map[string]RequeueData), + watchNamespace: watchNamespace} -// add adds a new Controller to mgr with r as the reconcile.Reconciler -func add(mgr manager.Manager, r reconcile.Reconciler) error { // Create a new controller c, err := controller.New("kabaneroplatform-controller", mgr, controller.Options{Reconciler: r}) if err != nil { @@ -105,6 +112,16 @@ func add(mgr manager.Manager, r reconcile.Reconciler) error { return err } + // Watch Namespace instances. We only care about create and delete events, not update events. + // When we see that a namespace has been created/deleted, we need to process any Kabanero objects that + // reference that namespace. + err = c.Watch(&source.Kind{Type: &corev1.Namespace{}}, &handler.EnqueueRequestsFromMapFunc{ + ToRequests: handler.ToRequestsFunc(r.targetNamespaceMapFunc)}, predicate.Funcs{ + UpdateFunc: func(e event.UpdateEvent) bool { return false }}) + if err != nil { + return err + } + /* Useful if RoleBindingList is changed to use Structured instead of Unstructured // Index Rolebindings by name if err := mgr.GetFieldIndexer().IndexField(&rbacv1.RoleBinding{}, "metadata.name", func(rawObj runtime.Object) []string { @@ -118,22 +135,17 @@ func add(mgr manager.Manager, r reconcile.Reconciler) error { return nil } -func getOperatorImage(c client.Client) (string, error) { +func (r *ReconcileKabanero) getOperatorImage() (string, error) { // First, read the POD_NAME env variable. This is set in the deployment spec in the CSV. podName := os.Getenv("POD_NAME") if len(podName) == 0 { return "", fmt.Errorf("The POD_NAME environment variable is not set, or is empty") } - namespace := os.Getenv("WATCH_NAMESPACE") - if len(namespace) == 0 { - return "", fmt.Errorf("The WATCH_NAMESPACE environment variable is not set, or is empty") - } - // Second, get the Pod instance with that name pod := &corev1.Pod{} - kubePodName := types.NamespacedName{Name: podName, Namespace: namespace} - err := c.Get(context.TODO(), kubePodName, pod) + kubePodName := types.NamespacedName{Name: podName, Namespace: r.watchNamespace} + err := r.client.Get(context.TODO(), kubePodName, pod) if err != nil { return "", fmt.Errorf("Pod %v could not be retrieved: %v", podName, err.Error()) } @@ -178,6 +190,7 @@ type ReconcileKabanero struct { client client.Client scheme *runtime.Scheme requeueDelayMap map[string]RequeueData + watchNamespace string } // RequeueData stores information that enables reconcile operations to be retried. @@ -186,6 +199,33 @@ type RequeueData struct { futureTime time.Time } +// When we see that a namespace has changed, we want to reconcile any Kabanero instances that +// reference that namespace in its targetNamespaces list. +func (r *ReconcileKabanero) targetNamespaceMapFunc(a handler.MapObject) []reconcile.Request { + log.Info(fmt.Sprintf("Processing for change in namespace %v", a.Meta.GetName())) + + // List Kabanero instances + kabaneros := &kabanerov1alpha2.KabaneroList{} + err := r.client.List(context.TODO(), kabaneros, client.InNamespace(r.watchNamespace)) + if err != nil { + log.Error(err, fmt.Sprintf("Could not process namespace event for \"%v\"", a.Meta.GetName())) + return nil + } + + // For each Kabanero instance, if spec.targetNamespaces includes a.meta.name then add a reconcile request. + requests := []reconcile.Request{} + for _, kabanero := range kabaneros.Items { + for _, namespace := range kabanero.Spec.TargetNamespaces { + if namespace == a.Meta.GetName() { + requests = append(requests, reconcile.Request{types.NamespacedName{Name: kabanero.Name, Namespace: kabanero.Namespace}}) + break + } + } + } + + return requests +} + // Determine if requeue is needed or not. // If requeue is required set RequeueAfter to 60 seconds the first time. // After the first time increase RequeueAfter by 60 seconds up to a max of 15 minutes. @@ -233,46 +273,7 @@ func (r *ReconcileKabanero) determineHowToRequeue(ctx context.Context, request r } -// Convert a v1alpha1 Kabanero CR instance, with collection repositories, to v1alpha2 -func (r *ReconcileKabanero) convertTo_v1alpha2(kabInstanceUnstructured *unstructured.Unstructured, reqLogger logr.Logger) { - // First populate a v1alpha1 object from the unstructured - data, err := kabInstanceUnstructured.MarshalJSON() - if err != nil { - reqLogger.Error(err, "Error marshalling unstructured data: ") - return - } - - kabInstanceV1 := &kabanerov1alpha1.Kabanero{} - err = json.Unmarshal(data, kabInstanceV1) - if err != nil { - reqLogger.Error(err, "Error unmarshalling unstructured data to Kabanero v1alpha1: ") - return - } - - // Next populate a v1alpha2 object from the unstructured. We'll keep the common fields. - kabInstanceV2 := &kabanerov1alpha2.Kabanero{} - err = json.Unmarshal(data, kabInstanceV2) - if err != nil { - reqLogger.Error(err, "Error unmarshalling unstructured data to Kabanero v1alpha2: ") - return - } - - // Now convert the collections to stacks - for _, collectionRepoConfig := range kabInstanceV1.Spec.Collections.Repositories { - httpsConfig := kabanerov1alpha2.HttpsProtocolFile{Url: collectionRepoConfig.Url, SkipCertVerification: collectionRepoConfig.SkipCertVerification} - stackRepoConfig := kabanerov1alpha2.RepositoryConfig{Name: collectionRepoConfig.Name, Https: httpsConfig} - // TODO: Pipelines? - kabInstanceV2.Spec.Stacks.Repositories = append(kabInstanceV2.Spec.Stacks.Repositories, stackRepoConfig) - } - // TODO: Triggers? - - // Write the object back. - err = r.client.Update(context.TODO(), kabInstanceV2) - if err != nil { - reqLogger.Error(err, "Error converting to Kabanero v1alpha2: ") - } -} // Reconcile reads that state of the cluster for a Kabanero object and makes changes based on the state read // and what is in the Kabanero.Spec @@ -289,14 +290,13 @@ func (r *ReconcileKabanero) Reconcile(request reconcile.Request) (reconcile.Resu // in the add() method because the client is not started yet (that would have been ideal). operatorContainerImageOp.Do(func() { var err error - operatorContainerImage, err = getOperatorImage(r.client) + operatorContainerImage, err = r.getOperatorImage() if err != nil { log.Error(err, "Could not read the kabanero-operator container image from the pod") } }) - // TODO: Retrieve kabanero as unstructured and see if there is a collection hub defined. If so, - // convert it, update, and retry. + // TODO: Retrieve kabanero as unstructured kabInstanceUnstructured := &unstructured.Unstructured{} kabInstanceUnstructured.SetGroupVersionKind(schema.GroupVersionKind{ Kind: "Kabanero", @@ -316,17 +316,6 @@ func (r *ReconcileKabanero) Reconcile(request reconcile.Request) (reconcile.Resu return reconcile.Result{}, err } - // See about the collection hub... - _, found, err := unstructured.NestedSlice(kabInstanceUnstructured.Object, "spec", "collections", "repositories") - if err != nil { - reqLogger.Error(err, "Unable to parse Kabanero instance for conversion") - } else { - if found { - // Do the conversion - r.convertTo_v1alpha2(kabInstanceUnstructured, reqLogger) - return reconcile.Result{}, nil // Will run again since we changed the object - } - } // Fetch the Kabanero instance instance := &kabanerov1alpha2.Kabanero{} @@ -362,8 +351,12 @@ func (r *ReconcileKabanero) Reconcile(request reconcile.Request) (reconcile.Resu return reconcile.Result{}, err } + // Collections are no longer supported. Remove any objects that were used by + // the collection controller. + cleanupCollectionController(ctx, instance, r.client, reqLogger) + // Wait for the admission controller webhook to be ready before we try - // to deploy the featured collections. + // to deploy the featured stacks. isAdmissionControllerWebhookReady, _ := getAdmissionControllerWebhookStatus(instance, r.client, reqLogger) if isAdmissionControllerWebhookReady == false { processStatus(ctx, request, instance, r.client, reqLogger) @@ -381,14 +374,7 @@ func (r *ReconcileKabanero) Reconcile(request reconcile.Request) (reconcile.Resu } } - // Reconcile the targetNamespaces - err = reconcileTargetNamespaces(ctx, instance, r.client, reqLogger) - if err != nil { - reqLogger.Error(err, "Error reconciling targetNamespaces") - return reconcile.Result{}, err - } - - // Deploy feature collection resources. + // Deploy featured stack resources. err = reconcileFeaturedStacks(ctx, instance, r.client, reqLogger) if err != nil { reqLogger.Error(err, "Error reconciling featured stacks.") @@ -493,12 +479,6 @@ func cleanup(ctx context.Context, k *kabanerov1alpha2.Kabanero, client client.Cl return err } - // Remove the cross-namespace objects that the collection controller uses. - err = cleanupCollectionController(ctx, k, client) - if err != nil { - return err - } - // Remove the cross-namespace objects that the stack controller uses. err = cleanupStackController(ctx, k, client) if err != nil { @@ -516,7 +496,13 @@ func cleanup(ctx context.Context, k *kabanerov1alpha2.Kabanero, client client.Cl if err != nil { return err } - + + // Remove the cross-namespace objects that target namespaces use. + err = cleanupTargetNamespaces(ctx, k, client) + if err != nil { + return err + } + // Cleanup the Serving and their cross-namespace objects err = cleanupServing(k, client, reqLogger) if err != nil { @@ -547,7 +533,6 @@ func processStatus(ctx context.Context, request reconcile.Request, k *kabanerov1 k.Status.KabaneroInstance.Ready = "False" // Gather the status of all resource dependencies. - isCollectionControllerReady, _ := getCollectionControllerStatus(ctx, k, c) isStackControllerReady, _ := getStackControllerStatus(ctx, k, c) isAppsodyReady, _ := getAppsodyStatus(k, c, reqLogger) isTektonReady, _ := getTektonStatus(k, c) @@ -560,10 +545,10 @@ func processStatus(ctx context.Context, request reconcile.Request, k *kabanerov1 isAdmissionControllerWebhookReady, _ := getAdmissionControllerWebhookStatus(k, c, reqLogger) isSsoReady, _ := getSsoStatus(k, c, reqLogger) isGitopsReady, _ := getGitopsStatus(k) + isTargetNamespacesReady, _ := getTargetNamespacesStatus(k) // Set the overall status. - isKabaneroReady := isCollectionControllerReady && - isStackControllerReady && + isKabaneroReady := isStackControllerReady && isTektonReady && isServerlessReady && isCliRouteReady && @@ -574,7 +559,8 @@ func processStatus(ctx context.Context, request reconcile.Request, k *kabanerov1 isEventsReady && isAdmissionControllerWebhookReady && isSsoReady && - isGitopsReady + isGitopsReady && + isTargetNamespacesReady if isKabaneroReady { k.Status.KabaneroInstance.Message = "" @@ -610,3 +596,46 @@ func initializeDependencies(k *kabanerov1alpha2.Kabanero) { // Codeready-workspaces initialization. initializeCRW(k) } + +// Cleanup the collection controller (used in past releases) +func cleanupCollectionController(ctx context.Context, k *kabanerov1alpha2.Kabanero, cl client.Client, reqLogger logr.Logger) { + // Easiest thing to do is probably to load the orchestration and delete everything. + orchestrationPath := "orchestrations/collection-controller/0.1" + templateContext := make(map[string]interface{}) + templateContext["instance"] = "nil" + templateContext["version"] = "nil" + templateContext["image"] = "nil:nil" + templateContext["name"] = "kabanero-" + k.GetNamespace() + "-trigger-rolebinding" + templateContext["kabaneroNamespace"] = k.GetNamespace() + rev := versioning.SoftwareRevision{Version: "nil", OrchestrationPath: orchestrationPath, Identifiers: templateContext} + + transformMap := make(map[string][]mf.Transformer) + transformMap["collection-controller.yaml"] = []mf.Transformer{mf.InjectNamespace(k.GetNamespace())} + transformMap["collection-controller-tekton.yaml"] = []mf.Transformer{} + for yaml, transforms := range transformMap { + f, err := rev.OpenOrchestration(yaml) + if err != nil { + reqLogger.Error(err, fmt.Sprintf("Unable to open %v orchestration", yaml)) + } else { + s, err := renderOrchestration(f, templateContext) + if err != nil { + reqLogger.Error(err, fmt.Sprintf("Unable to render %v orchestration", yaml)) + } else { + m, err := mf.ManifestFrom(mf.Reader(strings.NewReader(s)), mf.UseClient(mfc.NewClient(cl)), mf.UseLogger(reqLogger.WithName("manifestival"))) + if err != nil { + reqLogger.Error(err, fmt.Sprintf("Unable to load manifests for %v orchestration", yaml)) + } else { + mt, err := m.Transform(transforms...) + if err != nil { + reqLogger.Error(err, fmt.Sprintf("Unable to transform manifests for %v orchestration", yaml)) + } else { + err = mt.Delete() + if err != nil { + reqLogger.Error(err, fmt.Sprintf("Unable to delete %v objects", yaml)) + } + } + } + } + } + } +} diff --git a/pkg/controller/kabaneroplatform/targetnamespaces.go b/pkg/controller/kabaneroplatform/targetnamespaces.go index 03175f43..171122ee 100644 --- a/pkg/controller/kabaneroplatform/targetnamespaces.go +++ b/pkg/controller/kabaneroplatform/targetnamespaces.go @@ -1,6 +1,9 @@ package kabaneroplatform import ( "context" + "errors" + "fmt" + "strings" kabanerov1alpha2 "github.com/kabanero-io/kabanero-operator/pkg/apis/kabanero/v1alpha2" @@ -9,122 +12,211 @@ import ( rbacv1 "k8s.io/api/rbac/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "sigs.k8s.io/controller-runtime/pkg/client" + kerrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/util/sets" ) -func reconcileTargetNamespaces(ctx context.Context, k *kabanerov1alpha2.Kabanero, cl client.Client, reqLogger logr.Logger) error { +type targetNamespaceRoleBindingTemplate struct { + name string + saName string + saNamespace string + clusterRoleName string +} - // Rolebinding Template - ownerIsController := true - rolebindingResource := rbacv1.RoleBinding{ +func (info targetNamespaceRoleBindingTemplate) generate(targetNamespace string) rbacv1.RoleBinding { + return rbacv1.RoleBinding{ ObjectMeta: metav1.ObjectMeta{ - Name: "kabanero-pipeline-deploy-rolebinding", - OwnerReferences: []metav1.OwnerReference{ - metav1.OwnerReference{ - APIVersion: k.TypeMeta.APIVersion, - Kind: k.TypeMeta.Kind, - Name: k.ObjectMeta.Name, - UID: k.ObjectMeta.UID, - Controller: &ownerIsController, - }, - }, + Name: info.name, + Namespace: targetNamespace, }, Subjects: []rbacv1.Subject{ rbacv1.Subject{ Kind: "ServiceAccount", - Name: "kabanero-pipeline", - Namespace: "kabanero", + Name: info.saName, + Namespace: info.saNamespace, }, }, RoleRef: rbacv1.RoleRef{ Kind: "ClusterRole", - Name: "kabanero-pipeline-deploy-role", + Name: info.clusterRoleName, APIGroup: "rbac.authorization.k8s.io", }, } +} - - // List of Namespaces we want to bind - targetnamespaceList := k.Spec.TargetNamespaces +// We're going to target the current namespace, and the list of target +// namespaces from the Kabanero CR instance. +func getTargetNamespaces(targetNamespaces []string, defaultNamespace string) []string { + targetnamespaceList := targetNamespaces // If targetNamespaces is empty, default to binding to kabanero if len(targetnamespaceList) == 0 { - targetnamespaceList = append(targetnamespaceList, "kabanero") + targetnamespaceList = append(targetnamespaceList, defaultNamespace) } - /* Get all Rolebindings named kabanero-pipeline-deploy-rolebinding - Structured method only lists RoleBindings in kabanero namespace. Maybe due to client scoping? - - rolebindingList := &rbacv1.RoleBindingList{} - err := cl.List(ctx, rolebindingList, client.MatchingFields{"metadata.name": "kabanero-pipeline-deploy-rolebinding"}) - if err != nil { - return err + return targetnamespaceList +} + +// Create the binding templates +func createBindingTemplates(saNamespace string) []targetNamespaceRoleBindingTemplate{ + return []targetNamespaceRoleBindingTemplate { + { + name: "kabanero-pipeline-deploy-rolebinding", + saName: "kabanero-pipeline", + saNamespace: saNamespace, + clusterRoleName: "kabanero-pipeline-deploy-role", + }, + // TODO: Second role binding for CLI service } - */ +} - // Get all Rolebindings named kabanero-pipeline-deploy-rolebinding - rolebindingList := &unstructured.UnstructuredList{} - rolebindingList.SetGroupVersionKind(schema.GroupVersionKind{ - Group: "rbac.authorization.k8s.io", - Kind: "RoleBindingList", - Version: "v1", - }) - err := cl.List(ctx, rolebindingList, client.MatchingFields{"metadata.name": "kabanero-pipeline-deploy-rolebinding"}) - if err != nil { - return err +func reconcileTargetNamespaces(ctx context.Context, k *kabanerov1alpha2.Kabanero, cl client.Client, reqLogger logr.Logger) error { + + // Owner reference for same-namespace bindings + ownerIsController := true + ownerReference := metav1.OwnerReference{ + APIVersion: k.TypeMeta.APIVersion, + Kind: k.TypeMeta.Kind, + Name: k.ObjectMeta.Name, + UID: k.ObjectMeta.UID, + Controller: &ownerIsController, } - // For each Rolebinding - for _, rolebinding := range rolebindingList.Items { - matchFound := false - // If the Rolebinding namespace is in the targetNamespace list - for i, targetnamespace := range targetnamespaceList { - if rolebinding.GetNamespace() == targetnamespace { - - // Fill in the namespace for the template - desiredRolebinding := rolebindingResource - desiredRolebinding.ObjectMeta.Namespace = targetnamespace - - // Check if the existing Rolebinding matches the desired template, and skip? - // Update may handle this already - - // Apply the rolebinding - cl.Update(ctx, &desiredRolebinding) - - // Remove the namespace from the list of Namespaces remaining to bind - targetnamespaceList[i] = targetnamespaceList[len(targetnamespaceList)-1] // Copy last element to index i. - targetnamespaceList[len(targetnamespaceList)-1] = "" // Erase last element (write zero value). - targetnamespaceList = targetnamespaceList[:len(targetnamespaceList)-1] // Truncate slice. - - matchFound = true - break + // Be sure each requested namespace exists. This will catch namespaces added to the list, as well as + // namespaces that were deleted but not removed from the targetNamespaces list. + specTargetNamespaces := sets.NewString(getTargetNamespaces(k.Spec.TargetNamespaces, k.GetNamespace())...) + var errorNamespaces []string + for namespace, _ := range specTargetNamespaces { + exists, err := namespaceExists(ctx, namespace, cl) + if err != nil { + reqLogger.Error(err, fmt.Sprintf("Could not check status of namespace %v", namespace)) + errorNamespaces = append(errorNamespaces, namespace) + } + if exists == false { + reqLogger.Error(nil, fmt.Sprintf("Target namespace %v does not exist", namespace)) + errorNamespaces = append(errorNamespaces, namespace) + } + } + + for _, namespace := range errorNamespaces { + delete(specTargetNamespaces, namespace) + } + + // TODO: did I do this right? need to process the namespaces, then look at errorNamespaces and + // generate an error message for namespaces that did not exist. Once we have a watch set + // up, that should take care of partially active lists, and the delete case. + + // Compute the new, deleted, and common namespace names + statusTargetNamespaces := sets.NewString(getTargetNamespaces(k.Status.TargetNamespaces.Namespaces, k.GetNamespace())...) + oldNamespaces := statusTargetNamespaces.Difference(specTargetNamespaces) + newNamespaces := specTargetNamespaces.Difference(statusTargetNamespaces) + unchangedNamespaces := specTargetNamespaces.Intersection(statusTargetNamespaces) + + // Create the templates + bindingTemplates := createBindingTemplates(k.GetNamespace()) + + // For removed namespaces, delete the role bindings + for namespace, _ := range oldNamespaces { + for _, bindingTemplate := range bindingTemplates { + template := bindingTemplate.generate(namespace) + reqLogger.Info(fmt.Sprintf("Deleting RoleBinding %v for removed target namespace %v", template.GetName(), template.GetNamespace())) + cl.Delete(ctx, &template) + } + } + + // For new namespaces, create the role bindings + for namespace, _ := range newNamespaces { + for _, bindingTemplate := range bindingTemplates { + template := bindingTemplate.generate(namespace) + if k.GetNamespace() == namespace { + template.ObjectMeta.OwnerReferences = []metav1.OwnerReference{ownerReference} } + reqLogger.Info(fmt.Sprintf("Creating RoleBinding %v for added target namespace %v", template.GetName(), template.GetNamespace())) + cl.Create(ctx, &template) } + } - // If the Rolebinding does not match a targetNamespace, delete - if matchFound == false { - cl.Delete(ctx, &rolebinding) + // For unchanged namespaces, validate the role bindings + for namespace, _ := range unchangedNamespaces { + for _, bindingTemplate := range bindingTemplates { + template := bindingTemplate.generate(namespace) + if k.GetNamespace() == namespace { + template.ObjectMeta.OwnerReferences = []metav1.OwnerReference{ownerReference} + } + reqLogger.Info(fmt.Sprintf("Updating RoleBinding %v for unchanged target namespace %v", template.GetName(), template.GetNamespace())) + cl.Update(ctx, &template) } } - - // For remaining namespaces in the list, Create the Rolebinding - for _, targetnamespace := range targetnamespaceList { - // Check if the namespace exists - namespace := &unstructured.Unstructured{} - namespace.SetGroupVersionKind(schema.GroupVersionKind{ - Group: "", - Kind: "Namespace", - Version: "v1", - }) - err = cl.Get(ctx, client.ObjectKey{Namespace: targetnamespace, Name: targetnamespace,}, namespace) - if err == nil { - // Fill in the namespace for the template and Create - desiredRolebinding := rolebindingResource - desiredRolebinding.ObjectMeta.Namespace = targetnamespace - cl.Create(ctx, &desiredRolebinding) + + // Update the Status to reflect the new target namespaces. + k.Status.TargetNamespaces.Namespaces = nil + for _, namespace := range k.Spec.TargetNamespaces { + isErrorNamespace := false + for _, errorNamespace := range errorNamespaces { + if errorNamespace == namespace { + isErrorNamespace = true + break + } + } + if isErrorNamespace == false { + k.Status.TargetNamespaces.Namespaces = append(k.Status.TargetNamespaces.Namespaces, namespace) } } - + + if len(errorNamespaces) == 0 { + k.Status.TargetNamespaces.Ready = "True" + k.Status.TargetNamespaces.Message = "" + } else { + k.Status.TargetNamespaces.Ready = "False" + k.Status.TargetNamespaces.Message = fmt.Sprintf("The following namespaces could not be processed: %v", strings.Join(errorNamespaces, ",")) + return errors.New(k.Status.TargetNamespaces.Message) + } + + return nil +} + +// Checks if a namespace exists. If an unknown error occurs, return that too. +func namespaceExists(ctx context.Context, inNamespace string, cl client.Client) (bool, error) { + namespace := &unstructured.Unstructured{} + namespace.SetGroupVersionKind(schema.GroupVersionKind{ + Group: "", + Kind: "Namespace", + Version: "v1", + }) + err := cl.Get(ctx, client.ObjectKey{Namespace: inNamespace, Name: inNamespace,}, namespace) + if err == nil { + return true, nil + } + + if kerrors.IsNotFound(err) { + return false, nil + } + + return false, err +} + +// Returns the readiness status of the target namespaces. Presently the status +// is determined as the namespaces are activated. We are just reporting that +// status here. +func getTargetNamespacesStatus(k *kabanerov1alpha2.Kabanero) (bool, error) { + return k.Status.TargetNamespaces.Ready == "True", nil +} + +// Clean up the cross-namespace bindings that we created (deleting the +// Kabanero CR instance won't delete these because cross-namespace owner +// references are not allowed by Kubernetes). +func cleanupTargetNamespaces(ctx context.Context, k *kabanerov1alpha2.Kabanero, cl client.Client) error { + // Create the templates + bindingTemplates := createBindingTemplates(k.GetNamespace()) + + for _, namespace := range getTargetNamespaces(k.Status.TargetNamespaces.Namespaces, k.GetNamespace()) { + for _, bindingTemplate := range bindingTemplates { + template := bindingTemplate.generate(namespace) + cl.Delete(ctx, &template) + } + } + return nil } diff --git a/pkg/controller/kabaneroplatform/targetnamespaces_test.go b/pkg/controller/kabaneroplatform/targetnamespaces_test.go new file mode 100644 index 00000000..7caa736e --- /dev/null +++ b/pkg/controller/kabaneroplatform/targetnamespaces_test.go @@ -0,0 +1,342 @@ +package kabaneroplatform + +import ( + "context" + "errors" + "fmt" + + kabanerov1alpha2 "github.com/kabanero-io/kabanero-operator/pkg/apis/kabanero/v1alpha2" + apierrors "k8s.io/apimachinery/pkg/api/errors" + rbacv1 "k8s.io/api/rbac/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "sigs.k8s.io/controller-runtime/pkg/client" + logf "sigs.k8s.io/controller-runtime/pkg/log" + + "testing" +) + +func init() { + logf.SetLogger(testLogger{}) +} + +var nslog = logf.Log.WithName("targetnamespaces_test") + +// Unit test Kube client +type targetnamespaceTestClient struct { + // Role bindings that the client knows about. + objs map[client.ObjectKey]bool + + // Namespaces that the client knows about + namespaces map[string]bool +} + +func (c targetnamespaceTestClient) Get(ctx context.Context, key client.ObjectKey, obj runtime.Object) error { + fmt.Printf("Received Get() for %v\n", key.Name) + u, ok := obj.(*unstructured.Unstructured) + if !ok { + fmt.Printf("Received invalid target object for get: %v\n", obj) + return errors.New("Get only supports setting into Unstructured") + } + _, ok = c.namespaces[key.Name] + if !ok { + return apierrors.NewNotFound(schema.GroupResource{}, key.Name) + } + u.SetName(key.Name) + u.SetNamespace(key.Namespace) + return nil +} +func (c targetnamespaceTestClient) List(ctx context.Context, list runtime.Object, opts ...client.ListOption) error { + return nil +} +func (c targetnamespaceTestClient) Create(ctx context.Context, obj runtime.Object, opts ...client.CreateOption) error { + binding, ok := obj.(*rbacv1.RoleBinding) + if !ok { + fmt.Printf("Received invalid create: %v\n", obj) + return errors.New("Create only supports RoleBinding") + } + + fmt.Printf("Received Create() for %v\n", binding.GetName()) + key := client.ObjectKey{Name: binding.GetName(), Namespace: binding.GetNamespace()} + _, ok = c.objs[key] + if ok { + fmt.Printf("Receive create object already exists: %v/%v\n", binding.GetNamespace(), binding.GetName()) + return apierrors.NewAlreadyExists(schema.GroupResource{}, binding.GetName()) + } + + c.objs[key] = true + return nil +} +func (c targetnamespaceTestClient) Delete(ctx context.Context, obj runtime.Object, opts ...client.DeleteOption) error { + binding, ok := obj.(*rbacv1.RoleBinding) + if !ok { + fmt.Printf("Received invalid delete: %v\n", obj) + return errors.New("Delete only supports RoleBinding") + } + + fmt.Printf("Received Delete() for %v\n", binding.GetName()) + key := client.ObjectKey{Name: binding.GetName(), Namespace: binding.GetNamespace()} + _, ok = c.objs[key] + if !ok { + fmt.Printf("Received delete for an object that does not exist: %v\n", obj) + return apierrors.NewNotFound(schema.GroupResource{}, binding.GetName()) + } + delete(c.objs, key) + return nil +} +func (c targetnamespaceTestClient) DeleteAllOf(ctx context.Context, obj runtime.Object, opts ...client.DeleteAllOfOption) error { + return errors.New("DeleteAllOf is not supported") +} +func (c targetnamespaceTestClient) Update(ctx context.Context, obj runtime.Object, opts ...client.UpdateOption) error { + binding, ok := obj.(*rbacv1.RoleBinding) + if !ok { + fmt.Printf("Received invalid update: %v\n", obj) + return errors.New("Update only supports RoleBinding") + } + + fmt.Printf("Received Update() for %v\n", binding.GetName()) + key := client.ObjectKey{Name: binding.GetName(), Namespace: binding.GetNamespace()} + _, ok = c.objs[key] + if !ok { + fmt.Printf("Received update for object that does not exist: %v\n", obj) + return apierrors.NewNotFound(schema.GroupResource{}, binding.GetName()) + } + return nil +} +func (c targetnamespaceTestClient) Status() client.StatusWriter { return c } + +func (c targetnamespaceTestClient) Patch(ctx context.Context, obj runtime.Object, patch client.Patch, opts ...client.PatchOption) error { + return errors.New("Patch is not supported") +} + +// Apply the role bindings to an existing namespace +func TestReconcileTargetNamespaces(t *testing.T) { + targetNamespace := "fred" + k := kabanerov1alpha2.Kabanero{ + ObjectMeta: metav1.ObjectMeta{Name: "kabanero", Namespace: "kabanero"}, + Spec: kabanerov1alpha2.KabaneroSpec{ + TargetNamespaces: []string{targetNamespace}, + }, + } + + existingNamespaces := make(map[string]bool) + existingNamespaces[targetNamespace] = true + client := targetnamespaceTestClient{map[client.ObjectKey]bool{}, existingNamespaces} + + err := reconcileTargetNamespaces(context.TODO(), &k, client, nslog) + + if err != nil { + t.Fatal("Returned error: " + err.Error()) + } + + // Make sure the kabanero status was updated with the target namespace + if len(k.Status.TargetNamespaces.Namespaces) != 1 { + t.Fatal(fmt.Sprintf("Kabanero status should have 1 target namespace, but has %v: %v", len(k.Status.TargetNamespaces.Namespaces), k.Status.TargetNamespaces.Namespaces)) + } + + if k.Status.TargetNamespaces.Namespaces[0] != targetNamespace { + t.Fatal(fmt.Sprintf("Kabanero status target namespace should be %v, but is %v", targetNamespace, k.Status.TargetNamespaces.Namespaces[0])) + } + + if k.Status.TargetNamespaces.Ready != "True" { + t.Fatal(fmt.Sprintf("Kabanero target namespace status is not True: %v", k.Status.TargetNamespaces.Ready)) + } + + if len(k.Status.TargetNamespaces.Message) != 0 { + t.Fatal(fmt.Sprintf("Kabanero target namespace status contains an error message: %v", k.Status.TargetNamespaces.Message)) + } + + // Make sure the RoleBinding got added in the correct namespace. + if len(client.objs) != 1 { + t.Fatal(fmt.Sprintf("Should have created one RoleBinding, but created %v: %#v", len(client.objs), client.objs)) + } + + for key, _ := range client.objs { + if key.Namespace != targetNamespace { + t.Fatal(fmt.Sprintf("Should have created RoleBinding in %v namespace, but created in %v namespace", targetNamespace, key.Namespace)) + } + } +} + +// Apply the role bindings to a namespace that does not exist. +func TestReconcileTargetNamespacesNamespaceNotExist(t *testing.T) { + targetNamespace := "fred" + activeNamespace := "kabanero" + k := kabanerov1alpha2.Kabanero{ + ObjectMeta: metav1.ObjectMeta{Name: "kabanero", Namespace: "kabanero"}, + Spec: kabanerov1alpha2.KabaneroSpec{ + TargetNamespaces: []string{targetNamespace}, + }, + Status: kabanerov1alpha2.KabaneroStatus { + TargetNamespaces: kabanerov1alpha2.TargetNamespaceStatus { + Namespaces: []string{activeNamespace}, + Ready: "True", + }, + }, + } + + // Set up pre-existing objects + existingNamespaces := make(map[string]bool) + existingNamespaces[activeNamespace] = true + existingRoleBinding := client.ObjectKey{Name: "kabanero-pipeline-deploy-rolebinding", Namespace: activeNamespace} + existingRoleBindings := make(map[client.ObjectKey]bool) + existingRoleBindings[existingRoleBinding] = true + client := targetnamespaceTestClient{existingRoleBindings, existingNamespaces} + + err := reconcileTargetNamespaces(context.TODO(), &k, client, nslog) + + if err == nil { + t.Fatal("Did not return an error, but should have because namespace does not exist") + } + + // Make sure the kabanero status was not updated with the target namespace, + // since it did not exist. + if len(k.Status.TargetNamespaces.Namespaces) != 0 { + t.Fatal(fmt.Sprintf("Kabanero status should have 0 target namespace, but has %v: %v", len(k.Status.TargetNamespaces.Namespaces), k.Status.TargetNamespaces.Namespaces)) + } + + if k.Status.TargetNamespaces.Ready != "False" { + t.Fatal(fmt.Sprintf("Kabanero target namespace status is not False: %v", k.Status.TargetNamespaces.Ready)) + } + + if len(k.Status.TargetNamespaces.Message) == 0 { + t.Fatal("Kabanero target namespace status contains no error message") + } + + // Make sure the RoleBinding map got cleared. + if len(client.objs) != 0 { + t.Fatal(fmt.Sprintf("Should have created 0 RoleBindings, but created %v: %#v", len(client.objs), client.objs)) + } + + // OK, now create the namespace and make sure things resolve as per normal. + existingNamespaces[targetNamespace] = true + + err = reconcileTargetNamespaces(context.TODO(), &k, client, nslog) + + if err != nil { + t.Fatal("Returned error: " + err.Error()) + } + + // Make sure the kabanero status was updated with the target namespace + if len(k.Status.TargetNamespaces.Namespaces) != 1 { + t.Fatal(fmt.Sprintf("Kabanero status should have 1 target namespace, but has %v: %v", len(k.Status.TargetNamespaces.Namespaces), k.Status.TargetNamespaces.Namespaces)) + } + + if k.Status.TargetNamespaces.Namespaces[0] != targetNamespace { + t.Fatal(fmt.Sprintf("After NS create, Kabanero status target namespace should be %v, but is %v", targetNamespace, k.Status.TargetNamespaces.Namespaces[0])) + } + + if k.Status.TargetNamespaces.Ready != "True" { + t.Fatal(fmt.Sprintf("After NS create, Kabanero target namespace status is not True: %v", k.Status.TargetNamespaces.Ready)) + } + + if len(k.Status.TargetNamespaces.Message) != 0 { + t.Fatal(fmt.Sprintf("After NS create, Kabanero target namespace status contains an error message: %v", k.Status.TargetNamespaces.Message)) + } + + // Make sure the RoleBinding got added in the correct namespace. + if len(client.objs) != 1 { + t.Fatal(fmt.Sprintf("After NS create, should have created one RoleBinding, but created %v: %#v", len(client.objs), client.objs)) + } + + for key, _ := range client.objs { + if key.Namespace != targetNamespace { + t.Fatal(fmt.Sprintf("After NS create, should have created RoleBinding in %v namespace, but created in %v namespace", targetNamespace, key.Namespace)) + } + } +} + +// Apply the role bindings to a namespace that does not exist. +func TestTargetNamespacesGotDeleted(t *testing.T) { + targetNamespace1 := "fred" + targetNamespace2 := "george" + activeNamespace1 := "fred" + activeNamespace2 := "george" + + k := kabanerov1alpha2.Kabanero{ + ObjectMeta: metav1.ObjectMeta{Name: "kabanero", Namespace: "kabanero"}, + Spec: kabanerov1alpha2.KabaneroSpec{ + TargetNamespaces: []string{targetNamespace1, targetNamespace2}, + }, + Status: kabanerov1alpha2.KabaneroStatus { + TargetNamespaces: kabanerov1alpha2.TargetNamespaceStatus { + Namespaces: []string{activeNamespace1, activeNamespace2}, + Ready: "True", + }, + }, + } + + // Set up pre-existing objects + existingNamespaces := make(map[string]bool) + existingNamespaces[activeNamespace1] = true + existingRoleBinding := client.ObjectKey{Name: "kabanero-pipeline-deploy-rolebinding", Namespace: activeNamespace1} + existingRoleBindings := make(map[client.ObjectKey]bool) + existingRoleBindings[existingRoleBinding] = true + client := targetnamespaceTestClient{existingRoleBindings, existingNamespaces} + + err := reconcileTargetNamespaces(context.TODO(), &k, client, nslog) + + if err == nil { + t.Fatal("Did not return an error, but should have because namespace \"george\" does not exist") + } + + // Make sure the kabanero status was not updated with the target namespace, + // since it did not exist. + if len(k.Status.TargetNamespaces.Namespaces) != 1 { + t.Fatal(fmt.Sprintf("Kabanero status should have 1 target namespace, but has %v: %v", len(k.Status.TargetNamespaces.Namespaces), k.Status.TargetNamespaces.Namespaces)) + } + + if k.Status.TargetNamespaces.Namespaces[0] != "fred" { + t.Fatal(fmt.Sprintf("Kabanero status target namespace is not \"fred\", but is %v", k.Status.TargetNamespaces.Namespaces[0])) + } + + if k.Status.TargetNamespaces.Ready != "False" { + t.Fatal(fmt.Sprintf("Kabanero target namespace status is not False: %v", k.Status.TargetNamespaces.Ready)) + } + + if len(k.Status.TargetNamespaces.Message) == 0 { + t.Fatal("Kabanero target namespace status contains no error message") + } + + // Make sure the RoleBinding map got cleared. + if len(client.objs) != 1 { + t.Fatal(fmt.Sprintf("Should have created 1 RoleBindings, but created %v: %#v", len(client.objs), client.objs)) + } +} + +// Test callout from finalizer +func TestCleanupTargetNamespaces(t *testing.T) { + targetNamespace := "fred" + k := kabanerov1alpha2.Kabanero{ + ObjectMeta: metav1.ObjectMeta{Name: "kabanero", Namespace: "kabanero"}, + Spec: kabanerov1alpha2.KabaneroSpec{ + TargetNamespaces: []string{targetNamespace}, + }, + Status: kabanerov1alpha2.KabaneroStatus { + TargetNamespaces: kabanerov1alpha2.TargetNamespaceStatus { + Namespaces: []string{targetNamespace}, + Ready: "True", + }, + }, + } + + // Set up pre-existing objects + existingNamespaces := make(map[string]bool) + existingNamespaces[targetNamespace] = true + existingRoleBinding := client.ObjectKey{Name: "kabanero-pipeline-deploy-rolebinding", Namespace: targetNamespace} + existingRoleBindings := make(map[client.ObjectKey]bool) + existingRoleBindings[existingRoleBinding] = true + client := targetnamespaceTestClient{existingRoleBindings, existingNamespaces} + + err := cleanupTargetNamespaces(context.TODO(), &k, client) + + if err != nil { + t.Fatal("Returned error: " + err.Error()) + } + + if len(existingRoleBindings) != 0 { + t.Fatal(fmt.Sprintf("There were %v bindings left in the map after cleanup: %#v", len(existingRoleBindings), existingRoleBindings)) + } +} diff --git a/pkg/webhook/collection/mutatingwebhook.go b/pkg/webhook/collection/mutatingwebhook.go deleted file mode 100644 index 03054058..00000000 --- a/pkg/webhook/collection/mutatingwebhook.go +++ /dev/null @@ -1,212 +0,0 @@ -package collection - -import ( - "context" - "encoding/json" - "fmt" - "net/http" - - kabanerov1alpha1 "github.com/kabanero-io/kabanero-operator/pkg/apis/kabanero/v1alpha1" - "k8s.io/apimachinery/pkg/api/errors" - - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/manager" - "sigs.k8s.io/controller-runtime/pkg/webhook/admission" -) - -// BuildMutatingWebhook builds the webhook for the manager to register -func BuildMutatingWebhook(mgr *manager.Manager) *admission.Webhook { - return &admission.Webhook{Handler: &collectionMutator{}} -} - -// collectionMutator mutates collections -type collectionMutator struct { - client client.Client - decoder *admission.Decoder -} - -// Implement admission.Handler so the controller can handle admission request. -// This no-op assignment ensures that the struct implements the interface. -var _ admission.Handler = &collectionMutator{} - -// collectionMutator verifies that the collection version singleton and array -// are not in conflict. -func (a *collectionMutator) Handle(ctx context.Context, req admission.Request) admission.Response { - collection := &kabanerov1alpha1.Collection{} - - err := a.decoder.Decode(req, collection) - if err != nil { - return admission.Errored(http.StatusBadRequest, err) - } - - err = a.mutateCollectionFn(ctx, collection) - if err != nil { - return admission.Errored(http.StatusInternalServerError, err) - } - - marshaledCollection, err := json.Marshal(collection) - if err != nil { - return admission.Errored(http.StatusInternalServerError, err) - } - - return admission.PatchResponseFromRaw(req.Object.Raw, marshaledCollection) -} - -// mutateCollectionFn updates collection version entries. -func (a *collectionMutator) mutateCollectionFn(ctx context.Context, collection *kabanerov1alpha1.Collection) error { - // Get the currently installed collection. - current := &kabanerov1alpha1.Collection{} - err := a.client.Get(ctx, client.ObjectKey{ - Name: collection.Name, - Namespace: collection.Namespace}, current) - if err != nil { - if !errors.IsNotFound(err) { - return fmt.Errorf("Unable to retrieve installed collection object. Error: %v", err) - } - } - - err = processUpdate(current, collection) - - return err -} - -// Processes the needed changes when a collection update takes place. More precisely, it makes sure that -// that the values in new collection.Spec.Version[0] match the ones in new collection.Spec prior to processing the udpate. -func processUpdate(current *kabanerov1alpha1.Collection, new *kabanerov1alpha1.Collection) error { - // New collection.Spec.versions[0] is defined. - if len(new.Spec.Versions) > 0 { - // New collection.Spec and new collection.Spec.Versions[0] values are the same. - if areMixedVersionModelCollectionsEqual(new, new) { - // Make a basic check to see if new collection.Spec.Versions[0] and new collection.Spec values are the same because they are cleared. - if areSpecVersionValuesCleared(new) && areSpecVersions0ValuesCleared(new) { - return fmt.Errorf("The new collection.Spec and collection.Spec.versions[0] were not specified. New Collection: %v. Current collection: %v", new, current) - } - - return nil - } - - // New collection.Spec != new collection.Spec.Versions[0]. - // Current collection.Spec == new collection.Spec. - if areSpecVersionValuesEqual(current, new) { - // Current collection.Spec != New collection.Spec.Versions[0]. - if !areMixedVersionModelCollectionsEqual(current, new) { - // New Collection.Spec.Versions[0] values were cleared. Copy collection.Spec to collection.Spec.Versions[0]. - if areSpecVersions0ValuesCleared(new) { - new.Spec.Versions[0].Version = new.Spec.Version - new.Spec.Versions[0].RepositoryUrl = new.Spec.RepositoryUrl - new.Spec.Versions[0].DesiredState = new.Spec.DesiredState - return nil - } - - // Update new collection.Spec with values with collection.Spec.Versions[0] values. - new.Spec.Version = new.Spec.Versions[0].Version - new.Spec.RepositoryUrl = new.Spec.Versions[0].RepositoryUrl - new.Spec.DesiredState = new.Spec.Versions[0].DesiredState - return nil - } - - // No updates. - return nil - } - - // New collection.Spec != new collection.Spec.Versions[0]. - // Current collection.Spec != new collection.Spec. - // Current collection.Spec == new collection.Spec.Versions[0]. - if areMixedVersionModelCollectionsEqual(current, new) { - // New Collection.Spec values were cleared. Copy collection.Spec.Versions[0] to collection.Spec - if areSpecVersionValuesCleared(new) { - new.Spec.Version = new.Spec.Versions[0].Version - new.Spec.RepositoryUrl = new.Spec.Versions[0].RepositoryUrl - new.Spec.DesiredState = new.Spec.Versions[0].DesiredState - return nil - } - // Update new collection.Spec.Versions[0] with new collection.Spec values. - new.Spec.Versions[0].Version = new.Spec.Version - new.Spec.Versions[0].RepositoryUrl = new.Spec.RepositoryUrl - new.Spec.Versions[0].DesiredState = new.Spec.DesiredState - return nil - } - - // New collection.Spec != new collection.Spec.Versions[0]. - // Current collection.Spec != new collection.Spec. - // Current collection.Spec != new collection.Spec.Versions[0]. - // Current collection.Spec.Versions[0] = new collection.Spec.Versions[0]. - if len(current.Spec.Versions) > 0 && areSpecVersions0ValuesEqual(current, new) { - // Update new collection.Spec.Versions[0] with new collection.Spec values - new.Spec.Versions[0].Version = new.Spec.Version - new.Spec.Versions[0].RepositoryUrl = new.Spec.RepositoryUrl - new.Spec.Versions[0].DesiredState = new.Spec.DesiredState - return nil - } - - return fmt.Errorf("current collection.Spec, current, collection.Spec.Versions[0], new collection.Spec, and new collection.Spec.versions[0] have different values. Invalid update. New Collection: %v. Current collection: %v", new, current) - } - - // New collection.Spec.Versions[0] was NOT defined. - // Collection.Spec values were cleared. - if areSpecVersionValuesCleared(new) { - return fmt.Errorf("The new collection information under Spec and Spec.versions[0] were. New Collection: %v. Current collection: %v", new, current) - } - - // New collection.Spec.Versions[0] was NOT defined. - // Collection.Spec values were NOT cleared. - // Copy new collection.Spec to collection.Spec.Versions[0]. - versionsEntry := kabanerov1alpha1.CollectionVersion{ - Version: new.Spec.Version, - RepositoryUrl: new.Spec.RepositoryUrl, - DesiredState: new.Spec.DesiredState, - } - new.Spec.Versions = append(new.Spec.Versions, versionsEntry) - if len(new.Spec.Versions) != 1 { - return fmt.Errorf("Updated Spec.versions[] length of %v was not expected. Expected length: 1. New collection: %v", len(new.Spec.Versions), new) - } - - return nil -} - -// Returns true if all version related values in collection.Spec have a length of zero. Returns false otherwise. -func areSpecVersionValuesCleared(collection *kabanerov1alpha1.Collection) bool { - return (len(collection.Spec.Version) == 0 && - len(collection.Spec.RepositoryUrl) == 0 && - len(collection.Spec.DesiredState) == 0) -} - -// Returns true if all values in collection.Spec.Versions[0] have a length of zero. Returns false otherwise. -func areSpecVersions0ValuesCleared(collection *kabanerov1alpha1.Collection) bool { - return (len(collection.Spec.Versions[0].Version) == 0 && - len(collection.Spec.Versions[0].RepositoryUrl) == 0 && - len(collection.Spec.Versions[0].DesiredState) == 0) -} - -// Returns true if the version related values in the two input collection entries are the same. Returns false otherwise. -func areSpecVersionValuesEqual(this *kabanerov1alpha1.Collection, that *kabanerov1alpha1.Collection) bool { - return this.Spec.Version == that.Spec.Version && - this.Spec.RepositoryUrl == that.Spec.RepositoryUrl && - this.Spec.DesiredState == that.Spec.DesiredState -} - -// Returns true if collection.Spec.versions[0] values in the two input collection entries are the same. Returns false otherwise. -func areSpecVersions0ValuesEqual(this *kabanerov1alpha1.Collection, that *kabanerov1alpha1.Collection) bool { - return this.Spec.Versions[0].Version == that.Spec.Versions[0].Version && - this.Spec.Versions[0].RepositoryUrl == that.Spec.Versions[0].RepositoryUrl && - this.Spec.Versions[0].DesiredState == that.Spec.Versions[0].DesiredState -} - -// Returns true if version related values in input collection.Spec and input collection.Spec.Versions[0] are the same. Returns false otherwise. -func areMixedVersionModelCollectionsEqual(this *kabanerov1alpha1.Collection, that *kabanerov1alpha1.Collection) bool { - return this.Spec.Version == that.Spec.Versions[0].Version && - this.Spec.RepositoryUrl == that.Spec.Versions[0].RepositoryUrl && - this.Spec.DesiredState == that.Spec.Versions[0].DesiredState -} - -// InjectClient injects the client. -func (v *collectionMutator) InjectClient(c client.Client) error { - v.client = c - return nil -} - -// InjectDecoder injects the decoder. -func (v *collectionMutator) InjectDecoder(d *admission.Decoder) error { - v.decoder = d - return nil -} diff --git a/pkg/webhook/collection/mutatingwebhook_test.go b/pkg/webhook/collection/mutatingwebhook_test.go deleted file mode 100644 index 74fa85bf..00000000 --- a/pkg/webhook/collection/mutatingwebhook_test.go +++ /dev/null @@ -1,401 +0,0 @@ -package collection - -import ( - "testing" - - kabanerov1alpha1 "github.com/kabanero-io/kabanero-operator/pkg/apis/kabanero/v1alpha1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -// Base collection with no collection.Spec.Versions[] defined. -var mutatingBaseCollection kabanerov1alpha1.Collection = kabanerov1alpha1.Collection{ - ObjectMeta: metav1.ObjectMeta{ - Name: "java-microprofile", - Namespace: "Kabanero", - UID: "1", - OwnerReferences: []metav1.OwnerReference{ - metav1.OwnerReference{ - APIVersion: "a/1", - Kind: "Kabanero", - Name: "kabanero", - UID: "1", - }, - }, - }, - Spec: kabanerov1alpha1.CollectionSpec{ - Name: "java-microprofile", - DesiredState: "active", - RepositoryUrl: "https://github.com/some/collection/kabanero-index.yaml", - Version: "1.2.3", - }, - Status: kabanerov1alpha1.CollectionStatus{ - ActiveVersion: "1.2.3", - ActiveLocation: "https://github.com/some/collection/kabanero-index.yaml", - ActivePipelines: []kabanerov1alpha1.PipelineStatus{}, - Status: "active", - Images: []kabanerov1alpha1.Image{{ - Id: "java-microprofile", - Image: "kabanero/java-microprofile:1.2.3"}}, - }, -} - -// Base collection with no collection.Spec.Versions[0] defined. -var mutatingBaseCollectionVersions kabanerov1alpha1.Collection = kabanerov1alpha1.Collection{ - ObjectMeta: metav1.ObjectMeta{ - Name: "java-microprofile", - Namespace: "Kabanero", - UID: "1", - OwnerReferences: []metav1.OwnerReference{ - metav1.OwnerReference{ - APIVersion: "a/1", - Kind: "Kabanero", - Name: "kabanero", - UID: "1", - }, - }, - }, - Spec: kabanerov1alpha1.CollectionSpec{ - Name: "java-microprofile", - DesiredState: "active", - RepositoryUrl: "https://github.com/some/collection/kabanero-index.yaml", - Version: "1.2.3", - Versions: []kabanerov1alpha1.CollectionVersion{{ - DesiredState: "active", - RepositoryUrl: "https://github.com/some/collection/kabanero-index.yaml", - Version: "1.2.3", - }}, - }, - Status: kabanerov1alpha1.CollectionStatus{ - ActiveVersion: "1.2.3", - ActiveLocation: "https://github.com/some/collection/kabanero-index.yaml", - ActivePipelines: []kabanerov1alpha1.PipelineStatus{}, - Status: "active", - Images: []kabanerov1alpha1.Image{{ - Id: "java-microprofile", - Image: "kabanero/java-microprofile:1.2.3"}}, - Versions: []kabanerov1alpha1.CollectionVersionStatus{{ - Version: "1.2.3", - Location: "https://github.com/some/collection/kabanero-index.yaml", - Pipelines: []kabanerov1alpha1.PipelineStatus{}, - Status: "active", - Images: []kabanerov1alpha1.Image{{ - Id: "java-microprofile", - Image: "kabanero/java-microprofile:1.2.3"}}, - }}, - }, -} - -// Current collection.Spec = New collection.Spec. -// Current collection.Spec.Versions[] (empty) = and New collection.Spec.Versions[] (empty). -// Expectation: collection.Spec.versions[0] should be added with the contents of collection.Spec data. -func Test1(t *testing.T) { - newCollection := mutatingBaseCollection.DeepCopy() - err := processUpdate(&mutatingBaseCollection, newCollection) - if err != nil { - t.Fatal("Unexpected error during mutation.", err) - } - - expectedversion0 := kabanerov1alpha1.CollectionVersion{ - RepositoryUrl: "https://github.com/some/collection/kabanero-index.yaml", - Version: "1.2.3", - DesiredState: "active"} - - //fmt.Println("Here is the base collection: ", mutatingBaseCollection) - //fmt.Println("Here is the new collection: ", newCollection) - - if newCollection.Spec.Versions[0] != expectedversion0 { - t.Fatal("Mutated versions[0] does not match expected versions[0] values. Mutated versions[0]: ", newCollection.Spec.Versions[0], "Expected versions[0]: ", expectedversion0) - } - -} - -// Current collection.Spec != New collection.Spec. -// Current collection.Spec.Versions[] (empty) = and New collection.Spec.Versions[] (empty). -// Expectation: collection.Spec.versions[0] should be added with the contents of collection.Spec data. -func Test2(t *testing.T) { - newCollection := mutatingBaseCollection.DeepCopy() - newCollection.Spec.RepositoryUrl = "https://github.com/some/collection/alternate-kabanero-index.yaml" - newCollection.Spec.Version = "4.5.6" - err := processUpdate(&mutatingBaseCollection, newCollection) - if err != nil { - t.Fatal("Unexpected error during mutation.", err) - } - - expectedversion0 := kabanerov1alpha1.CollectionVersion{ - RepositoryUrl: "https://github.com/some/collection/alternate-kabanero-index.yaml", - Version: "4.5.6", - DesiredState: "active"} - - if newCollection.Spec.Versions[0] != expectedversion0 { - t.Fatal("Mutated versions[0] does not match expected versions[0] values. Mutated versions[0]: ", newCollection.Spec.Versions[0], "Expected versions[0]: ", expectedversion0) - } -} - -// Current collection.Spec != New collection.Spec. -// Current collection.Spec.Versions[] (empty) = and New collection.Spec.Versions[] (empty). -// Expectation: An error condition should be reported. -func Test3(t *testing.T) { - newCollection := mutatingBaseCollection.DeepCopy() - newCollection.Spec.RepositoryUrl = "" - newCollection.Spec.Version = "" - newCollection.Spec.DesiredState = "" - err := processUpdate(&mutatingBaseCollection, newCollection) - if err == nil { - t.Fatal("An error condition should have been reported. Spec and Spec.versions were not properly defined.", err) - } -} - -// Current collection.Spec != New collection.Spec. -// Current collection.Spec == New collection.Spec.versions[0] -// Current collection.Spec.Versions[] (empty). -// Expectation: New collection.Spec should have been copied to New collection.Spec.versions[0]. -func Test4(t *testing.T) { - newCollection := mutatingBaseCollectionVersions.DeepCopy() - newCollection.Spec.RepositoryUrl = "https://github.com/some/collection/alternate-kabanero-index.yaml" - newCollection.Spec.Version = "4.5.6" - newCollection.Spec.DesiredState = "inactive" - err := processUpdate(&mutatingBaseCollection, newCollection) - if err != nil { - t.Fatal("Unexpected error during mutation.", err) - } - - expectedversion0 := kabanerov1alpha1.CollectionVersion{ - RepositoryUrl: "https://github.com/some/collection/alternate-kabanero-index.yaml", - Version: "4.5.6", - DesiredState: "inactive"} - - if newCollection.Spec.Versions[0] != expectedversion0 { - t.Fatal("New collection.Spec.Versions[0] values do not match expected collection.Spec.Versions[0] values. New versions[0]: ", newCollection.Spec.Versions[0], "Expected versions[0]: ", expectedversion0) - } -} - -// Current collection.Spec == New collection.Spec. -// Current collection.Spec != New collection.Spec.versions[0] -// Current collection.Spec.Versions[] (empty). -// Expectation: New collection.Spec.versions[0] values should have been copied to New collection.Spec. -func Test5(t *testing.T) { - newCollection := mutatingBaseCollectionVersions.DeepCopy() - newCollection.Spec.Versions[0].RepositoryUrl = "https://github.com/some/collection/alternate-kabanero-index.yaml" - newCollection.Spec.Versions[0].Version = "4.5.6" - newCollection.Spec.Versions[0].DesiredState = "inactive" - err := processUpdate(&mutatingBaseCollection, newCollection) - if err != nil { - t.Fatal("Unexpected error during mutation.", err) - } - - if newCollection.Spec.RepositoryUrl != "https://github.com/some/collection/alternate-kabanero-index.yaml" { - t.Fatal("New collection.Spec.RepositoryUrl values do not match expected value of https://github.com/some/collection/alternate-kabanero-index.yaml. RepositoryUrl found: ", newCollection.Spec.RepositoryUrl) - } - if newCollection.Spec.Version != "4.5.6" { - t.Fatal("New collection.Spec.Version values do not match expected value of 4.5.6. Version found: ", newCollection.Spec.Version) - } - if newCollection.Spec.DesiredState != "inactive" { - t.Fatal("New collection.Spec.DesiredState values do not match expected value of inactive. DesiredStateme found: ", newCollection.Spec.DesiredState) - } -} - -// Current collection.Spec != New collection.Spec. -// Current collection.Spec != New collection.Spec.versions[0] -// Current collection.Spec.Versions[] (empty). -// Expectation: An error condition should be reported. -func Test6(t *testing.T) { - newCollection := mutatingBaseCollectionVersions.DeepCopy() - newCollection.Spec.RepositoryUrl = "https://github.com/some/collection/other-alternate-kabanero-index.yaml" - newCollection.Spec.Version = "7.8.9" - newCollection.Spec.DesiredState = "active" - newCollection.Spec.Versions[0].RepositoryUrl = "https://github.com/some/collection/alternate-kabanero-index.yaml" - newCollection.Spec.Versions[0].Version = "4.5.6" - newCollection.Spec.Versions[0].DesiredState = "inactive" - err := processUpdate(&mutatingBaseCollection, newCollection) - if err == nil { - t.Fatal("An error condition should have been reported. New collection.Spec and new collection.Spec.versions[0] contain conflicting data.", err) - } -} - -// Current collection.Spec == New collection.Spec. -// Current collection.Spec == New collection.Spec.versions[0] -// Current collection.Spec.Versions[] (empty). -// Expectation: No change should have taken place. Everything should still be the same. -func Test7(t *testing.T) { - newCollection := mutatingBaseCollectionVersions.DeepCopy() - err := processUpdate(&mutatingBaseCollection, newCollection) - if err != nil { - t.Fatal("Unexpected error during mutation.", err) - } - - expectedversion0 := kabanerov1alpha1.CollectionVersion{ - DesiredState: "active", - RepositoryUrl: "https://github.com/some/collection/kabanero-index.yaml", - Version: "1.2.3"} - - if newCollection.Spec.Versions[0] != expectedversion0 { - t.Fatal("New collection.Spec.Versions[0] values do not match expected collection.Spec.Versions[0] values. New versions[0]: ", newCollection.Spec.Versions[0], "Expected versions[0]: ", expectedversion0) - } - - if newCollection.Spec.RepositoryUrl != "https://github.com/some/collection/kabanero-index.yaml" { - t.Fatal("New collection.Spec.RepositoryUrl values do not match expected value of https://github.com/some/collection/kabanero-index.yaml. RepositoryUrl found: ", newCollection.Spec.RepositoryUrl) - } - if newCollection.Spec.Version != "1.2.3" { - t.Fatal("New collection.Spec.Version values do not match expected value of 1.2.3. Version found: ", newCollection.Spec.Version) - } - if newCollection.Spec.DesiredState != "active" { - t.Fatal("New collection.Spec.DesiredState values do not match expected value of active. DesiredStateme found: ", newCollection.Spec.DesiredState) - } -} - -// Current collection.Spec == New collection.Spec. -// Current collection.Spec != New collection.Spec.versions[0] because collection.Spec.versions[0] values were cleared. -// Current collection.Spec.Versions[] (empty). -// Expectation: New collection.Spec values should have been copied to New collection.Spec.versions[0]. The same behavior -// should be applied as the case where collection.Spec.versions is empty. -func Test8(t *testing.T) { - newCollection := mutatingBaseCollectionVersions.DeepCopy() - newCollection.Spec.Versions[0].RepositoryUrl = "" - newCollection.Spec.Versions[0].Version = "" - newCollection.Spec.Versions[0].DesiredState = "" - - err := processUpdate(&mutatingBaseCollection, newCollection) - if err != nil { - t.Fatal("Unexpected error during mutation.", err) - } - - expectedversion0 := kabanerov1alpha1.CollectionVersion{ - DesiredState: "active", - RepositoryUrl: "https://github.com/some/collection/kabanero-index.yaml", - Version: "1.2.3"} - - if newCollection.Spec.Versions[0] != expectedversion0 { - t.Fatal("New collection.Spec.Versions[0] values do not match expected collection.Spec.Versions[0] values. New versions[0]: ", newCollection.Spec.Versions[0], "Expected versions[0]: ", expectedversion0) - } -} - -// New collection.Spec.Versions[0] == New collection.Spec. -// New collection.Spec.Versions[0] has all values cleared == New collection.Spec has all values cleared. -// Expectation: This is an invalid case. -func Test9(t *testing.T) { - newCollection := mutatingBaseCollectionVersions.DeepCopy() - newCollection.Spec.RepositoryUrl = "" - newCollection.Spec.Version = "" - newCollection.Spec.DesiredState = "" - newCollection.Spec.Versions[0].RepositoryUrl = "" - newCollection.Spec.Versions[0].Version = "" - newCollection.Spec.Versions[0].DesiredState = "" - - err := processUpdate(&mutatingBaseCollection, newCollection) - if err == nil { - t.Fatal("An error condition should have been reported. New collection.Spec and new collection.Spec.versions[0] contain empty fields.", err) - } -} - -// New colleciton.Spec != new collection.Spec.Versions[0]. -// Current colleciton.Spec != new collection.Spec. -// Current collection.Spec != new collection.Spec.Versions[0]. -// Current collection.Spec.Versions[0] = new collection.Spec.Versions[0]. -// Expectation: new collection.Spec values should be copied to new collection.Spec.Versions[0] -func Test10(t *testing.T) { - custommutatingBaseCollection := mutatingBaseCollectionVersions.DeepCopy() - newCollection := mutatingBaseCollectionVersions.DeepCopy() - custommutatingBaseCollection.Spec.Version = "1.2.4" - newCollection.Spec.Version = "1.2.5" - custommutatingBaseCollection.Spec.Versions[0].Version = "2.0.0" - newCollection.Spec.Versions[0].Version = "2.0.0" - - err := processUpdate(custommutatingBaseCollection, newCollection) - if err != nil { - t.Fatal("Unexpected error during mutation.", err) - } - - expectedversion0 := kabanerov1alpha1.CollectionVersion{ - DesiredState: "active", - RepositoryUrl: "https://github.com/some/collection/kabanero-index.yaml", - Version: "1.2.5"} - - if newCollection.Spec.Versions[0] != expectedversion0 { - t.Fatal("New collection.Spec.Versions[0] values do not match expected collection.Spec.Versions[0] values. New versions[0]: ", newCollection.Spec.Versions[0], "Expected versions[0]: ", expectedversion0) - } -} - -// New colleciton.Spec != new collection.Spec.Versions[0]. -// Current colleciton.Spec == new collection.Spec. -// Current collection.Spec != new collection.Spec.Versions[0]. -// Current collection.Spec.Versions[0] != new collection.Spec.Versions[0]. -// Expectation: new collection.Spec.Versions[0] values should be copied to new collection.Spec. -func Test11(t *testing.T) { - custommutatingBaseCollection := mutatingBaseCollectionVersions.DeepCopy() - newCollection := mutatingBaseCollectionVersions.DeepCopy() - custommutatingBaseCollection.Spec.Version = "1.2.4" - newCollection.Spec.Version = "1.2.4" - custommutatingBaseCollection.Spec.Versions[0].Version = "2.0.0" - newCollection.Spec.Versions[0].Version = "2.0.1" - - err := processUpdate(custommutatingBaseCollection, newCollection) - if err != nil { - t.Fatal("Unexpected error during mutation.", err) - } - - if newCollection.Spec.RepositoryUrl != "https://github.com/some/collection/kabanero-index.yaml" { - t.Fatal("New collection.Spec.RepositoryUrl values do not match expected value of https://github.com/some/collection/kabanero-index.yaml. RepositoryUrl found: ", newCollection.Spec.RepositoryUrl) - } - if newCollection.Spec.Version != "2.0.1" { - t.Fatal("New collection.Spec.Version values do not match expected value of 1.2.3. Version found: ", newCollection.Spec.Version) - } - if newCollection.Spec.DesiredState != "active" { - t.Fatal("New collection.Spec.DesiredState values do not match expected value of active. DesiredStateme found: ", newCollection.Spec.DesiredState) - } -} - -// New colleciton.Spec == new collection.Spec.Versions[0]. -// Current colleciton.Spec != new collection.Spec. -// Current collection.Spec.Versions[0] == new collection.Spec.Versions[0]. -// Expectation: No updates are expected. -func Test12(t *testing.T) { - custommutatingBaseCollection := mutatingBaseCollectionVersions.DeepCopy() - newCollection := mutatingBaseCollectionVersions.DeepCopy() - custommutatingBaseCollection.Spec.Version = "1.2.3" - newCollection.Spec.Version = "1.2.4" - custommutatingBaseCollection.Spec.Versions[0].Version = "1.2.4" - newCollection.Spec.Versions[0].Version = "1.2.4" - - err := processUpdate(custommutatingBaseCollection, newCollection) - if err != nil { - t.Fatal("Unexpected error during mutation.", err) - } - - expectedversion0 := kabanerov1alpha1.CollectionVersion{ - DesiredState: "active", - RepositoryUrl: "https://github.com/some/collection/kabanero-index.yaml", - Version: "1.2.4"} - - if newCollection.Spec.Versions[0] != expectedversion0 { - t.Fatal("New collection.Spec.Versions[0] values do not match expected collection.Spec.Versions[0] values. New versions[0]: ", newCollection.Spec.Versions[0], "Expected versions[0]: ", expectedversion0) - } - - if newCollection.Spec.RepositoryUrl != "https://github.com/some/collection/kabanero-index.yaml" { - t.Fatal("New collection.Spec.RepositoryUrl values do not match expected value of https://github.com/some/collection/kabanero-index.yaml. RepositoryUrl found: ", newCollection.Spec.RepositoryUrl) - } - if newCollection.Spec.Version != "1.2.4" { - t.Fatal("New collection.Spec.Version values do not match expected value of 1.2.3. Version found: ", newCollection.Spec.Version) - } - if newCollection.Spec.DesiredState != "active" { - t.Fatal("New collection.Spec.DesiredState values do not match expected value of active. DesiredStateme found: ", newCollection.Spec.DesiredState) - } -} - -// New colleciton.Spec != new collection.Spec.Versions[0]. -// Current colleciton.Spec != new collection.Spec. -// Current collection.Spec != new collection.Spec.Versions[0]. -// Current collection.Spec.Versions[0] = new collection.Spec.Versions[0]. -// Expectation: This is an invalid case and is unrecoverable. New and current version values are different. -// The instance may need to be re-deployed. -func Test13(t *testing.T) { - custommutatingBaseCollection := mutatingBaseCollectionVersions.DeepCopy() - newCollection := mutatingBaseCollectionVersions.DeepCopy() - custommutatingBaseCollection.Spec.Version = "1.2.4" - newCollection.Spec.Version = "1.2.5" - custommutatingBaseCollection.Spec.Versions[0].Version = "2.0.0" - newCollection.Spec.Versions[0].Version = "2.0.1" - err := processUpdate(custommutatingBaseCollection, newCollection) - if err == nil { - t.Fatal("An error condition should have been reported. Current and new collection.Spec and current and new collection.Spec.versions[0] have different values.", err) - } -} diff --git a/pkg/webhook/collection/validatingwebhook.go b/pkg/webhook/collection/validatingwebhook.go deleted file mode 100644 index 7871727b..00000000 --- a/pkg/webhook/collection/validatingwebhook.go +++ /dev/null @@ -1,73 +0,0 @@ -package collection - -// The controller-runtime example webhook (v0.10) was used to build this -// webhook implementation. - -import ( - "context" - "fmt" - "net/http" - - kabanerov1alpha1 "github.com/kabanero-io/kabanero-operator/pkg/apis/kabanero/v1alpha1" - - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/manager" - "sigs.k8s.io/controller-runtime/pkg/webhook/admission" -) - -// BuildValidatingWebhook builds the webhook for the manager to register -func BuildValidatingWebhook(mgr *manager.Manager) *admission.Webhook { - return &admission.Webhook{Handler: &collectionValidator{}} -} - -// collectionValidator validates Collections -type collectionValidator struct { - client client.Client - decoder *admission.Decoder -} - -// Implement admission.Handler so the controller can handle admission request. -// This no-op assignment ensures that the struct implements the interface. -var _ admission.Handler = &collectionValidator{} - -// collectionValidator admits a collection if it passes validity checks -func (v *collectionValidator) Handle(ctx context.Context, req admission.Request) admission.Response { - collection := &kabanerov1alpha1.Collection{} - - err := v.decoder.Decode(req, collection) - if err != nil { - return admission.Errored(http.StatusBadRequest, err) - } - - allowed, reason, err := v.validateCollectionFn(ctx, collection) - if err != nil { - return admission.Errored(http.StatusInternalServerError, err) - } - return admission.ValidationResponse(allowed, reason) -} - -func (v *collectionValidator) validateCollectionFn(ctx context.Context, collection *kabanerov1alpha1.Collection) (bool, string, error) { - allowed := collection.Spec.Version == collection.Spec.Versions[0].Version && - collection.Spec.RepositoryUrl == collection.Spec.Versions[0].RepositoryUrl && - collection.Spec.DesiredState == collection.Spec.Versions[0].DesiredState - - if !allowed { - reason := fmt.Sprintf("Single version collection model values do not match multiple collection model values. collection: %v", collection) - err := fmt.Errorf(reason) - return false, reason, err - } - - return true, "", nil -} - -// InjectClient injects the client. -func (v *collectionValidator) InjectClient(c client.Client) error { - v.client = c - return nil -} - -// InjectDecoder injects the decoder. -func (v *collectionValidator) InjectDecoder(d *admission.Decoder) error { - v.decoder = d - return nil -} diff --git a/pkg/webhook/collection/validatingwebhook_test.go b/pkg/webhook/collection/validatingwebhook_test.go deleted file mode 100644 index 68b50433..00000000 --- a/pkg/webhook/collection/validatingwebhook_test.go +++ /dev/null @@ -1,94 +0,0 @@ -package collection - -import ( - "testing" - - kabanerov1alpha1 "github.com/kabanero-io/kabanero-operator/pkg/apis/kabanero/v1alpha1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -// Base collection with collection.Spec.Versions[0] defined. -var validatingCollectionVersions kabanerov1alpha1.Collection = kabanerov1alpha1.Collection{ - ObjectMeta: metav1.ObjectMeta{ - Name: "java-microprofile", - Namespace: "Kabanero", - UID: "1", - OwnerReferences: []metav1.OwnerReference{ - metav1.OwnerReference{ - APIVersion: "a/1", - Kind: "Kabanero", - Name: "kabanero", - UID: "1", - }, - }, - }, - Spec: kabanerov1alpha1.CollectionSpec{ - Name: "java-microprofile", - DesiredState: "active", - RepositoryUrl: "https://github.com/some/collection/kabanero-index.yaml", - Version: "1.2.3", - Versions: []kabanerov1alpha1.CollectionVersion{{ - DesiredState: "active", - RepositoryUrl: "https://github.com/some/collection/kabanero-index.yaml", - Version: "1.2.3", - }}, - }, - Status: kabanerov1alpha1.CollectionStatus{ - ActiveVersion: "1.2.3", - ActiveLocation: "https://github.com/some/collection/kabanero-index.yaml", - ActivePipelines: []kabanerov1alpha1.PipelineStatus{}, - Status: "active", - Images: []kabanerov1alpha1.Image{{ - Id: "java-microprofile", - Image: "kabanero/java-microprofile:1.2.3"}}, - Versions: []kabanerov1alpha1.CollectionVersionStatus{{ - Version: "1.2.3", - Location: "https://github.com/some/collection/kabanero-index.yaml", - Pipelines: []kabanerov1alpha1.PipelineStatus{}, - Status: "active", - Images: []kabanerov1alpha1.Image{{ - Id: "java-microprofile", - Image: "kabanero/java-microprofile:1.2.3"}}, - }}, - }, -} - -// Collection.Spec = New collection.Spec.Versions -func validationSuccess(t *testing.T) { - newCollection := validatingCollectionVersions.DeepCopy() - cv := collectionValidator{} - allowed, msg, err := cv.validateCollectionFn(nil, newCollection) - - if !allowed { - t.Fatal("Validation should have passed. The validation was not allowed") - } - - if len(msg) != 0 { - t.Fatal("Validation succeeded. A message was not expected. Message: ", msg) - } - - if err != nil { - t.Fatal("Validation succeeded. An error was not expected. Error: ", err) - } -} - -// Collection.Spec != New collection.Spec.Versions -func validationFailure(t *testing.T) { - newCollection := validatingCollectionVersions.DeepCopy() - newCollection.Spec.Version = "4.5.6" - - cv := collectionValidator{} - allowed, msg, err := cv.validateCollectionFn(nil, newCollection) - - if allowed { - t.Fatal("Validation should have failed. The validation was allowed instead.") - } - - if len(msg) == 0 { - t.Fatal("Validation failed. A message was expected.") - } - - if err == nil { - t.Fatal("Validation failed. An error was expected") - } -} diff --git a/pkg/webhook/kabanero/v1alpha1/mutatingwebhook.go b/pkg/webhook/kabanero/v1alpha1/mutatingwebhook.go deleted file mode 100644 index 23fcca12..00000000 --- a/pkg/webhook/kabanero/v1alpha1/mutatingwebhook.go +++ /dev/null @@ -1,69 +0,0 @@ -package kabanero - -import ( - "context" - "encoding/json" - "net/http" - - kabanerov1alpha1 "github.com/kabanero-io/kabanero-operator/pkg/apis/kabanero/v1alpha1" - - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/manager" - "sigs.k8s.io/controller-runtime/pkg/webhook/admission" -) - -// Builds the webhook for the manager to register -func BuildMutatingWebhook(mgr *manager.Manager) *admission.Webhook { - return &admission.Webhook{Handler: &kabaneroMutator{}} -} - -// kabaneroMutator mutates kabaneros -type kabaneroMutator struct { - client client.Client - decoder *admission.Decoder -} - -// Implement admission.Handler so the controller can handle admission request. -// This no-op assignment ensures that the struct implements the interface. -var _ admission.Handler = &kabaneroMutator{} - -// kabaneroMutator verifies that the kabanero version singleton and array -// are not in conflict. -func (a *kabaneroMutator) Handle(ctx context.Context, req admission.Request) admission.Response { - kabanero := &kabanerov1alpha1.Kabanero{} - - err := a.decoder.Decode(req, kabanero) - if err != nil { - return admission.Errored(http.StatusBadRequest, err) - } - - err = a.mutatekabaneroFn(ctx, kabanero) - if err != nil { - return admission.Errored(http.StatusInternalServerError, err) - } - - marshaledKabanero, err := json.Marshal(kabanero) - if err != nil { - return admission.Errored(http.StatusInternalServerError, err) - } - - return admission.PatchResponseFromRaw(req.Object.Raw, marshaledKabanero) -} - -// mutatekabaneroFn add an annotation to the given pod -func (a *kabaneroMutator) mutatekabaneroFn(ctx context.Context, kabanero *kabanerov1alpha1.Kabanero) error { - // TODO: Business logic - return nil -} - -// InjectClient injects the client. -func (v *kabaneroMutator) InjectClient(c client.Client) error { - v.client = c - return nil -} - -// InjectDecoder injects the decoder. -func (v *kabaneroMutator) InjectDecoder(d *admission.Decoder) error { - v.decoder = d - return nil -} diff --git a/pkg/webhook/kabanero/v1alpha1/validatingwebhook.go b/pkg/webhook/kabanero/v1alpha1/validatingwebhook.go deleted file mode 100644 index 06024cd1..00000000 --- a/pkg/webhook/kabanero/v1alpha1/validatingwebhook.go +++ /dev/null @@ -1,92 +0,0 @@ -package kabanero - -// The controller-runtime example webhook (v0.10) was used to build this -// webhook implementation. - -import ( - "context" - "net/http" - "fmt" - - kabanerov1alpha1 "github.com/kabanero-io/kabanero-operator/pkg/apis/kabanero/v1alpha1" - - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/manager" - "sigs.k8s.io/controller-runtime/pkg/webhook/admission" -) - -// Builds the webhook for the manager to register -func BuildValidatingWebhook(mgr *manager.Manager) *admission.Webhook { - return &admission.Webhook{Handler: &kabaneroValidator{}} -} - -// kabaneroValidator validates kabaneros -type kabaneroValidator struct { - client client.Client - decoder *admission.Decoder -} - -// Implement admission.Handler so the controller can handle admission request. -// This no-op assignment ensures that the struct implements the interface. -var _ admission.Handler = &kabaneroValidator{} - -// kabaneroValidator admits a kabanero if it passes validity checks -func (v *kabaneroValidator) Handle(ctx context.Context, req admission.Request) admission.Response { - kabanero := &kabanerov1alpha1.Kabanero{} - - err := v.decoder.Decode(req, kabanero) - if err != nil { - return admission.Errored(http.StatusBadRequest, err) - } - - allowed, reason, err := v.validatekabaneroFn(ctx, kabanero) - if err != nil { - return admission.Errored(http.StatusInternalServerError, err) - } - return admission.ValidationResponse(allowed, reason) -} - -func (v *kabaneroValidator) validatekabaneroFn(ctx context.Context, pod *kabanerov1alpha1.Kabanero) (bool, string, error) { - // For now, just reject everything. - - name := pod.ObjectMeta.Name - namespace := pod.ObjectMeta.Namespace - kabaneroList := &kabanerov1alpha1.KabaneroList{} - options := []client.ListOption{client.InNamespace(namespace)} - - err := v.client.List(ctx, kabaneroList, options...) - if err != nil { - return false, fmt.Sprintf("Failed to list Kabaneros in namespace: %s", namespace), err - } - - // If there is a Kabanero in this namespace other than a named match (update), reject. - // Do not allow more than 1 Kabanero per namespace. - allow := true - for _, kabanero := range kabaneroList.Items { - if name == kabanero.Name { - // Matching name, allow Update - break - } else { - // This is an additional instance, reject - allow = false - } - } - - if allow { - return true, fmt.Sprintf("Kabanero %s in namespace %s approved", name, namespace), nil - } else { - return false, fmt.Sprintf("Rejecting additional Kabanero instance: %s in namespace: %s. Multiple Kabanero instances are not allowed.", name, namespace), nil - } -} - -// InjectClient injects the client. -func (v *kabaneroValidator) InjectClient(c client.Client) error { - v.client = c - return nil -} - -// InjectDecoder injects the decoder. -func (v *kabaneroValidator) InjectDecoder(d *admission.Decoder) error { - v.decoder = d - return nil -} diff --git a/registry/Dockerfile b/registry/Dockerfile index bf3e60aa..7d925c09 100644 --- a/registry/Dockerfile +++ b/registry/Dockerfile @@ -1,4 +1,4 @@ -FROM quay.io/operator-framework/upstream-registry-builder:v1.5.6 as builder +FROM quay.io/operator-framework/upstream-registry-builder:v1.12.2 as builder # This dockerfile is taken from the operator-registry upstream example COPY manifests manifests diff --git a/registry/manifests/kabanero-operator/0.10.0/kabanero-operator.v0.10.0.clusterserviceversion.yaml b/registry/manifests/kabanero-operator/0.10.0/kabanero-operator.v0.10.0.clusterserviceversion.yaml new file mode 100644 index 00000000..fc035db5 --- /dev/null +++ b/registry/manifests/kabanero-operator/0.10.0/kabanero-operator.v0.10.0.clusterserviceversion.yaml @@ -0,0 +1,290 @@ +apiVersion: operators.coreos.com/v1alpha1 +kind: ClusterServiceVersion +metadata: + name: kabanero-operator.v0.10.0 + namespace: placeholder + annotations: + capabilities: Basic Install + categories: "Integration & Delivery" + certified: "false" + containerImage: kabanero/kabanero-operator:latest + createdAt: 2019-11-19T12:00:00.000-0500 + description: Bringings together foundational open source technologies into a modern microservices-based framework. + olm.skipRange: '>=0.6.1 <0.10.0' + repository: https://github.com/kabanero-io/kabanero-operator + support: IBM + alm-examples: |- + [ + { + "apiVersion": "kabanero.io/v1alpha2", + "kind": "Kabanero", + "metadata": { + "name": "kabanero" + }, + "spec": { + "version": "0.10.0", + "stacks": { + "repositories": [ + { + "name": "incubator", + "https": { + "url": "https://github.com/kabanero-io/kabanero-stack-hub/releases/download/0.9.0/kabanero-stack-hub-index.yaml" + } + } + ], + "pipelines": [ + { + "id": "default", + "sha256": "deb5162495e1fe60ab52632f0879f9c9b95e943066590574865138791cbe948f", + "https": { + "url": "https://github.com/kabanero-io/kabanero-pipelines/releases/download/0.9.1/default-kabanero-pipelines.tar.gz" + } + } + ] + } + } + }, + { + "apiVersion": "kabanero.io/v1alpha2", + "kind": "Stack", + "metadata": { + "name": "java-openliberty" + }, + "spec": { + "name": "java-openliberty", + "versions": [ + { "version": "0.2.11", + "pipelines": [ + { "id": "default", + "sha256": "deb5162495e1fe60ab52632f0879f9c9b95e943066590574865138791cbe948f", + "https": { + "url": "https://github.com/kabanero-io/kabanero-pipelines/releases/download/0.9.1/default-kabanero-pipelines.tar.gz" + } + } + ], + "images": [ + { "id": "java-openliberty", + "image": "docker.io/appsody/java-openliberty:0.2.11" + } + ] + } + ] + } + } + ] +spec: + minKubeVersion: 1.16.0 + apiservicedefinitions: {} + maturity: alpha + version: 0.10.0 + replaces: kabanero-operator.v0.9.1 + displayName: Kabanero Operator + description: | + The Kabanero operator is used to manage Kabanero Foundation instances on your Open Shift or Kubernetes cluster. + + [Kabanero](http://kabanero.io) is an open source project focused on bringing together foundational open source technologies into a modern microservices-based framework. + + Use our application stacks infused with expertise to select proven technologies, languages, and runtimes for building applications for Kubernetes. Apply customizations before sharing the application stack with developers and operations teams, to ensure your business process and governance needs are met. Application stacks reduce the decision-cycle time, enabling developers to focus on delivering line-of-business value without having to become full stack experts. + + ## Prerequisites + The Kabanero operator creates objects that are processed by other + operators. The target environment is OpenShift Container Platform + 4.2. The following operators must be installed in the cluster: + * [OpenShift Service Mesh](https://docs.openshift.com/container-platform/4.2/service_mesh/service_mesh_install/installing-ossm.html) + * [OpenShift Serverless Operator](https://docs.openshift.com/container-platform/4.2/serverless/installing-openshift-serverless.html) + * [Openshift Pipelines Operator](https://github.com/openshift/tektoncd-pipeline-operator) + * [Appsody Operator](https://github.com/appsody/appsody-operator/) + + We recommend you use the sample install.sh script located under "Assets" in each of the [Kabanero Operator Releases](https://github.com/kabanero-io/kabanero-operator/releases) to install the prerequisites from the appropriate operator catalogs. + icon: + - base64data: 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 + mediatype: image/png + maintainers: + - name: Tim Kaczynski + email: kaczynsk@us.ibm.com + - name: Ed Mezarina + email: mezarina@us.ibm.com + - name: Dan Cleyrat + email: dacleyra@us.ibm.com + links: + - name: Kabanero.io + url: https://kabanero.io + - name: Kabanero Operator + url: https://github.com/kabanero-io/kabanero-operator + keywords: + - 'Microservice' + - 'Knative' + - 'Istio' + - 'Codewind' + - 'Appsody' + - 'Tekton' + customresourcedefinitions: + owned: + - kind: Stack + name: stacks.kabanero.io + version: v1alpha2 + group: kabanero.io + description: Kabanero Stack + displayName: Kabanero Stack + resources: + - kind: Pipeline + name: '' + version: v1alpha1 + - kind: Task + name: '' + version: v1alpha1 + - kind: Condition + name: '' + version: v1alpha1 + - kind: ServiceAccount + name: '' + version: v1 + statusDescriptors: + - description: Version of the stack + displayName: Version + path: activeVersion + x-descriptors: + - 'urn:alm:descriptor:com.tectonic.ui:label' + - description: The URL where the stack is located + displayName: Location + path: activeLocation + x-descriptors: + - 'urn:alm:descriptor:com.tectonic.ui:label' + - description: The status of the stack + displayName: Status + path: status + x-descriptors: + - 'urn:alm:descriptor:com.tectonic.ui:label' + - kind: Kabanero + name: kabaneros.kabanero.io + version: v1alpha2 + group: kabanero.io + description: Kabanero Platform + displayName: Kabanero + resources: + - kind: Stack + name: "" + version: v1alpha2 + - kind: ConfigMap + name: "" + version: v1 + - kind: Deployment + name: "" + version: v1 + - kind: Pod + name: "" + version: v1 + - kind: Role + name: "" + version: v1 + - kind: RoleBinding + name: "" + version: v1 + - kind: ServiceAccount + name: "" + version: v1 + statusDescriptors: + - description: Kabanero foundation version + displayName: Version + path: kabaneroInstance.version + x-descriptors: + - 'urn:alm:descriptor:com.tectonic.ui:label' + - description: Kabanero operator readiness status. + displayName: Kabanero Readiness + path: kabaneroInstance.ready + x-descriptors: + - 'urn:alm:descriptor:com.tectonic.ui:label' + - description: Serverless readiness status. + displayName: Serverless Readiness + path: serverless.ready + x-descriptors: + - 'urn:alm:descriptor:com.tectonic.ui:label' + - description: Knative serving readiness status. + displayName: Knative Serving Readiness + path: serverless.knativeServing.ready + x-descriptors: + - 'urn:alm:descriptor:com.tectonic.ui:label' + - description: Tekton readiness status. + displayName: Tekton Readiness + path: tekton.ready + x-descriptors: + - 'urn:alm:descriptor:com.tectonic.ui:label' + - description: Kabanero CLI service readiness status. + displayName: Kabanero CLI Readiness + path: cli.ready + x-descriptors: + - 'urn:alm:descriptor:com.tectonic.ui:label' + - description: Appsody readiness status. + displayName: Appsody Readiness + path: appsody.ready + x-descriptors: + - 'urn:alm:descriptor:com.tectonic.ui:label' + # The required CRDs are not listed due to OLM's random catalog selection, + # but the following are required: + # Knative Serving, Tekton, Appsody + required: + install: + spec: + deployments: + - name: kabanero-operator + spec: + replicas: 1 + selector: + matchLabels: + name: kabanero-operator + strategy: {} + template: + metadata: + labels: + name: kabanero-operator + app.kubernetes.io/name: kabanero + app.kubernetes.io/instance: + app.kubernetes.io/version: '0.10.0' + app.kubernetes.io/component: operator + app.kubernetes.io/part-of: kabanero + app.kubernetes.io/managed-by: olm + spec: + containers: + - command: + - kabanero-operator + env: + - name: WATCH_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: OPERATOR_NAME + value: kabanero-operator + image: kabanero/kabanero-operator:latest + imagePullPolicy: Always + name: kabanero-operator + resources: {} + serviceAccountName: kabanero-operator + clusterPermissions: + - rules: + - apiGroups: + - '*' + resources: + - '*' + verbs: + - '*' + - nonResourceURLs: + - '*' + verbs: + - '*' + serviceAccountName: kabanero-operator + strategy: deployment + installModes: + - supported: true + type: OwnNamespace + - supported: true + type: SingleNamespace + - supported: false + type: MultiNamespace + - supported: false + type: AllNamespaces + provider: + name: IBM diff --git a/registry/manifests/kabanero-operator/0.9.0/kabanero-operator.v0.9.0.clusterserviceversion.yaml b/registry/manifests/kabanero-operator/0.9.0/kabanero-operator.v0.9.0.clusterserviceversion.yaml index 6a7dfc4b..ed563ea9 100644 --- a/registry/manifests/kabanero-operator/0.9.0/kabanero-operator.v0.9.0.clusterserviceversion.yaml +++ b/registry/manifests/kabanero-operator/0.9.0/kabanero-operator.v0.9.0.clusterserviceversion.yaml @@ -7,7 +7,7 @@ metadata: capabilities: Basic Install categories: "Integration & Delivery" certified: "false" - containerImage: kabanero/kabanero-operator:latest + containerImage: kabanero/kabanero-operator@sha256:3ec321bb84127e108d4f65b6d2c97f102072b7622fa545ce1a78ef6935c2f3a8 createdAt: 2019-11-19T12:00:00.000-0500 description: Bringings together foundational open source technologies into a modern microservices-based framework. olm.skipRange: '>=0.6.1 <0.9.0' @@ -302,7 +302,7 @@ spec: fieldPath: metadata.name - name: OPERATOR_NAME value: kabanero-operator - image: kabanero/kabanero-operator:latest + image: kabanero/kabanero-operator@sha256:3ec321bb84127e108d4f65b6d2c97f102072b7622fa545ce1a78ef6935c2f3a8 imagePullPolicy: Always name: kabanero-operator resources: {} @@ -332,3 +332,12 @@ spec: type: AllNamespaces provider: name: IBM + relatedImages: + - image: kabanero/kabanero-command-line-services:0.9.0 + name: cli-services-0.9.0 + - image: kabanero/landing:0.9.0 + name: landing-0.9.0 + - image: kabanero/events-operator:0.1.0 + name: events-0.9.0 + - image: kabanero/che-devfile-registry:0.11.0 + name: codeready-workspaces-0.9.0 diff --git a/deploy/crds/kabanero.io_collections_crd.yaml b/registry/manifests/kabanero-operator/0.9.0/kabanero.io_collections_crd.yaml similarity index 100% rename from deploy/crds/kabanero.io_collections_crd.yaml rename to registry/manifests/kabanero-operator/0.9.0/kabanero.io_collections_crd.yaml diff --git a/registry/manifests/kabanero-operator/0.9.0/kabanero.io_kabaneros_crd.yaml b/registry/manifests/kabanero-operator/0.9.0/kabanero.io_kabaneros_crd.yaml new file mode 100644 index 00000000..bbb58bb7 --- /dev/null +++ b/registry/manifests/kabanero-operator/0.9.0/kabanero.io_kabaneros_crd.yaml @@ -0,0 +1,977 @@ +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: kabaneros.kabanero.io +spec: + additionalPrinterColumns: + - JSONPath: .metadata.creationTimestamp + description: CreationTimestamp is a timestamp representing the server time when + this object was created. It is not guaranteed to be set in happens-before order + across separate operations. + name: Age + type: date + - JSONPath: .status.kabaneroInstance.version + description: Kabanero operator instance version. + name: Version + type: string + - JSONPath: .status.kabaneroInstance.ready + description: Kabanero operator instance readiness status. The status is directly + correlated to the availability of the operator's resources dependencies. + name: Ready + type: string + group: kabanero.io + names: + kind: Kabanero + listKind: KabaneroList + plural: kabaneros + singular: kabanero + scope: Namespaced + subresources: + status: {} + version: v1alpha1 + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + 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: KabaneroSpec defines the desired state of Kabanero + properties: + admissionControllerWebhook: + properties: + image: + type: string + repository: + type: string + tag: + type: string + version: + type: string + type: object + che: + description: CheCustomizationSpec defines customization entries for + Che. + properties: + cheOperatorInstance: + description: CheOperatorInstanceSpec defines customization entries + for the Che operator instance. + properties: + cheWorkspaceClusterRole: + type: string + type: object + enable: + type: boolean + kabaneroChe: + description: KabaneroCheSpec defines customization entries for + Kabanero Che. + properties: + image: + type: string + repository: + type: string + tag: + type: string + version: + type: string + type: object + type: object + cliServices: + description: KabaneroCliServicesCustomizationSpec defines customization + entries for the Kabanero CLI. + properties: + image: + type: string + repository: + type: string + sessionExpirationSeconds: + type: string + tag: + type: string + version: + description: 'Future: Enable bool `json:"enable,omitempty"`' + type: string + type: object + collectionController: + description: CollectionControllerSpec defines customization entried + for the Kabanero collection controller. + properties: + image: + type: string + repository: + type: string + tag: + type: string + version: + type: string + type: object + collections: + description: InstanceCollectionConfig defines the customization entries + for a set of collections. + properties: + repositories: + items: + description: RepositoryConfig defines customization entries + for a collection. + properties: + activateDefaultCollections: + type: boolean + name: + type: string + skipCertVerification: + type: boolean + url: + type: string + type: object + type: array + type: object + events: + properties: + enable: + type: boolean + image: + type: string + repository: + type: string + tag: + type: string + version: + type: string + type: object + github: + description: GithubConfig represents the Github information (public + or GHE) where the organization and teams managing the collections + live. Members of the specified team in the specified organization + will have admin authority in the Kabanero CLI. + properties: + apiUrl: + type: string + organization: + type: string + teams: + items: + type: string + type: array + type: object + landing: + description: KabaneroLandingCustomizationSpec defines customization + entries for Kabanero landing page. + properties: + enable: + type: boolean + version: + type: string + type: object + targetNamespaces: + items: + type: string + type: array + tekton: + description: TektonCustomizationSpec defines customization entries + for Tekton + properties: + disabled: + type: boolean + version: + type: string + type: object + version: + type: string + type: object + status: + description: KabaneroStatus defines the observed state of the Kabanero + instance. + properties: + admissionControllerWebhook: + description: Admission webhook instance status + properties: + errorMessage: + type: string + ready: + type: string + type: object + appsody: + description: Appsody instance readiness status. + properties: + errorMessage: + type: string + ready: + type: string + version: + type: string + type: object + che: + description: Che instance readiness status. + properties: + cheOperator: + description: CheOperatorStatus defines the observed status details + of the Che operator. + properties: + version: + type: string + type: object + errorMessage: + type: string + kabaneroChe: + description: KabaneroCheStatus defines the observed status details + of Kabanero Che. + properties: + version: + type: string + type: object + kabaneroCheInstance: + description: KabaneroCheInstanceStatus defines the observed status + details of Che instance. + properties: + cheImage: + type: string + cheImageTag: + type: string + cheWorkspaceClusterRole: + type: string + type: object + ready: + type: string + type: object + cli: + description: CLI readiness status. + properties: + errorMessage: + type: string + hostnames: + items: + type: string + type: array + ready: + type: string + type: object + collectionController: + description: Kabanero collection controller readiness status. + properties: + errorMessage: + type: string + ready: + type: string + version: + type: string + type: object + events: + description: Events instance status + properties: + errorMessage: + type: string + hostnames: + items: + type: string + type: array + ready: + type: string + type: object + kabaneroInstance: + description: Kabanero operator instance readiness status. The status + is directly correlated to the availability of resources dependencies. + properties: + errorMessage: + type: string + ready: + type: string + version: + type: string + type: object + kappnav: + description: Kabanero Application Navigator instance readiness status. + properties: + apiLocations: + items: + type: string + type: array + errorMessage: + type: string + ready: + type: string + uiLocations: + items: + type: string + type: array + type: object + knativeEventing: + description: Knative eventing instance readiness status. + properties: + errorMessage: + type: string + ready: + type: string + version: + type: string + type: object + landing: + description: Kabanero Landing page readiness status. + properties: + errorMessage: + type: string + ready: + type: string + version: + type: string + type: object + serverless: + description: OpenShift serverless operator status. + properties: + errorMessage: + type: string + knativeServing: + description: KnativeServingStatus defines the observed status + details of Knative Serving. + properties: + errorMessage: + type: string + ready: + type: string + version: + type: string + type: object + ready: + type: string + version: + type: string + type: object + tekton: + description: Tekton instance readiness status. + properties: + errorMessage: + type: string + ready: + type: string + version: + type: string + type: object + type: object + type: object + served: true + storage: false + - name: v1alpha2 + schema: + openAPIV3Schema: + 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: KabaneroSpec defines the desired state of Kabanero + properties: + admissionControllerWebhook: + properties: + image: + type: string + repository: + type: string + tag: + type: string + version: + type: string + type: object + cliServices: + description: KabaneroCliServicesCustomizationSpec defines customization + entries for the Kabanero CLI. + properties: + image: + type: string + repository: + type: string + sessionExpirationSeconds: + type: string + tag: + type: string + version: + description: 'Future: Enable bool `json:"enable,omitempty"`' + type: string + type: object + codeReadyWorkspaces: + description: CRWCustomizationSpec defines customization entries for + codeready-workspaces. + properties: + enable: + type: boolean + operator: + description: CRWOperatorSpec defines customization entries for + the codeready-workspaces operator. + properties: + customResourceInstance: + description: CRWOperatorCustomResourceSpec defines custom + resource customization entries for the codeready-workspaces + operator. + properties: + cheWorkspaceClusterRole: + type: string + devFileRegistryImage: + description: CWRCustomResourceDevFileRegImage defines + DevFileRegistryImage custom resource customization for + the codeready-workspaces operator. + properties: + image: + type: string + repository: + type: string + tag: + type: string + version: + type: string + type: object + openShiftOAuth: + type: boolean + selfSignedCert: + type: boolean + tlsSupport: + type: boolean + type: object + type: object + type: object + collectionController: + description: CollectionControllerSpec defines customization entried + for the Kabanero collection controller. + properties: + image: + type: string + repository: + type: string + tag: + type: string + version: + type: string + type: object + events: + properties: + enable: + type: boolean + image: + type: string + repository: + type: string + tag: + type: string + version: + type: string + type: object + github: + description: GithubConfig represents the Github information (public + or GHE) where the organization and teams managing the stacks live. Members + of the specified team in the specified organization will have admin + authority in the Kabanero CLI. + properties: + apiUrl: + type: string + organization: + type: string + teams: + items: + type: string + type: array + type: object + gitops: + properties: + pipelines: + items: + description: PipelineSpec defines a set of pipelines and associated + resources for a component. + properties: + gitRelease: + description: GitReleaseSpec defines customization entries + for a Git release. + properties: + assetName: + type: string + hostname: + type: string + organization: + type: string + project: + type: string + release: + type: string + skipCertVerification: + type: boolean + type: object + https: + description: HttpsProtocolFile defines how to retrieve a + file over https + properties: + skipCertVerification: + type: boolean + url: + type: string + type: object + id: + type: string + sha256: + type: string + type: object + type: array + type: object + governancePolicy: + description: GovernancePolicyConfig defines customization entries + for governance policies. + properties: + stackPolicy: + type: string + type: object + landing: + description: KabaneroLandingCustomizationSpec defines customization + entries for Kabanero landing page. + properties: + enable: + type: boolean + image: + type: string + repository: + type: string + tag: + type: string + version: + type: string + type: object + sso: + properties: + adminSecretName: + type: string + enable: + type: boolean + provider: + type: string + type: object + stackController: + description: StackControllerSpec defines customization entried for + the Kabanero stack controller. + properties: + image: + type: string + repository: + type: string + tag: + type: string + version: + type: string + type: object + stacks: + description: InstanceStackConfig defines the customization entries + for a set of stacks. + properties: + pipelines: + items: + description: PipelineSpec defines a set of pipelines and associated + resources for a component. + properties: + gitRelease: + description: GitReleaseSpec defines customization entries + for a Git release. + properties: + assetName: + type: string + hostname: + type: string + organization: + type: string + project: + type: string + release: + type: string + skipCertVerification: + type: boolean + type: object + https: + description: HttpsProtocolFile defines how to retrieve a + file over https + properties: + skipCertVerification: + type: boolean + url: + type: string + type: object + id: + type: string + sha256: + type: string + type: object + type: array + repositories: + items: + description: RepositoryConfig defines customization entries + for a stack. + properties: + gitRelease: + description: GitReleaseSpec defines customization entries + for a Git release. + properties: + assetName: + type: string + hostname: + type: string + organization: + type: string + project: + type: string + release: + type: string + skipCertVerification: + type: boolean + type: object + https: + description: HttpsProtocolFile defines how to retrieve a + file over https + properties: + skipCertVerification: + type: boolean + url: + type: string + type: object + name: + type: string + pipelines: + items: + description: PipelineSpec defines a set of pipelines and + associated resources for a component. + properties: + gitRelease: + description: GitReleaseSpec defines customization + entries for a Git release. + properties: + assetName: + type: string + hostname: + type: string + organization: + type: string + project: + type: string + release: + type: string + skipCertVerification: + type: boolean + type: object + https: + description: HttpsProtocolFile defines how to retrieve + a file over https + properties: + skipCertVerification: + type: boolean + url: + type: string + type: object + id: + type: string + sha256: + type: string + type: object + type: array + type: object + type: array + skipRegistryCertVerification: + type: boolean + type: object + targetNamespaces: + items: + type: string + type: array + triggers: + items: + description: TriggerSpec defines the sets of default triggers for + the stacks + properties: + gitRelease: + description: GitReleaseSpec defines customization entries for + a Git release. + properties: + assetName: + type: string + hostname: + type: string + organization: + type: string + project: + type: string + release: + type: string + skipCertVerification: + type: boolean + type: object + https: + description: HttpsProtocolFile defines how to retrieve a file + over https + properties: + skipCertVerification: + type: boolean + url: + type: string + type: object + id: + type: string + sha256: + type: string + type: object + type: array + version: + type: string + type: object + status: + description: KabaneroStatus defines the observed state of the Kabanero + instance. + properties: + admissionControllerWebhook: + description: Admission webhook instance status + properties: + message: + type: string + ready: + type: string + type: object + appsody: + description: Appsody instance readiness status. + properties: + message: + type: string + ready: + type: string + version: + type: string + type: object + cli: + description: CLI readiness status. + properties: + hostnames: + items: + type: string + type: array + message: + type: string + ready: + type: string + type: object + codereadyWorkspaces: + description: Codeready-workspaces instance readiness status. + properties: + message: + type: string + operator: + description: CRWOperatorStatus defines the observed status details + of the codeready-workspaces operator. + properties: + instance: + description: CRWInstanceStatus defines the observed status + details of the codeready-workspaces operator custom resource. + properties: + cheWorkspaceClusterRole: + type: string + devfileRegistryImage: + type: string + openShiftOAuth: + type: boolean + selfSignedCert: + type: boolean + tlsSupport: + type: boolean + required: + - cheWorkspaceClusterRole + - devfileRegistryImage + - openShiftOAuth + - selfSignedCert + - tlsSupport + type: object + version: + type: string + type: object + ready: + type: string + type: object + collectionController: + description: Kabanero collection controller readiness status. + properties: + message: + type: string + ready: + type: string + version: + type: string + type: object + events: + description: Events instance status + properties: + hostnames: + items: + type: string + type: array + message: + type: string + ready: + type: string + type: object + gitops: + description: The status of the gitops pipelines + properties: + message: + type: string + pipelines: + items: + description: PipelineStatus defines the observed state of the + assets located within a single pipeline .tar.gz. + properties: + activeAssets: + items: + description: RepositoryAssetStatus defines the observed + state of a single asset in a pipelines respository. + properties: + assetDigest: + type: string + assetName: + type: string + group: + type: string + kind: + type: string + namespace: + type: string + status: + type: string + statusMessage: + type: string + version: + type: string + type: object + type: array + digest: + type: string + gitRelease: + description: GitReleaseInfo is all of the GitReleaseSpec + information, minus the "skip cert verification" information, + which is not relevant for status. + properties: + assetName: + type: string + hostname: + type: string + organization: + type: string + project: + type: string + release: + type: string + type: object + name: + type: string + url: + type: string + type: object + type: array + ready: + type: string + type: object + kabaneroInstance: + description: Kabanero operator instance readiness status. The status + is directly correlated to the availability of resources dependencies. + properties: + message: + type: string + ready: + type: string + version: + type: string + type: object + kappnav: + description: Kabanero Application Navigator instance readiness status. + properties: + apiLocations: + items: + type: string + type: array + message: + type: string + ready: + type: string + uiLocations: + items: + type: string + type: array + type: object + landing: + description: Kabanero Landing page readiness status. + properties: + message: + type: string + ready: + type: string + version: + type: string + type: object + serverless: + description: OpenShift serverless operator status. + properties: + knativeServing: + description: KnativeServingStatus defines the observed status + details of Knative Serving. + properties: + message: + type: string + ready: + type: string + version: + type: string + type: object + message: + type: string + ready: + type: string + version: + type: string + type: object + sso: + description: SSO server status + properties: + configured: + type: string + message: + type: string + ready: + type: string + type: object + stackController: + description: Kabanero stack controller readiness status. + properties: + message: + type: string + ready: + type: string + version: + type: string + type: object + tekton: + description: Tekton instance readiness status. + properties: + message: + type: string + ready: + type: string + version: + type: string + type: object + type: object + type: object + served: true + storage: true diff --git a/registry/manifests/kabanero-operator/0.9.0/kabanero.io_stacks_crd.yaml b/registry/manifests/kabanero-operator/0.9.0/kabanero.io_stacks_crd.yaml new file mode 100644 index 00000000..854aa37d --- /dev/null +++ b/registry/manifests/kabanero-operator/0.9.0/kabanero.io_stacks_crd.yaml @@ -0,0 +1,210 @@ +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: stacks.kabanero.io +spec: + additionalPrinterColumns: + - JSONPath: .metadata.creationTimestamp + description: CreationTimestamp is a timestamp representing the server time when + this object was created. It is not guaranteed to be set in happens-before order + across separate operations. + name: Age + type: date + - JSONPath: .status.summary + description: Stack summary. + name: Summary + type: string + group: kabanero.io + names: + kind: Stack + listKind: StackList + plural: stacks + singular: stack + scope: Namespaced + subresources: + status: {} + validation: + openAPIV3Schema: + description: Stack is the Schema for the stack 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: StackSpec defines the desired composition of a Stack + properties: + name: + type: string + versions: + items: + description: StackVersion defines the desired composition of a specific + stack version. + properties: + desiredState: + type: string + images: + items: + description: Image defines a container image used by a stack + properties: + id: + type: string + image: + type: string + type: object + type: array + pipelines: + items: + description: PipelineSpec defines a set of pipelines and associated + resources for a component. + properties: + gitRelease: + description: GitReleaseSpec defines customization entries + for a Git release. + properties: + assetName: + type: string + hostname: + type: string + organization: + type: string + project: + type: string + release: + type: string + skipCertVerification: + type: boolean + type: object + https: + description: HttpsProtocolFile defines how to retrieve a + file over https + properties: + skipCertVerification: + type: boolean + url: + type: string + type: object + id: + type: string + sha256: + type: string + type: object + type: array + skipCertVerification: + type: boolean + skipRegistryCertVerification: + type: boolean + version: + type: string + type: object + type: array + type: object + status: + description: StackStatus defines the observed state of a stack + properties: + statusMessage: + type: string + summary: + type: string + versions: + items: + description: StackVersionStatus defines the observed state of a specific + stack version. + properties: + images: + items: + description: ImageStatus defines a container image status used + by a stack + properties: + digest: + description: ImageDigest defines a container image digest + used by a stack + properties: + activation: + type: string + message: + type: string + type: object + id: + type: string + image: + type: string + type: object + type: array + location: + type: string + pipelines: + items: + description: PipelineStatus defines the observed state of the + assets located within a single pipeline .tar.gz. + properties: + activeAssets: + items: + description: RepositoryAssetStatus defines the observed + state of a single asset in a pipelines respository. + properties: + assetDigest: + type: string + assetName: + type: string + group: + type: string + kind: + type: string + namespace: + type: string + status: + type: string + statusMessage: + type: string + version: + type: string + type: object + type: array + digest: + type: string + gitRelease: + description: GitReleaseInfo is all of the GitReleaseSpec + information, minus the "skip cert verification" information, + which is not relevant for status. + properties: + assetName: + type: string + hostname: + type: string + organization: + type: string + project: + type: string + release: + type: string + type: object + name: + type: string + url: + type: string + type: object + type: array + status: + type: string + statusMessage: + type: string + version: + type: string + type: object + type: array + type: object + type: object + version: v1alpha2 + versions: + - name: v1alpha2 + served: true + storage: true diff --git a/registry/manifests/kabanero-operator/0.9.1/kabanero-operator.v0.9.1.clusterserviceversion.yaml b/registry/manifests/kabanero-operator/0.9.1/kabanero-operator.v0.9.1.clusterserviceversion.yaml new file mode 100644 index 00000000..01c575b9 --- /dev/null +++ b/registry/manifests/kabanero-operator/0.9.1/kabanero-operator.v0.9.1.clusterserviceversion.yaml @@ -0,0 +1,343 @@ +apiVersion: operators.coreos.com/v1alpha1 +kind: ClusterServiceVersion +metadata: + name: kabanero-operator.v0.9.1 + namespace: placeholder + annotations: + capabilities: Basic Install + categories: "Integration & Delivery" + certified: "false" + containerImage: kabanero/kabanero-operator@sha256:26e3fa7765cdfb89610541528e9d8c4052a77a6e43254eb7c7513b4941711f4f + createdAt: 2019-11-19T12:00:00.000-0500 + description: Bringings together foundational open source technologies into a modern microservices-based framework. + olm.skipRange: '>=0.6.1 <0.9.1' + repository: https://github.com/kabanero-io/kabanero-operator + support: IBM + alm-examples: |- + [ + { + "apiVersion": "kabanero.io/v1alpha2", + "kind": "Kabanero", + "metadata": { + "name": "kabanero" + }, + "spec": { + "version": "0.9.1", + "stacks": { + "repositories": [ + { + "name": "incubator", + "https": { + "url": "https://github.com/kabanero-io/kabanero-stack-hub/releases/download/0.9.0/kabanero-stack-hub-index.yaml" + } + } + ], + "pipelines": [ + { + "id": "default", + "sha256": "deb5162495e1fe60ab52632f0879f9c9b95e943066590574865138791cbe948f", + "https": { + "url": "https://github.com/kabanero-io/kabanero-pipelines/releases/download/0.9.1/default-kabanero-pipelines.tar.gz" + } + } + ] + } + } + }, + { + "apiVersion": "kabanero.io/v1alpha1", + "kind": "Collection", + "metadata": { + "name": "java-openliberty" + }, + "spec": { + "version": "0.2.11", + "name": "java-openliberty", + "desiredState": "inactive" + } + }, + { + "apiVersion": "kabanero.io/v1alpha2", + "kind": "Stack", + "metadata": { + "name": "java-openliberty" + }, + "spec": { + "name": "java-openliberty", + "versions": [ + { "version": "0.2.11", + "pipelines": [ + { "id": "default", + "sha256": "deb5162495e1fe60ab52632f0879f9c9b95e943066590574865138791cbe948f", + "https": { + "url": "https://github.com/kabanero-io/kabanero-pipelines/releases/download/0.9.1/default-kabanero-pipelines.tar.gz" + } + } + ], + "images": [ + { "id": "java-openliberty", + "image": "docker.io/appsody/java-openliberty:0.2.11" + } + ] + } + ] + } + } + ] +spec: + minKubeVersion: 1.16.0 + apiservicedefinitions: {} + maturity: alpha + version: 0.9.1 + replaces: kabanero-operator.v0.9.0 + displayName: Kabanero Operator + description: | + The Kabanero operator is used to manage Kabanero Foundation instances on your Open Shift or Kubernetes cluster. + + [Kabanero](http://kabanero.io) is an open source project focused on bringing together foundational open source technologies into a modern microservices-based framework. + + Use our application stacks infused with expertise to select proven technologies, languages, and runtimes for building applications for Kubernetes. Apply customizations before sharing the application stack with developers and operations teams, to ensure your business process and governance needs are met. Application stacks reduce the decision-cycle time, enabling developers to focus on delivering line-of-business value without having to become full stack experts. + + ## Prerequisites + The Kabanero operator creates objects that are processed by other + operators. The target environment is OpenShift Container Platform + 4.2. The following operators must be installed in the cluster: + * [OpenShift Service Mesh](https://docs.openshift.com/container-platform/4.2/service_mesh/service_mesh_install/installing-ossm.html) + * [OpenShift Serverless Operator](https://docs.openshift.com/container-platform/4.2/serverless/installing-openshift-serverless.html) + * [Openshift Pipelines Operator](https://github.com/openshift/tektoncd-pipeline-operator) + * [Appsody Operator](https://github.com/appsody/appsody-operator/) + + We recommend you use the sample install.sh script located under "Assets" in each of the [Kabanero Operator Releases](https://github.com/kabanero-io/kabanero-operator/releases) to install the prerequisites from the appropriate operator catalogs. + icon: + - base64data: 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 + mediatype: image/png + maintainers: + - name: Tim Kaczynski + email: kaczynsk@us.ibm.com + - name: Ed Mezarina + email: mezarina@us.ibm.com + - name: Dan Cleyrat + email: dacleyra@us.ibm.com + links: + - name: Kabanero.io + url: https://kabanero.io + - name: Kabanero Operator + url: https://github.com/kabanero-io/kabanero-operator + keywords: + - 'Microservice' + - 'Knative' + - 'Istio' + - 'Codewind' + - 'Appsody' + - 'Tekton' + customresourcedefinitions: + owned: + - kind: Collection + name: collections.kabanero.io + version: v1alpha1 + group: kabanero.io + description: Kabanero Collection + displayName: Kabanero Collection + resources: + - kind: Pipeline + name: '' + version: v1alpha1 + - kind: Task + name: '' + version: v1alpha1 + - kind: ServiceAccount + name: '' + version: v1 + statusDescriptors: + - description: Version of the collection + displayName: Version + path: activeVersion + x-descriptors: + - 'urn:alm:descriptor:com.tectonic.ui:label' + - description: The URL where the collection is located + displayName: Location + path: activeLocation + x-descriptors: + - 'urn:alm:descriptor:com.tectonic.ui:label' + - description: The status of the collection + displayName: Status + path: status + x-descriptors: + - 'urn:alm:descriptor:com.tectonic.ui:label' + - kind: Stack + name: stacks.kabanero.io + version: v1alpha2 + group: kabanero.io + description: Kabanero Stack + displayName: Kabanero Stack + resources: + - kind: Pipeline + name: '' + version: v1alpha1 + - kind: Task + name: '' + version: v1alpha1 + - kind: Condition + name: '' + version: v1alpha1 + - kind: ServiceAccount + name: '' + version: v1 + statusDescriptors: + - description: Version of the stack + displayName: Version + path: activeVersion + x-descriptors: + - 'urn:alm:descriptor:com.tectonic.ui:label' + - description: The URL where the stack is located + displayName: Location + path: activeLocation + x-descriptors: + - 'urn:alm:descriptor:com.tectonic.ui:label' + - description: The status of the stack + displayName: Status + path: status + x-descriptors: + - 'urn:alm:descriptor:com.tectonic.ui:label' + - kind: Kabanero + name: kabaneros.kabanero.io + version: v1alpha2 + group: kabanero.io + description: Kabanero Platform + displayName: Kabanero + resources: + - kind: Stack + name: "" + version: v1alpha2 + - kind: ConfigMap + name: "" + version: v1 + - kind: Deployment + name: "" + version: v1 + - kind: Pod + name: "" + version: v1 + - kind: Role + name: "" + version: v1 + - kind: RoleBinding + name: "" + version: v1 + - kind: ServiceAccount + name: "" + version: v1 + statusDescriptors: + - description: Kabanero foundation version + displayName: Version + path: kabaneroInstance.version + x-descriptors: + - 'urn:alm:descriptor:com.tectonic.ui:label' + - description: Kabanero operator readiness status. + displayName: Kabanero Readiness + path: kabaneroInstance.ready + x-descriptors: + - 'urn:alm:descriptor:com.tectonic.ui:label' + - description: Serverless readiness status. + displayName: Serverless Readiness + path: serverless.ready + x-descriptors: + - 'urn:alm:descriptor:com.tectonic.ui:label' + - description: Knative serving readiness status. + displayName: Knative Serving Readiness + path: serverless.knativeServing.ready + x-descriptors: + - 'urn:alm:descriptor:com.tectonic.ui:label' + - description: Tekton readiness status. + displayName: Tekton Readiness + path: tekton.ready + x-descriptors: + - 'urn:alm:descriptor:com.tectonic.ui:label' + - description: Kabanero CLI service readiness status. + displayName: Kabanero CLI Readiness + path: cli.ready + x-descriptors: + - 'urn:alm:descriptor:com.tectonic.ui:label' + - description: Appsody readiness status. + displayName: Appsody Readiness + path: appsody.ready + x-descriptors: + - 'urn:alm:descriptor:com.tectonic.ui:label' + # The required CRDs are not listed due to OLM's random catalog selection, + # but the following are required: + # Knative Serving, Tekton, Appsody + required: + install: + spec: + deployments: + - name: kabanero-operator + spec: + replicas: 1 + selector: + matchLabels: + name: kabanero-operator + strategy: {} + template: + metadata: + labels: + name: kabanero-operator + app.kubernetes.io/name: kabanero + app.kubernetes.io/instance: + app.kubernetes.io/version: '0.9.1' + app.kubernetes.io/component: operator + app.kubernetes.io/part-of: kabanero + app.kubernetes.io/managed-by: olm + spec: + containers: + - command: + - kabanero-operator + env: + - name: WATCH_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: OPERATOR_NAME + value: kabanero-operator + image: kabanero/kabanero-operator@sha256:26e3fa7765cdfb89610541528e9d8c4052a77a6e43254eb7c7513b4941711f4f + imagePullPolicy: Always + name: kabanero-operator + resources: {} + serviceAccountName: kabanero-operator + clusterPermissions: + - rules: + - apiGroups: + - '*' + resources: + - '*' + verbs: + - '*' + - nonResourceURLs: + - '*' + verbs: + - '*' + serviceAccountName: kabanero-operator + strategy: deployment + installModes: + - supported: true + type: OwnNamespace + - supported: true + type: SingleNamespace + - supported: false + type: MultiNamespace + - supported: false + type: AllNamespaces + provider: + name: IBM + relatedImages: + - image: kabanero/kabanero-command-line-services:0.9.1 + name: cli-services-0.9.1 + - image: kabanero/landing:0.9.0 + name: landing-0.9.0 + - image: kabanero/events-operator:0.1.0 + name: events-0.9.0 + - image: kabanero/che-devfile-registry:0.11.0 + name: codeready-workspaces-0.9.0 diff --git a/registry/manifests/kabanero-operator/0.9.1/kabanero.io_collections_crd.yaml b/registry/manifests/kabanero-operator/0.9.1/kabanero.io_collections_crd.yaml new file mode 100644 index 00000000..927ba881 --- /dev/null +++ b/registry/manifests/kabanero-operator/0.9.1/kabanero.io_collections_crd.yaml @@ -0,0 +1,215 @@ +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: collections.kabanero.io +spec: + additionalPrinterColumns: + - JSONPath: .metadata.creationTimestamp + description: CreationTimestamp is a timestamp representing the server time when + this object was created. It is not guaranteed to be set in happens-before order + across separate operations. + name: Age + type: date + - JSONPath: .status.status + description: Collection status. + name: Status + type: string + group: kabanero.io + names: + kind: Collection + listKind: CollectionList + plural: collections + singular: collection + scope: Namespaced + subresources: + status: {} + validation: + openAPIV3Schema: + description: Collection is the Schema for the collections 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: CollectionSpec defines the desired composition of a Collection + properties: + desiredState: + type: string + name: + type: string + repositoryUrl: + type: string + skipCertVerification: + type: boolean + version: + type: string + versions: + items: + description: CollectionVersion defines the desired composition of + a specific collection version. + properties: + desiredState: + type: string + repositoryUrl: + type: string + skipCertVerification: + type: boolean + version: + type: string + type: object + type: array + x-kubernetes-list-type: set + type: object + status: + description: CollectionStatus defines the observed state of a collection + properties: + activeLocation: + type: string + activePipelines: + items: + description: PipelineStatus defines the observed state of the assets + located within a single pipeline .tar.gz. + properties: + activeAssets: + items: + description: RepositoryAssetStatus defines the observed state + of a single asset in a respository, in the collection. + properties: + assetDigest: + type: string + assetName: + type: string + group: + type: string + kind: + type: string + namespace: + type: string + status: + type: string + statusMessage: + type: string + version: + type: string + type: object + type: array + x-kubernetes-list-type: set + digest: + type: string + name: + type: string + url: + type: string + required: + - digest + - name + - url + type: object + type: array + x-kubernetes-list-type: set + activeVersion: + type: string + availableLocation: + type: string + availableVersion: + type: string + images: + items: + description: Image defines a container image used by a collection + properties: + id: + type: string + image: + type: string + type: object + type: array + x-kubernetes-list-type: set + status: + type: string + statusMessage: + type: string + versions: + items: + description: CollectionVersionStatus defines the observed state of + a specific collection version. + properties: + images: + items: + description: Image defines a container image used by a collection + properties: + id: + type: string + image: + type: string + type: object + type: array + x-kubernetes-list-type: set + location: + type: string + pipelines: + items: + description: PipelineStatus defines the observed state of the + assets located within a single pipeline .tar.gz. + properties: + activeAssets: + items: + description: RepositoryAssetStatus defines the observed + state of a single asset in a respository, in the collection. + properties: + assetDigest: + type: string + assetName: + type: string + group: + type: string + kind: + type: string + namespace: + type: string + status: + type: string + statusMessage: + type: string + version: + type: string + type: object + type: array + x-kubernetes-list-type: set + digest: + type: string + name: + type: string + url: + type: string + required: + - digest + - name + - url + type: object + type: array + x-kubernetes-list-type: set + status: + type: string + statusMessage: + type: string + version: + type: string + type: object + type: array + x-kubernetes-list-type: set + type: object + type: object + version: v1alpha1 + versions: + - name: v1alpha1 + served: true + storage: true diff --git a/registry/manifests/kabanero-operator/0.9.1/kabanero.io_kabaneros_crd.yaml b/registry/manifests/kabanero-operator/0.9.1/kabanero.io_kabaneros_crd.yaml new file mode 100644 index 00000000..bbb58bb7 --- /dev/null +++ b/registry/manifests/kabanero-operator/0.9.1/kabanero.io_kabaneros_crd.yaml @@ -0,0 +1,977 @@ +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: kabaneros.kabanero.io +spec: + additionalPrinterColumns: + - JSONPath: .metadata.creationTimestamp + description: CreationTimestamp is a timestamp representing the server time when + this object was created. It is not guaranteed to be set in happens-before order + across separate operations. + name: Age + type: date + - JSONPath: .status.kabaneroInstance.version + description: Kabanero operator instance version. + name: Version + type: string + - JSONPath: .status.kabaneroInstance.ready + description: Kabanero operator instance readiness status. The status is directly + correlated to the availability of the operator's resources dependencies. + name: Ready + type: string + group: kabanero.io + names: + kind: Kabanero + listKind: KabaneroList + plural: kabaneros + singular: kabanero + scope: Namespaced + subresources: + status: {} + version: v1alpha1 + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + 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: KabaneroSpec defines the desired state of Kabanero + properties: + admissionControllerWebhook: + properties: + image: + type: string + repository: + type: string + tag: + type: string + version: + type: string + type: object + che: + description: CheCustomizationSpec defines customization entries for + Che. + properties: + cheOperatorInstance: + description: CheOperatorInstanceSpec defines customization entries + for the Che operator instance. + properties: + cheWorkspaceClusterRole: + type: string + type: object + enable: + type: boolean + kabaneroChe: + description: KabaneroCheSpec defines customization entries for + Kabanero Che. + properties: + image: + type: string + repository: + type: string + tag: + type: string + version: + type: string + type: object + type: object + cliServices: + description: KabaneroCliServicesCustomizationSpec defines customization + entries for the Kabanero CLI. + properties: + image: + type: string + repository: + type: string + sessionExpirationSeconds: + type: string + tag: + type: string + version: + description: 'Future: Enable bool `json:"enable,omitempty"`' + type: string + type: object + collectionController: + description: CollectionControllerSpec defines customization entried + for the Kabanero collection controller. + properties: + image: + type: string + repository: + type: string + tag: + type: string + version: + type: string + type: object + collections: + description: InstanceCollectionConfig defines the customization entries + for a set of collections. + properties: + repositories: + items: + description: RepositoryConfig defines customization entries + for a collection. + properties: + activateDefaultCollections: + type: boolean + name: + type: string + skipCertVerification: + type: boolean + url: + type: string + type: object + type: array + type: object + events: + properties: + enable: + type: boolean + image: + type: string + repository: + type: string + tag: + type: string + version: + type: string + type: object + github: + description: GithubConfig represents the Github information (public + or GHE) where the organization and teams managing the collections + live. Members of the specified team in the specified organization + will have admin authority in the Kabanero CLI. + properties: + apiUrl: + type: string + organization: + type: string + teams: + items: + type: string + type: array + type: object + landing: + description: KabaneroLandingCustomizationSpec defines customization + entries for Kabanero landing page. + properties: + enable: + type: boolean + version: + type: string + type: object + targetNamespaces: + items: + type: string + type: array + tekton: + description: TektonCustomizationSpec defines customization entries + for Tekton + properties: + disabled: + type: boolean + version: + type: string + type: object + version: + type: string + type: object + status: + description: KabaneroStatus defines the observed state of the Kabanero + instance. + properties: + admissionControllerWebhook: + description: Admission webhook instance status + properties: + errorMessage: + type: string + ready: + type: string + type: object + appsody: + description: Appsody instance readiness status. + properties: + errorMessage: + type: string + ready: + type: string + version: + type: string + type: object + che: + description: Che instance readiness status. + properties: + cheOperator: + description: CheOperatorStatus defines the observed status details + of the Che operator. + properties: + version: + type: string + type: object + errorMessage: + type: string + kabaneroChe: + description: KabaneroCheStatus defines the observed status details + of Kabanero Che. + properties: + version: + type: string + type: object + kabaneroCheInstance: + description: KabaneroCheInstanceStatus defines the observed status + details of Che instance. + properties: + cheImage: + type: string + cheImageTag: + type: string + cheWorkspaceClusterRole: + type: string + type: object + ready: + type: string + type: object + cli: + description: CLI readiness status. + properties: + errorMessage: + type: string + hostnames: + items: + type: string + type: array + ready: + type: string + type: object + collectionController: + description: Kabanero collection controller readiness status. + properties: + errorMessage: + type: string + ready: + type: string + version: + type: string + type: object + events: + description: Events instance status + properties: + errorMessage: + type: string + hostnames: + items: + type: string + type: array + ready: + type: string + type: object + kabaneroInstance: + description: Kabanero operator instance readiness status. The status + is directly correlated to the availability of resources dependencies. + properties: + errorMessage: + type: string + ready: + type: string + version: + type: string + type: object + kappnav: + description: Kabanero Application Navigator instance readiness status. + properties: + apiLocations: + items: + type: string + type: array + errorMessage: + type: string + ready: + type: string + uiLocations: + items: + type: string + type: array + type: object + knativeEventing: + description: Knative eventing instance readiness status. + properties: + errorMessage: + type: string + ready: + type: string + version: + type: string + type: object + landing: + description: Kabanero Landing page readiness status. + properties: + errorMessage: + type: string + ready: + type: string + version: + type: string + type: object + serverless: + description: OpenShift serverless operator status. + properties: + errorMessage: + type: string + knativeServing: + description: KnativeServingStatus defines the observed status + details of Knative Serving. + properties: + errorMessage: + type: string + ready: + type: string + version: + type: string + type: object + ready: + type: string + version: + type: string + type: object + tekton: + description: Tekton instance readiness status. + properties: + errorMessage: + type: string + ready: + type: string + version: + type: string + type: object + type: object + type: object + served: true + storage: false + - name: v1alpha2 + schema: + openAPIV3Schema: + 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: KabaneroSpec defines the desired state of Kabanero + properties: + admissionControllerWebhook: + properties: + image: + type: string + repository: + type: string + tag: + type: string + version: + type: string + type: object + cliServices: + description: KabaneroCliServicesCustomizationSpec defines customization + entries for the Kabanero CLI. + properties: + image: + type: string + repository: + type: string + sessionExpirationSeconds: + type: string + tag: + type: string + version: + description: 'Future: Enable bool `json:"enable,omitempty"`' + type: string + type: object + codeReadyWorkspaces: + description: CRWCustomizationSpec defines customization entries for + codeready-workspaces. + properties: + enable: + type: boolean + operator: + description: CRWOperatorSpec defines customization entries for + the codeready-workspaces operator. + properties: + customResourceInstance: + description: CRWOperatorCustomResourceSpec defines custom + resource customization entries for the codeready-workspaces + operator. + properties: + cheWorkspaceClusterRole: + type: string + devFileRegistryImage: + description: CWRCustomResourceDevFileRegImage defines + DevFileRegistryImage custom resource customization for + the codeready-workspaces operator. + properties: + image: + type: string + repository: + type: string + tag: + type: string + version: + type: string + type: object + openShiftOAuth: + type: boolean + selfSignedCert: + type: boolean + tlsSupport: + type: boolean + type: object + type: object + type: object + collectionController: + description: CollectionControllerSpec defines customization entried + for the Kabanero collection controller. + properties: + image: + type: string + repository: + type: string + tag: + type: string + version: + type: string + type: object + events: + properties: + enable: + type: boolean + image: + type: string + repository: + type: string + tag: + type: string + version: + type: string + type: object + github: + description: GithubConfig represents the Github information (public + or GHE) where the organization and teams managing the stacks live. Members + of the specified team in the specified organization will have admin + authority in the Kabanero CLI. + properties: + apiUrl: + type: string + organization: + type: string + teams: + items: + type: string + type: array + type: object + gitops: + properties: + pipelines: + items: + description: PipelineSpec defines a set of pipelines and associated + resources for a component. + properties: + gitRelease: + description: GitReleaseSpec defines customization entries + for a Git release. + properties: + assetName: + type: string + hostname: + type: string + organization: + type: string + project: + type: string + release: + type: string + skipCertVerification: + type: boolean + type: object + https: + description: HttpsProtocolFile defines how to retrieve a + file over https + properties: + skipCertVerification: + type: boolean + url: + type: string + type: object + id: + type: string + sha256: + type: string + type: object + type: array + type: object + governancePolicy: + description: GovernancePolicyConfig defines customization entries + for governance policies. + properties: + stackPolicy: + type: string + type: object + landing: + description: KabaneroLandingCustomizationSpec defines customization + entries for Kabanero landing page. + properties: + enable: + type: boolean + image: + type: string + repository: + type: string + tag: + type: string + version: + type: string + type: object + sso: + properties: + adminSecretName: + type: string + enable: + type: boolean + provider: + type: string + type: object + stackController: + description: StackControllerSpec defines customization entried for + the Kabanero stack controller. + properties: + image: + type: string + repository: + type: string + tag: + type: string + version: + type: string + type: object + stacks: + description: InstanceStackConfig defines the customization entries + for a set of stacks. + properties: + pipelines: + items: + description: PipelineSpec defines a set of pipelines and associated + resources for a component. + properties: + gitRelease: + description: GitReleaseSpec defines customization entries + for a Git release. + properties: + assetName: + type: string + hostname: + type: string + organization: + type: string + project: + type: string + release: + type: string + skipCertVerification: + type: boolean + type: object + https: + description: HttpsProtocolFile defines how to retrieve a + file over https + properties: + skipCertVerification: + type: boolean + url: + type: string + type: object + id: + type: string + sha256: + type: string + type: object + type: array + repositories: + items: + description: RepositoryConfig defines customization entries + for a stack. + properties: + gitRelease: + description: GitReleaseSpec defines customization entries + for a Git release. + properties: + assetName: + type: string + hostname: + type: string + organization: + type: string + project: + type: string + release: + type: string + skipCertVerification: + type: boolean + type: object + https: + description: HttpsProtocolFile defines how to retrieve a + file over https + properties: + skipCertVerification: + type: boolean + url: + type: string + type: object + name: + type: string + pipelines: + items: + description: PipelineSpec defines a set of pipelines and + associated resources for a component. + properties: + gitRelease: + description: GitReleaseSpec defines customization + entries for a Git release. + properties: + assetName: + type: string + hostname: + type: string + organization: + type: string + project: + type: string + release: + type: string + skipCertVerification: + type: boolean + type: object + https: + description: HttpsProtocolFile defines how to retrieve + a file over https + properties: + skipCertVerification: + type: boolean + url: + type: string + type: object + id: + type: string + sha256: + type: string + type: object + type: array + type: object + type: array + skipRegistryCertVerification: + type: boolean + type: object + targetNamespaces: + items: + type: string + type: array + triggers: + items: + description: TriggerSpec defines the sets of default triggers for + the stacks + properties: + gitRelease: + description: GitReleaseSpec defines customization entries for + a Git release. + properties: + assetName: + type: string + hostname: + type: string + organization: + type: string + project: + type: string + release: + type: string + skipCertVerification: + type: boolean + type: object + https: + description: HttpsProtocolFile defines how to retrieve a file + over https + properties: + skipCertVerification: + type: boolean + url: + type: string + type: object + id: + type: string + sha256: + type: string + type: object + type: array + version: + type: string + type: object + status: + description: KabaneroStatus defines the observed state of the Kabanero + instance. + properties: + admissionControllerWebhook: + description: Admission webhook instance status + properties: + message: + type: string + ready: + type: string + type: object + appsody: + description: Appsody instance readiness status. + properties: + message: + type: string + ready: + type: string + version: + type: string + type: object + cli: + description: CLI readiness status. + properties: + hostnames: + items: + type: string + type: array + message: + type: string + ready: + type: string + type: object + codereadyWorkspaces: + description: Codeready-workspaces instance readiness status. + properties: + message: + type: string + operator: + description: CRWOperatorStatus defines the observed status details + of the codeready-workspaces operator. + properties: + instance: + description: CRWInstanceStatus defines the observed status + details of the codeready-workspaces operator custom resource. + properties: + cheWorkspaceClusterRole: + type: string + devfileRegistryImage: + type: string + openShiftOAuth: + type: boolean + selfSignedCert: + type: boolean + tlsSupport: + type: boolean + required: + - cheWorkspaceClusterRole + - devfileRegistryImage + - openShiftOAuth + - selfSignedCert + - tlsSupport + type: object + version: + type: string + type: object + ready: + type: string + type: object + collectionController: + description: Kabanero collection controller readiness status. + properties: + message: + type: string + ready: + type: string + version: + type: string + type: object + events: + description: Events instance status + properties: + hostnames: + items: + type: string + type: array + message: + type: string + ready: + type: string + type: object + gitops: + description: The status of the gitops pipelines + properties: + message: + type: string + pipelines: + items: + description: PipelineStatus defines the observed state of the + assets located within a single pipeline .tar.gz. + properties: + activeAssets: + items: + description: RepositoryAssetStatus defines the observed + state of a single asset in a pipelines respository. + properties: + assetDigest: + type: string + assetName: + type: string + group: + type: string + kind: + type: string + namespace: + type: string + status: + type: string + statusMessage: + type: string + version: + type: string + type: object + type: array + digest: + type: string + gitRelease: + description: GitReleaseInfo is all of the GitReleaseSpec + information, minus the "skip cert verification" information, + which is not relevant for status. + properties: + assetName: + type: string + hostname: + type: string + organization: + type: string + project: + type: string + release: + type: string + type: object + name: + type: string + url: + type: string + type: object + type: array + ready: + type: string + type: object + kabaneroInstance: + description: Kabanero operator instance readiness status. The status + is directly correlated to the availability of resources dependencies. + properties: + message: + type: string + ready: + type: string + version: + type: string + type: object + kappnav: + description: Kabanero Application Navigator instance readiness status. + properties: + apiLocations: + items: + type: string + type: array + message: + type: string + ready: + type: string + uiLocations: + items: + type: string + type: array + type: object + landing: + description: Kabanero Landing page readiness status. + properties: + message: + type: string + ready: + type: string + version: + type: string + type: object + serverless: + description: OpenShift serverless operator status. + properties: + knativeServing: + description: KnativeServingStatus defines the observed status + details of Knative Serving. + properties: + message: + type: string + ready: + type: string + version: + type: string + type: object + message: + type: string + ready: + type: string + version: + type: string + type: object + sso: + description: SSO server status + properties: + configured: + type: string + message: + type: string + ready: + type: string + type: object + stackController: + description: Kabanero stack controller readiness status. + properties: + message: + type: string + ready: + type: string + version: + type: string + type: object + tekton: + description: Tekton instance readiness status. + properties: + message: + type: string + ready: + type: string + version: + type: string + type: object + type: object + type: object + served: true + storage: true diff --git a/registry/manifests/kabanero-operator/0.9.1/kabanero.io_stacks_crd.yaml b/registry/manifests/kabanero-operator/0.9.1/kabanero.io_stacks_crd.yaml new file mode 100644 index 00000000..854aa37d --- /dev/null +++ b/registry/manifests/kabanero-operator/0.9.1/kabanero.io_stacks_crd.yaml @@ -0,0 +1,210 @@ +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: stacks.kabanero.io +spec: + additionalPrinterColumns: + - JSONPath: .metadata.creationTimestamp + description: CreationTimestamp is a timestamp representing the server time when + this object was created. It is not guaranteed to be set in happens-before order + across separate operations. + name: Age + type: date + - JSONPath: .status.summary + description: Stack summary. + name: Summary + type: string + group: kabanero.io + names: + kind: Stack + listKind: StackList + plural: stacks + singular: stack + scope: Namespaced + subresources: + status: {} + validation: + openAPIV3Schema: + description: Stack is the Schema for the stack 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: StackSpec defines the desired composition of a Stack + properties: + name: + type: string + versions: + items: + description: StackVersion defines the desired composition of a specific + stack version. + properties: + desiredState: + type: string + images: + items: + description: Image defines a container image used by a stack + properties: + id: + type: string + image: + type: string + type: object + type: array + pipelines: + items: + description: PipelineSpec defines a set of pipelines and associated + resources for a component. + properties: + gitRelease: + description: GitReleaseSpec defines customization entries + for a Git release. + properties: + assetName: + type: string + hostname: + type: string + organization: + type: string + project: + type: string + release: + type: string + skipCertVerification: + type: boolean + type: object + https: + description: HttpsProtocolFile defines how to retrieve a + file over https + properties: + skipCertVerification: + type: boolean + url: + type: string + type: object + id: + type: string + sha256: + type: string + type: object + type: array + skipCertVerification: + type: boolean + skipRegistryCertVerification: + type: boolean + version: + type: string + type: object + type: array + type: object + status: + description: StackStatus defines the observed state of a stack + properties: + statusMessage: + type: string + summary: + type: string + versions: + items: + description: StackVersionStatus defines the observed state of a specific + stack version. + properties: + images: + items: + description: ImageStatus defines a container image status used + by a stack + properties: + digest: + description: ImageDigest defines a container image digest + used by a stack + properties: + activation: + type: string + message: + type: string + type: object + id: + type: string + image: + type: string + type: object + type: array + location: + type: string + pipelines: + items: + description: PipelineStatus defines the observed state of the + assets located within a single pipeline .tar.gz. + properties: + activeAssets: + items: + description: RepositoryAssetStatus defines the observed + state of a single asset in a pipelines respository. + properties: + assetDigest: + type: string + assetName: + type: string + group: + type: string + kind: + type: string + namespace: + type: string + status: + type: string + statusMessage: + type: string + version: + type: string + type: object + type: array + digest: + type: string + gitRelease: + description: GitReleaseInfo is all of the GitReleaseSpec + information, minus the "skip cert verification" information, + which is not relevant for status. + properties: + assetName: + type: string + hostname: + type: string + organization: + type: string + project: + type: string + release: + type: string + type: object + name: + type: string + url: + type: string + type: object + type: array + status: + type: string + statusMessage: + type: string + version: + type: string + type: object + type: array + type: object + type: object + version: v1alpha2 + versions: + - name: v1alpha2 + served: true + storage: true diff --git a/registry/manifests/kabanero-operator/kabanero-operator-package.yaml b/registry/manifests/kabanero-operator/kabanero-operator-package.yaml index c4bdf809..a0f4a802 100644 --- a/registry/manifests/kabanero-operator/kabanero-operator-package.yaml +++ b/registry/manifests/kabanero-operator/kabanero-operator-package.yaml @@ -15,6 +15,8 @@ channels: - name: release-0.8 currentCSV: kabanero-operator.v0.8.0 - name: release-0.9 - currentCSV: kabanero-operator.v0.9.0 -defaultChannel: release-0.9 + currentCSV: kabanero-operator.v0.9.1 +- name: release-0.10 + currentCSV: kabanero-operator.v0.10.0 +defaultChannel: release-0.10